Опубликовано 9 апреля, 20188 г. comment_446 Приветствую. В данной статье расскажу Virtual Method Table Hooks или просто VMT хуки. В движке игры CSGO есть виртуальные классы - интерфейсы, в которых находятся различные методы. Пример: class CEngine { public: CEngine() {} virtual void Func1() { printf("CEngine::Func1\n"); } virtual void Func2() { printf("CEngine::Func2\n"); } virtual ~CEngine() {} }; Класс, в котором есть хоть одна виртуальная функция, имеет виртуальную таблицу. Указатель на которую можно получить так DWORD * VMT = *(DWORD**)Instance; Виртуальная таблица по сути своей - это массив 4 байтных указатель для x32 и 8 байтных для x64 соответственно. Пример вызова виртуальной функции через каст указателя на неё к тайпдефу. class CEngine { public: CEngine() {} virtual void Func1() { printf("CEngine::Func1\n"); } virtual void Func2() { printf("CEngine::Func2\n"); } virtual ~CEngine() {} }; int main() { CEngine * g_pEngine = new CEngine(); typedef void(__fastcall * fn)(void); fn ofn; DWORD * VMT = *(DWORD**)g_pEngine; ofn = (fn)VMT[0]; if (ofn != nullptr) ofn(); delete g_pEngine; return 0L; } Создаём тайпдеф данной функции. Используем __fastcall т.к. в нём параметры передаются через регистры ECX, EDX , как раз указатель на класс передаётся через регистр ECX соответственно для соглашения __thiscall. Далее к объекту тайпдефа кастим указатель на нулевую виртуальную функцию в виртуальной таблице, проверяем на валидность и вызываем. Вы уже могли начать догадываться о том, что указатель внутри виртуальной таблицы можно подменить на свою функцию тем самым установив хук (как и делают VMT hooks библиотеки). Пример: class CEngine { public: CEngine() {} virtual void Func1() { printf("CEngine::Func1\n"); } virtual void Func2() { printf("CEngine::Func2\n"); } virtual ~CEngine() {} }; void __fastcall hkFunc1() { printf("Hook was called\n"); } int main() { CEngine * g_pEngine = new CEngine(); DWORD * VMT = *(DWORD**)g_pEngine; g_pEngine->Func1(); // call orig method DWORD oldProt; VirtualProtect(VMT, SizeOfVMT(VMT) * sizeof(DWORD), PAGE_EXECUTE_READWRITE, &oldProt); VMT[0] = (DWORD)hkFunc1; // "hook" VirtualProtect(VMT, SizeOfVMT(VMT) * sizeof(DWORD), oldProt, &oldProt); g_pEngine->Func1(); // call hook method delete g_pEngine; return 0L; } Получаем указатель на начало виртуальной таблицы. Ставим флаг на память, чтобы разрешить нам писать туда. Подменяем указатель на оригинальный метод указателем на нашу hook - функцию, которая имеет прототип оригинальной функции с соглашением __fatscall (объяснял выше). Также нужно делать трамполайн - возврат оригинального адреса, а то будет краш. Делается это также как и ставится хук. Разбирайтесь) With love by P45H3 =)
comment_446With love by P45H3 =)