Гайд LuaJIT reverse engineering

mercury1337

Участник
Автор темы
17
27
Добрый вечер.

В этом гайде расскажу и покажу на реальном примере как обходить скрипты LuaJIT.
Создадим скрипт с привязкой самостоятельно, отличаться он не будет абсолютно ничем от пеид. Отличие в том, что мы будем использовать глобальную, не защищенную функцию string.find и вместо hwid/nick используем получение ника компьютера через FFI.

Для начала напишем сам скрипт:

791db4dd23e0123a75cc3.png

https://t.me/+dumSNYnT4nw2Nzhi


Обьясняю почему я не добавлял проверки на кряки.
Все проверки которые пишутся кодом (большая часть) никак не реагирует на изменение скрипта через hex, ведь бы аккуратно подменяем байты, а не добавляем / изменяем функции и целостность скрипта, поэтому они нам не нужны в этом туториале. Как можем заметить, функции local, поэтому их названия в листинге байткода не будут видны.

❗️Рабочий код на HTTP запрос, основанный через FFI, можете найти в нашем телеграм канале + получение ника компьютера ❗️​

Скрипт написан, теперь компилируем его и запускаем.

a18fcfdb38e9f1bda5983.png

https://t.me/+dumSNYnT4nw2Nzhi
Итог таков. Теперь начинаем это обходить. Все достаточно легко. Скачиваем листер байткода клик и запускаем его, требуется Python. Далее переносим скрипт на decompiler.py выбираем 3 - List bytecode и 2 - Decompile with Python-written decompiler. У вас появится asm и -decompiled.lua файлы. Открываем.

❗️У МЕНЯ ВИДОИЗМЕНЕННАЯ ВЕРСИЯ, У ВАС БУДЕТ ЛИСТИНГ ВЫГЛЯДЕТЬ НЕСКОЛЬКО ПО ДРУГОМУ ❗️​

04fdec6ccd2798931112c.png

https://t.me/+dumSNYnT4nw2Nzhi
Декомпилированный формат, кстати он облегчает код - это его особенность, мы ничего не теряем из-за этого.
Конечно не удобно, что бесплатный декомпилятор оставляет slot, приватный так не делает:

2259e52fab12fe827f85e.png

https://t.me/+dumSNYnT4nw2Nzhi
Пока этот декомпилятор находится у малого круга лиц. Возможно вскоре буду продавать, но это не точно =)
ASM выглядит так:

c9d24524e4c77ed6eb2fc.png

https://t.me/+dumSNYnT4nw2Nzhi




Не пугаемся, чем больше смотрите, тем понятнее.

021fadb23733babdde3eb.png

Краткий мануал
Дальше начинается самое интересное, мы должны понять, что нам нужно нопнуть, это может быть либо опкод JMP (прыжок, отвечает за проверку if) либо CALL (вызов, отвечает за () вызов функций).
Давайте я покажу оба способа. Начнем с первого.

Ищем нужный нам JMP, в асм по рядом стоящим меткам.

df3087bc0a9cfab2921bf.png

https://t.me/+dumSNYnT4nw2Nzhi
9157994aa912ad7f3bc45.png

https://t.me/+dumSNYnT4nw2Nzhi
Как я нашел что именно этот JMP наша проверка?
По определенным меткам:

  • Глобальным функциям
  • Строкам
  • Интуитивности
  • 54 - номер JMP опкода в LuaJIT 2.0, 58 - номер JMP в LuaJIT 2.1 !!!
Конечно нужно понимать, что с первого раза вы можете ошибиться или искать дольше обычного этот опкод, но через множество практик, вы начнете интуитивно понимать и ориентироваться в байткоде.

Далее нам нужно поменять байты так, чтобы проверка постоянно проходила.
Нам понадобится любой HEX-редактор, я пользуюсь hexed.it , на нем и буду демонстрировать.

Для начала перекидываем туда наш файл, и возвращаемся к оффсетам. Они нам нужны для легкого поиска нужных опкодов, чтобы не составлять поисковую строку самостоятельно, легче скопировать оффсет и нас сразу перекинет на нужный байт (причем без ошибочно). Чтобы узнать что такое оффсет, посмотрите мануал по листингу который я прикрепил выше.

Для нашей проверки оффсет - 000002D8

155ec533b1474e81834d0.png

https://t.me/+dumSNYnT4nw2Nzhi
Вставляем в поиск, не забываем приписать к началу 0x

Иначе может найти не верный байт. Нажимаем Enter, нас перекидывает на байт (выделенный)

3c0a0d897750c92c2b3d7.png

https://t.me/+dumSNYnT4nw2Nzhi


Чтобы нопнуть этот джамп, заменяем 4 байта следующим образом:

  • было 54 06 04 80
  • заменяем на 54 00 00 80
daf616ccf1319c1b48bbd.png

https://t.me/+dumSNYnT4nw2Nzhi
Доп. информация: если вам нужно чтобы проверка наоборот не работала, то заменяем 54 00 80 00
Аналогично с теми у кого LuaJIT 2.1, только у вас не 54 будет JMP, а 58. Ну и заменяем разумеется на 58 00 00 80.

afc9ee88755de25c0cc43.png

https://t.me/+dumSNYnT4nw2Nzhi
Готово! Мы отключили проверку.

Идем дальше, отключаем вызовы функций которые могут сломать скрипт.​

Мы видим в нашем исходнике вызов функции

17ed65ce615199d99f393.png

https://t.me/+dumSNYnT4nw2Nzhi


Эта функция возвращает ошибку (quit_script), давайте ее выключим. Ищем CALL, вероятно она будет стоять рядом со строками которые находятся выше нее.

12d676846f43c42d15820.png

https://t.me/+dumSNYnT4nw2Nzhi
Мы видим 3 шт CALL, тут уже чуть сложнее найти нужный.

Базовая аналитика​

Смотря на это могу предположить что второй колл отключает функцию получения имени пк, тоесть getComputerName. Значит смысла трогать ее нет. У нас осталась либо первый либо второй, мы можем пропатчить обе, мы ничего не потеряем, просто с выходои скрипта выключится и негативный принт. Давайте всеже найдем нужный вызов, смотрим где расположена print - чуть выше чем строки (my pc name... и тд) которые в самом принте , у нас в нем же и вызывается функция getComputerName, и уже после принта вызывается наша quit_script(). Значит 3 CALL - наш. Как-то так нужно мыслить, чтобы искать нужные опкоды.

Раз мы уже нашли ее, давайте выключать
Берем оффсет -> в поиск хекседита (не забываем про 0x) -> перекидывает на байт.

Заменяем 4 байта на 54 00 00 80 (прыжок в никуда)

8775911674f8a65d8300e.png

https://t.me/+dumSNYnT4nw2Nzhi
Как видим, ошибки, что закрывала скрипт, уже нет.

Финал​

Также этим прыжком "в никуда" мы можем выключать любой опкод, тоесть "стирать его", но нужно понимать, что вы можете навредить скрипту и он перестанет запускаться вовсе. Поэтому будьте аккуратны.

Данный гайд подходит к концу. Тема следующего гайда - хуки.

Подписываемся на телеграм канал со всеми гайдами реверсу / защите скриптов, в комментариях к посту оставлю функции http, getComputerName как бонус - https://t.me/+dumSNYnT4nw2Nzhi
ps copy by telegraph, знаю, что информация в открытом доступе лежит на бласт хаке, залил свою версию​

 

paulohardy

вы еще постите говно? тогда я иду к вам
Всефорумный модератор
1,907
1,283
1704974066641.png
в случае запроса можно было бы и его затереть
Идем дальше, отключаем вызовы функций которые могут сломать скрипт.
после патча else блок стал недостижим, че он там сломать может?
 

mercury1337

Участник
Автор темы
17
27