Войти или зарегистрироваться

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

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!
iM5A7lc.png


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

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

vtHN4Xw.png


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

SWr0cd5.png


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

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


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

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

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

Давайте оставим инициализацию класса и перейдем к функции main:
X1xpEAI.png


Код:
.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, что мы и видим на скриншоте ниже. Ошибок нет.
mufSlkW.png


А далее из под него достает объект out типа Ljava/io/PrintStream, а это эквивалентно java.io.PrintStream, разбираем код дальше..
4LU7nqR.png

Код:
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
(Думаю аргументы уже всем понятны)
WQvY9PG.png


Вуаля! Сборка успешно завершена, не проверяя, существует ли данный метод!
BbWpIS5.png


Заменяем наш старый Main.class в .jar файле на новый и пытаемся его запустить!
lp5Si70.png

Double-вуаля! Java-машина попыталась вызвать java.io.PrintStream.RuBukkit, но не нашла метода, выбив нам исключение.

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

В конце .j файла есть нужная нам строчка:
y4picM0.png


Изменим её на:
Код:
.sourcefile 'RuBukkit.org'

А номер строки можно найти в разделе .linenumbertable

hsZzLru.png


L0 в нашем случае это функция System.out.println("test output");
Ей и присуждена строка под номером 5
А L8 это return, а если быть точнее, конец функции.
Давайте сравним с IDE?
9RbpFlT.png

Заменяем на..
Код:
        .linenumbertable 
            L0 1337 
            L8 6 
        .end linenumbertable

Теперь собираем и тестируем..
Все получилось!
Vuykm0g.png


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


Всем удачи! :)
 
Номер строки можно и удалить. И жаба не будет знать номер строки с ошибкой.
 
Напиши как работать с байт-кодом в JBE (Java Byte Editor, довольно хорошая штука).
 
Гениально! Спасибо, оч было полезно, сейчас аж руки чешутся все выучить и начать ломать AAC :D
Уже немного снимается туман большого ассемблерского кода )
Единственное что бы добавить тебе для других - параметры этих файликов, чтобы например не один класс собрать, а целый плагин назад.
 
Гениально! Спасибо, оч было полезно, сейчас аж руки чешутся все выучить и начать ломать AAC :D
Уже немного снимается туман большого ассемблерского кода )
Единственное что бы добавить тебе для других - параметры этих файликов, чтобы например не один класс собрать, а целый плагин назад.
Да там уже ломать то нечего, без стрингаря уже нет защиты по константпулу.
Да и там все на рефлексиях в AAC, он небось грузит сервер сильнее чам сами читаки :D.
 
Да там уже ломать то нечего, без стрингаря уже нет защиты по константпулу.
Да и там все на рефлексиях в AAC, он небось грузит сервер сильнее чам сами читаки :D.
Кстати есть шанс ломануть стрингарь триалку (2.х.х)? Видел в нете не особо до этого доходят, все на 1.6 где то.
 
Кстати есть шанс ломануть стрингарь триалку (2.х.х)? Видел в нете не особо до этого доходят, все на 1.6 где то.
У меня есть полностью снятый стрингарь 2.х.х. Все так же на изи снимается.
p27g4nMtoW3ag2.jpg

А всякие статейки типо хабра, что тип мегазащита, хрен снять в рантайме. Это все полный наеп для пиара стрингаря.
В реале же асмом сливается в 2 клика.
От кракатао кстати можно затычку поставить, просто делаем имена пакетов и классов неким левым уникодом и все не переварит.
 
Назад
Верх