Так уж случилось, что время от времени я развлекаюсь анализом клиентов ММО-игр на тему различного рода полезностей или получения информации о действии тех или иных игровых аспектов. Основное количество информации приносит разбор клиента в IDA Pro или OllyDbg.
Так как опыта у меня не так уж и много в данном действе, обычно я банально беру какую-либо функцию, пишу dll-перехватчик и анализирую аргументы функции, полученные при перехвате.
К сожалению, даже IDA не идеальна — получить аргументы функции, соответствующие истине, зачастую проблематично(самый простой пример — lua-функции, lua_state определяется Идой как int). Да и, по мере анализа клиента, dll обрастает порой просто неприличным количеством функций, их объявлений и описаний, а также прочего добра. В результате получаем километры кода.
Но стремление к прекрасному живет в большинстве из нас — потому возникает желание как-то этот код «утрамбовать», сделать более читаемым. К примеру, я при написании dll люблю использовать макросы, регионы, по возможности уменьшать количество однотипных функций и т.д.
И вот не так давно я загорелся идеей еще сильнее сжать код путем сжатия объявления и описания функции, переменных и прочего добра в 1 макрос. В идеале — скидывать список аргументов перехваченной функции в файл. На данный момент я написал относительно универсальный перехватчик для __cdecl функций(т.к. уровень знаний в данной области у меня не слишком высок, могу предположить, что адекватно работать будет только для Windows x86, возможно, есть еще какие-то ограничения). Для перехвата использую обычно Detours x86, иногда — простенький аналог.
Собственно, код:
#define cdecl_hook(name1) /*Macro definition*/
void name1##_hook(int a1, ...) /*Declare hooker*/
{
int check_s = 0;
__asm{mov check_s, esp} /*Save esp state*/
int *ptr = &a1; /*Get pointer to 1st arg, equialent of va_list*/
debug_msg("Advanced",true,"--%s arg list started--", __FUNCTION__); /*debug_msg() - vfprintf wrapper*/
for(int i=0; i*4<name1##_arg_amount; i++)
{
debug_msg("Advanced",true," |---Element %d: %d", i, ptr[i]);
} /*Arg list -> file(Advanced.txt)*/
debug_msg("Advanced",true,"--arg list finished--n");
__asm{lea ecx, a1} /*Move addr of a1 to ecx*/
__asm{mov eax, name1##_arg_amount} /*move size of args in stack(can get from IDA, for ex.) to eax*/
__asm{label_loop: } /*Start loop*/
__asm{mov ebx, dword ptr[ecx+eax-4]} /*Move args from stack to ebx in loop and push ebx*/
__asm{push ebx}
__asm{sub eax,4}
__asm{cmp eax,0}
__asm{jg label_loop}
__asm{call dword ptr[name1##_Detour]} /*Call original function*/
__asm{mov esp, check_s} /*Restore stack, same as __asm{add esp, name1##_arg_amount}*/
}
#define RF_O_UP_FUNC(name1, address, args) /*Define needed functions and variables*/
typedef void (* t##name1 ) ();
/*__declspec(dllexport) */t##name1 name1##_Detour = ( t##name1 ) ( address ); /*Define original function and bind to addr*/
void name1##_hook(int a1, ...); /*Define hooker*/
int name1##_arg_amount = args; /*Summary size of args in stack, can get from IDA*/
cdecl_hook(name1); /*Call hooker definition*/
Ну и, собственно, пример объявления всего этого добра:
RF_O_UP_FUNC(resources, 0x687054, 0x4C);
RF_O_UP_FUNC(hooker, 0x17E4D18, 7);
RF_O_UP_FUNC(begin, 0x689BA0, 5);
Вот так 1 строкой мы объявляем функцию-перехватчик, указываем, какую функцию и по какому адресу мы хотим перехватить, а также при перехвате получаем список аргументов(в данном примере все аргументы будут записаны в файл как int, можно добавить формат в макрос).
Далее все просто — если используем Detours, то аттач будет выглядеть как-то так:
DetourAttach(&(PVOID&)resources_Detour, resources_hook).
Остальное, в принципе, не нуждается в пояснениях.
Пример вывода аргументов:
--resources_hook arg list started--
|---Element 0: 204181
|---Element 1: 204181
|---Element 2: 1277574
|---Element 3: 1363294854
|---Element 4: 1
|---Element 5: 0
|---Element 6: 0
|---Element 7: 0
|---Element 8: 0
|---Element 9: 0
|---Element 10: 0
|---Element 11: 0
|---Element 12: 0
|---Element 13: 0
|---Element 14: 0
|---Element 15: 0
|---Element 16: 1
|---Element 17: 100
|---Element 18: 1
--arg list finished--
Итого, при помощи пары небольших макросов, мы получили возможность неплохо ужать код.
Недостатки:
1) На данный момент не работает с __stdcall'ом, __thiscall'ом и другими соглашениями о вызовах. Не откажусь от помощи или совета по данному поводу.
2) Как я уже упоминал, опыта в данном вопросе достаточно мало, так что вполне могут быть косяки, которых я не учел, так что просьба сильно не тролить.
3) Не нашел аналогов, однако это не значит, что нету более адекватных способов / нельзя оптимизировать текущий. Замечания по данному поводу также были бы кстати.
Благодарю за внимание!
Автор: Demogor