1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie. Узнать больше.
  2. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

Туториал Основы редактирования Java Bytecode

Тема в разделе "Руководства, инструкции, утилиты", создана пользователем ANTI_GREEFER, 3 янв 2016.

  1. Автор темы
    ANTI_GREEFER

    ANTI_GREEFER Активный участник Пользователь

    Баллы:
    88
    Здравствуйте, администраторы серверов и простые кодеры. :)

    Сегодня я расскажу, как менять код Java без декомпилирования/компилирования.
    Мы будем заниматься чем-то похожим, но это будет ассемблирование и дисассемблирование.

    В чем отличие между декомпилированием и дисассемблированием?
    Декомпиляция на выходе дает обычный код Java и при его повторном компилировании могут возникнуть кучи ошибок по причинам того, что компилятор не в силах разресолвить необходимые зависимости.

    С дисассемблированием все проще. На выходе мы получаем байт-код Java, который легко изменить и собрать обратно (ассемблирование).

    Java Bytecode / Википедия:
    https://ru.wikipedia.org/wiki/Байт-код_Java

    Список OP-кодов Java байткода:
    https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

    Основы Byte-кода Java (Хабрахабр):
    http://habrahabr.ru/post/111456/

    Шаг 1: Утилиты для ассемблирования/дисассемблирования

    Самой лучшей утилитой я считаю Krakatau Bytecode Tools.
    На её примере мы и будем работать.
    Загрузить утилиту можно тут: https://github.com/Storyyeller/Krakatau
    Прочитать README данной утилиты можно тут: README.txt

    Устанавливать утилиту не нужно, просто извлеките скачанный архив в нужную папку и скрипты готовы для запуска.

    Внимание! Для компиляции при помощи Krakatau необходима Java Development Kit!
    (Не путать с ассемблированием!)

    Для запуска Krakatau необходима Python версии 2.7!
    [​IMG]

    Шаг 2: Разбираем простую программу и смотрим что да как.

    Давайте создадим простую программу на Java, которая выводит в консоль "test output", скомпилируем её и потом дисассемблируем.

    [​IMG]

    После сборки в "Runnable JAR File" мы кидаем его в рабочую папку и разбираем при помощи Krakatau.

    [​IMG]

    Для начала перейдем в ту папку, где лежат скрипты Krakatau. Нам понадобится disassemble.py
    Указываем параметры -r (recursive) и -out <путь> (путь, куда будут положены разобранные .class файлы) и потом путь до нашего .jar файла.

    Нормальный выхлоп разбирания .jar файла без ошибок:
    [​IMG]

    Смотрим папку, которую мы указали в параметре -out, и что мы видим? Появились файлы с расширением .j, это и есть файлы с байт-кодом.

    .j файлы открываются почти любым блокнотом (в других проблема с переносами строк)
    Я использую Notepad++.

    Тут можно посмотреть весь код класса: http://pastebin.com/k0bBVHPs

    Давайте оставим инициализацию класса и перейдем к функции main:
    [​IMG]

    Код:
    .method public static main : ([Ljava/lang/String;)V 
    Естественно отвечает за функцию main, которой в аргументы идет [Ljava/lang/String; (Массив строк)

    Перейдем к коду.
    Код:
    System.out.println("test output");
    Выглядит как:
    Код:
    L0:     getstatic Field java/lang/System out Ljava/io/PrintStream; 
    L3:     ldc 'test output' 
    L5:     invokevirtual Method java/io/PrintStream println (Ljava/lang/String;)V 
    Давайте разберем его. getstatic получает значение статического объекта, а именно java/lang/System.
    java/lang/System эквивалентна java.lang.System, что мы и видим на скриншоте ниже. Ошибок нет.
    [​IMG]

    А далее из под него достает объект out типа Ljava/io/PrintStream, а это эквивалентно java.io.PrintStream, разбираем код дальше..
    [​IMG]
    Код:
    ldc 'test output' 
    Пушает строку 'test output' в стак.

    Код:
    invokevirtual Method java/io/PrintStream println (Ljava/lang/String;)V 
    А вот это уже веселее. Она вызывает метод println из java/io/PrintStream и отдает ему аргумент Ljava/lang/String;

    Просто, не так ли? :)

    (Для доп. информации: для статических методов используется invokestatic)

    А теперь немного повеселимся. Давайте заставим Java-машину вызывать метод RuBukkit вместо println!

    Заменяем
    Код:
    L5:     invokevirtual Method java/io/PrintStream println (Ljava/lang/String;)V 
    на
    Код:
    L5:     invokevirtual Method java/io/PrintStream RuBukkit (Ljava/lang/String;)V 
    Теперь собираем! Нам понадобится assemble.py
    (Думаю аргументы уже всем понятны)
    [​IMG]

    Вуаля! Сборка успешно завершена, не проверяя, существует ли данный метод!
    [​IMG]

    Заменяем наш старый Main.class в .jar файле на новый и пытаемся его запустить!
    [​IMG]
    Double-вуаля! Java-машина попыталась вызвать java.io.PrintStream.RuBukkit, но не нашла метода, выбив нам исключение.

    Стоп, что это? Main.java:5?
    Откуда Java-машина знает, что у меня именно в этом файле и на этой строке находится данный вызов?
    Давайте это аккуратно исправим! Я хочу, что бы при данном исключении показывало файл RuBukkit.org и строку 1337!

    В конце .j файла есть нужная нам строчка:
    [​IMG]

    Изменим её на:
    Код:
    .sourcefile 'RuBukkit.org' 
    А номер строки можно найти в разделе .linenumbertable

    [​IMG]

    L0 в нашем случае это функция System.out.println("test output");
    Ей и присуждена строка под номером 5
    А L8 это return, а если быть точнее, конец функции.
    Давайте сравним с IDE?
    [​IMG]
    Заменяем на..
    Код:
            .linenumbertable 
                L0 1337 
                L8 6 
            .end linenumbertable 
    Теперь собираем и тестируем..
    Все получилось!
    [​IMG]

    Вот и мой маленький туториал завершен.
    Кому нужна дополнительная помощь или связь со мной - можете написать мне.


    Всем удачи! :)
     
  2. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    Номер строки можно и удалить. И жаба не будет знать номер строки с ошибкой.
     
  3. MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    BlackTrojan
    Напиши как работать с байт-кодом в JBE (Java Byte Editor, довольно хорошая штука).
     
  4. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    Днище полное...
     
  5. Beshelmek

    Beshelmek Активный участник Пользователь

    Баллы:
    88
    Имя в Minecraft:
    Beshelmek
    Полезно) Спасибо)
     
  6. MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    BlackTrojan
    С 8 будет работать, я сам проверял.
     
  7. LuckyZeeRo

    LuckyZeeRo Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    i0xHeX
    Гениально! Спасибо, оч было полезно, сейчас аж руки чешутся все выучить и начать ломать AAC :D
    Уже немного снимается туман большого ассемблерского кода )
    Единственное что бы добавить тебе для других - параметры этих файликов, чтобы например не один класс собрать, а целый плагин назад.
     
  8. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    Да там уже ломать то нечего, без стрингаря уже нет защиты по константпулу.
    Да и там все на рефлексиях в AAC, он небось грузит сервер сильнее чам сами читаки :D.
     
  9. LuckyZeeRo

    LuckyZeeRo Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    i0xHeX
    Кстати есть шанс ломануть стрингарь триалку (2.х.х)? Видел в нете не особо до этого доходят, все на 1.6 где то.
     
  10. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    У меня есть полностью снятый стрингарь 2.х.х. Все так же на изи снимается.
    [​IMG]
    А всякие статейки типо хабра, что тип мегазащита, хрен снять в рантайме. Это все полный наеп для пиара стрингаря.
    В реале же асмом сливается в 2 клика.
    От кракатао кстати можно затычку поставить, просто делаем имена пакетов и классов неким левым уникодом и все не переварит.
     

Поделиться этой страницей