Главная » 2010»Октябрь»14 » Декомпиляция плагинов (из .amxx в .sma) на основе amxxdump
21:18
Декомпиляция плагинов (из .amxx в .sma) на основе amxxdump
Введение amx и amxx файлы используются на виртуальной машине, которая содержит набор сценариев. amx файл разбит на три части: заголовок (который содержит информацию о размере), раздел кода и раздел данных. A amxx файл - это простой метод для того, чтобы сохранить два amx файла в одном. Тем самым имеем 32-разрядную и 64-разрядную совместимость в одном файле. Раздел кода содержит коды операций виртуальной машины (то есть примитивные команды виртуальной машины) для компилированного плагина. Раздел данных содержит стек, динамическую память и другие данные, такие как массивы и строки. Виртуальная машина довольно проста. Она основана на двух регистрах (PRI и ALT), стеке и динамической памяти. Регистры - простые ячейки, используемые для хранения временной информации и их возвращения. Стек используется для локальных переменных. Стек имеет две операции: помещение элемента в стек (push) и доставание верхнего элемента из стека (pop). Динамическая память - это простой участок памяти, используемый для хранения временных переменных. Все данные в виртуальной машине вращаются вокруг интегрального типа данных, 'ячейки' (cell). Интегральный - это целочисленный тип данных, который содержит указатель на 32-bit на 32-разрядном процессоре и на 64-bit на 64-разрядном процессоре. AMX обладает способностью вызова процедур (возможность вызывать функцию и возвращать ее значение), которые вращаются вокруг скрытого регистра под названием FRM (который располагается на стеке). При любом вызове процедуры передаются параметры стеку в обратном порядке и закончивается числом помещенных байтов. Например, чтобы вызвать функцию с параметрами A и B, сначала вы поместите параметр B, потом A, а затем число 8 в стек (или 16, если 64-bit). Способы адресации у виртуальной машины - это прежде всего DAT и FRM. Инструкции, относящиеся к FRM, заканчиваются на '.S'. Инструкции, относящиеся к константам, заканчиваются на '.C'. Они относятся к нескольким категориям:
* Переходы (JUMP) * Математические вычисления * Манипуляция со стеком (POP, PUSH) * Вызовы процедур (локальный, системный) * Память (установка и восстановление)
Инструкции, относящиеся к регистрам, заканчиваются на '.ALT' или '.PRI'.
Описание amxxdump - это консольное приложение, предназначенное для дизассемблирования .amxx плагинов, автором которого является Steve Dudenhoeffer. Данное приложение будем использовать через командную строку Windows (cmd). Синтаксис использования: amxxdump [параметры] имя_файла.amxx
Список параметров
-a - не показывать адресные положения. -c - не показывать комментарии. -x - список всех public и stock функций плагина и их параметры. -n - список native функций, используемых в плагине. -D - дизассемблирование указанной функции. -d - дизассемблировать код плагина. -s - показать все символы. -m - показать необходимые модули. -r - поиск информации об указанной функции. -R - поиск информации об указанной native функции. -v - показать значение адреса в разделе данных. -A - в дополнении к параметру -v, формирует дамп в зависимости от указанного размера ячеек. -V - показать значение адреса в разделе данных в качестве строки. -F - показать значение адреса в разделе данных в качестве числа с плавающей точкой. -f - показать названия всех файлов, код которых включен в плагин (stock). -l - показать номер строки и название файла у оператора BREAK. -j - показать метки для jump, switch и case таблиц. -e - попытаться сформировать данные от операторов push.c/const.pri. -E - использовать список параметров для стандартных вызовов native функций. Для работы необходимы .inc файлы. -N - не показывать рамзерность переменных, теги и стандартные значения. Подразумевает параметр -E. -g - список всех глобальных переменных. -h - скрыть номера параметров и их адреса. -! - показать лицензию программы. -? - помощь.
Применение Рассмотрим применение amxxdump, к примеру, на стандартном плагине antiflood.amxx из версии AMX Mod X 1.8.1. 1. Узнаем список всех public и stock функций плагина:
amxxdump -x antiflood.amxx
Получаем:
Код: Выделить всё 0x0000004C stock bool:operator!(Float:)(Float:oper) 0x00000008 stock bool:operator>(Float:,Float:)(Float:oper1,Float:oper2) 0x000001AC public chkFlood(id) 0x00000078 public plugin_init()
В данном случае функции operator! и operator> тоже самое, что операторы ! и > в условиях, поэтому их дизассемблировать не обязательно. 2. Узнаем список всех native функций, используемых в плагине:
codestart codeend address type name 0x00000008 0x0000004C 0x00000010 local val oper2 0x00000008 0x0000004C 0x0000000C local val oper1 0x0000004C 0x00000078 0x0000000C local val oper 0x00000210 0x0000049C 0xFFFFFFF8 local val nexTime 0x000001B8 0x000004B0 0xFFFFFFFC local val maxChat 0x000001AC 0x000004B0 0x0000000C local val id 0x0000004C 0x00000078 0x0000004C stock operator!(Float:) 0x00000008 0x0000004C 0x00000008 stock operator>(Float:,Float:) 0x00000078 0x000004B0 0x00000000 global val AMXX_VERSION_STR[11] 0x00000078 0x000004B0 0x00000134 global val amx_flood_time 0x000001AC 0x000004B0 0x000001AC public chkFlood 0x00000078 0x000004B0 0x000000B0 global val g_Flood[33] 0x00000078 0x000004B0 0x0000002C global val g_Flooding[33] 0x00000078 0x000001AC 0x00000078 public plugin_init
local - локальная переменная, то есть может быть использована только в какой-то конкретной функции. global - глобальная переменная, то есть может быть использована во всех функциях плагина. public - public функция. stock - stock функция. 4. Узнаем используемые модули:
amxxdump -m antiflood.amxx
Получаем:
No module data detected.
Значит другие модули, кроме amxmodx, не используются. 5. Узнаем список всех глобальных переменных:
amxxdump -g antiflood.amxx
Получаем:
0x00000000 new AMXX_VERSION_STR[11] 0x00000134 new amx_flood_time 0x000000B0 new g_Flood[33] 0x0000002C new Float:g_Flooding[33]
AMXX_VERSION_STR - это константа, в которой содежится текущая версия AMX Mod X. 6. Получаем весь дизассемблированный код плагина:
// PROC - говорит нам о том, что это процедура (функция), в нашем случае plugin_init 0x78 PROC ; public plugin_init()
Запишем как:
public plugin_init()
// PUSH.C - означает, что мы помещаем константу в стек // Поэтому стек будет содержать (0x164, 0x0, 0x138, 0xC) // Последний PUSH.C - это количество параметров в байтах. 0xC - в десятичной системе равно 12. // Размер 32-разрядной ячейки равен 4, поэтому 12/4 = 3 параметра. 0x84 PUSH.C 0x164 ; "AMXX Dev Team" // третий параметр 0x8C PUSH.C 0x0 ; AMXX_VERSION_STR[11] "1.8.1.3722" // второй параметр 0x94 PUSH.C 0x138 ; "Anti Flood" // первый параметр 0x9C PUSH.C 0xC
// SYSREQ.C - конечная инструкция, которая работает с данными из стека // Вызывает функцию register_plugin 0xA4 SYSREQ.C 0x1 ; register_plugin("Anti Flood",AMXX_VERSION_STR[11]={"1.8.1.3722"},"AMXX Dev Team")
// STACK - означает, что мы освобождаем из стека 4 ячейки (16 байт) 0xAC STACK 0x10 ; free 4 cells
// BREAK - означает прерывание, можно понимать это, как конец строки 0xB4 BREAK ; antiflood.sma:44
Так как используется функция register_plugin, то мы знаем ее синтаксис:
0x164 PUSH.C 0x0 ; AMXX_VERSION_STR[11] "1.8.1.3722" // Четвертый аргумент и комментарий AMXX_VERSION_STR[11] "1.8.1.3722" неверный, ошибка работы параметра -e 0x16C PUSH.C 0x0 ; AMXX_VERSION_STR[11] "1.8.1.3722" // Третий аргумент и комментарий AMXX_VERSION_STR[11] "1.8.1.3722" неверный, ошибка работы параметра -e 0x174 PUSH.C 0x290 ; "0.75" // Второй аргумент 0x17C PUSH.C 0x254 ; "amx_flood_time" // Первый аргумент 0x184 PUSH.C 0x10 // Четыре аргумента 0x18C SYSREQ.C 0x4 ; register_cvar("amx_flood_time","0.75",0,0.000000) // Вызываем функцию register_cvar 0x194 STACK 0x14 ; free 5 cells // Освобождаем из стека 5 ячеек
// STOR - означает копирование в указанный адрес памяти значения. Другими словами у нас идет присвоение переменной amx_flood_time определенного значения. 0x19C STOR.pri 0x134 ; amx_flood_time
Так как используется функция register_cvar, то мы знаем ее синтаксис:
Смысл не изменится, так как два последних параметра имеют стандартные значения.
// RETN - означает return (возвращение) функции. // ZERO.pro - говорит нам о том, что возвращается ноль (return 0). Это аналогично return PLUGIN_CONTINUE. 0x1A4 ZERO.pri 0x1A8 RETN
Запишем как:
return PLUGIN_CONTINUE
8. Рассмотрим только функцию chkFlood. Используем:
Так как используется функция get_pcvar_float, то мы знаем ее синтаксис:
get_pcvar_float(pcvar)
Запишем как:
new Float:maxChat = get_pcvar_float(amx_flood_time)
0x1EC PUSH.S 0xFFFFFFFC ; Float:maxChat // Аргумент 0x1F4 PUSH.C 0x4 // Один аргумент // CALL - означает вызов приватной функции, которая идентифицируется, как operator! 0x1FC CALL 0x4C ; stock bool:operator!(Float:)(Float:oper)
// JNZ (Jump Not Zero) - переход на метку jump_0, если не равно нулю, то есть maxChat != 0. Но выше у нас есть вызов оператора !, который означает отрицание, то есть если !(maxChat != 0) будет true, то произойдет переход на jump_0. 0x204 JNZ 0x49C ; jump_0 0x20C BREAK ; antiflood.sma:56
Так как используется функция get_gametime, то мы знаем ее синтаксис:
get_gametime()
Запишем как:
new Float:nexTime = get_gametime()
// CONST.alt - означает, что в ALT у нас будет хранение 0x2C 0x23C CONST.alt 0x2C ; Float:g_Flooding[33]=0x0 (0.00000) 0x244 LOAD.S.pri 0xC ; id // Загружаем индекс id массива
// BOUNDS - rоличество элементов массива. В данном случае 32 (размерность 33). 0x24C BOUNDS 0x20
// LIDX - одна из инструкций, используемая для доступа к массиву. 0x254 LIDX
0x258 MOVE.alt 0x25C LOAD.S.pri 0xFFFFFFF8 ; Float:nexTime 0x264 PUSH.pri 0x268 PUSH.pri // Второй параметр 0x26C PUSH.alt // Первый параметр 0x270 PUSH.C 0x8 // Два параметра 0x278 CALL 0x8 ; stock bool:operator>(Float:,Float:)(Float:oper1,Float:oper2) // Вызываем оператор > 0x280 POP.alt // JZER (Jump on ZERo) - так как мы имеем сверху вызов оператора >, то в данном случае это условие будет означать следующее, если g_Flooding[id] не больше nexTime, то переходим на метку jump_1. 0x284 JZER 0x3DC ; jump_1 0x28C BREAK ; antiflood.sma:60
Запишем как:
if (g_Flooding[id] > nexTime)
0x290 CONST.alt 0xB0 ; g_Flood[33]=0x0 (0.00000) // Помещаем в ALT значение g_Flood[id] 0x298 LOAD.S.pri 0xC ; id 0x2A0 BOUNDS 0x20 0x2A8 LIDX 0x2AC MOVE.alt 0x2B0 CONST.pri 0x3 ; 0x2E00 (11776.00000) // Помещаем в PRI значение 3
// JSGRTR - означает переход на метку jump_2, если PRI > ALT. То есть если g_Flood[id] меньше 3 - это true и значит переходим на метку jump_2. 0x2B8 JSGRTR 0x3A0 ; jump_2 0x2C0 BREAK ; antiflood.sma:62
// INC - обозначает увеличение (increment), то есть операция ++ 0x3CC INC.I 0x3D0 POP.pri
// JUMP - переход на метку. Но так как мы находимся уже внутри условия, поэтому это может означать, что есть еще else или else if при выполнении перехода на метку jump_1. 0x3D4 JUMP 0x438 ; jump_3 0x3DC BREAK ; antiflood.sma:68
Запишем как:
g_Flood[id]++
// Метка jump_1 ; target:jump_1 // Данный кусок кода обозначает, что это массив g_Flood размерностью 33 и индексом id 0x3E0 CONST.alt 0xB0 ; g_Flood[33]=0x0 (0.00000) 0x3E8 LOAD.S.pri 0xC ; id 0x3F0 BOUNDS 0x20 0x3F8 LIDX // Если g_Flood[id] равен 0 будет true, значит перейдем на метку jump_4 0x3FC JZER 0x438 ; jump_4 0x404 BREAK ; antiflood.sma:70
Запишем как (учитывая JUMP переход выше, следует, что у нас else if, так как в коде есть еще JZER условие):
else if (g_Flood[id])
// Данный кусок кода обозначает, что это массив g_Flood размерностью 33 и индексом id 0x408 CONST.alt 0xB0 ; g_Flood[33]=0x0 (0.00000) 0x410 LOAD.S.pri 0xC ; id 0x418 BOUNDS 0x20
0x420 IDXADDR 0x424 PUSH.pri 0x428 LOAD.I 0x42C SWAP.pri // DEC - обозначает уменьшение (decrement), то есть операция -- 0x430 DEC.I 0x434 POP.pri 0x438 BREAK ; antiflood.sma:73
Запишем как:
g_Flood[id]--
; target:jump_3
Метка 3 в нашем случае не содержит кода.
// Метка jump_4 ; target:jump_4 // Данный кусок кода обозначает, что это массив g_Flooding размерностью 33 и индексом id 0x43C CONST.alt 0x2C ; Float:g_Flooding[33]=0x0 (0.00000) 0x444 LOAD.S.pri 0xC ; id 0x44C BOUNDS 0x20
Зарег. на сайте : Всего: 9075 овых за месяц: 0 Новых за неделю: 0 Новых вчера: 0 Новых сегодня: 0 Из них : Администраторов: 2 Модераторов: 0 Проверенных: 0 Обычных юзеров: 9070 Забаненных юзеров: 2 Из них: Парней: 7304 Девушек: 68
Кто нас посетил:
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
При копировании материалов с сайта источник на info-cs.net.ru обязателен