#include "hook.h" #include #include #include #include "../../lib/mice/mice.h" function_hook_t* hook_list = NULL; void append_hook(function_hook_t* hook) { hook->next = NULL; if (hook_list == NULL) { hook_list = hook; return; } function_hook_t* hl = hook_list; while (hl->next != NULL) hl = hl->next; hl->next = hook; } void hook(LPCSTR dll, LPCSTR name, void* patch, void** store) { function_hook_t* hook = (function_hook_t*)malloc(sizeof(struct function_hook)); hook->dll = dll; hook->name = name; hook->patch = patch; hook->store = store; append_hook(hook); } void patch_at(PVOID addr, const char* patch, DWORD length) { DWORD oldProt; VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt); memcpy(addr, patch, length); VirtualProtect(addr, length, oldProt, &oldProt); } void clear_at(PVOID addr, BYTE clearVal, DWORD length) { DWORD oldProt; VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt); memset(addr, clearVal, length); VirtualProtect(addr, length, oldProt, &oldProt); } BOOL Detour(PVOID src, PVOID dst, const intptr_t len) { if (len < 5) return FALSE; DWORD oldProt; VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt); *(PCHAR)src = '\xE9'; *(PINT)((int)src + 1) = (int)dst - (int)src - 5; VirtualProtect(src, len, oldProt, &oldProt); return TRUE; } void* Win32HotpatchHook(PVOID src, PVOID dst) { LPBYTE bSrc = (LPBYTE)src; DWORD oldProt; VirtualProtect(bSrc - 5, 7, PAGE_EXECUTE_READWRITE, &oldProt); // relative JMP to dst bSrc[-5] = 0xE9; DWORD relJump = (DWORD)dst - (DWORD)src; bSrc[-1] = (relJump >> 24) & 0xff; bSrc[-2] = (relJump >> 16) & 0xff; bSrc[-3] = (relJump >> 8) & 0xff; bSrc[-4] = relJump & 0xff; // JMP $-5 bSrc[0] = 0xEB; bSrc[1] = 0xF9; VirtualProtect(bSrc - 5, 7, oldProt, &oldProt); // We don't need a gateway; we can just jump right in return bSrc + 2; } void* CreateHook32(PVOID src, PVOID dst) { LPBYTE bSrc = (LPBYTE)src; // If this DLL is hotpatchable, sieze the opportunity if (bSrc[0] == 0x8b && bSrc[1] == 0xff && bSrc[-1] == 0xCC && bSrc[-2] == 0xCC && bSrc[-3] == 0xCC && bSrc[-4] == 0xCC && bSrc[-5] == 0xCC) { return Win32HotpatchHook(src, dst); } intptr_t len = 5; // This is a very crude way to identify common instruction patterns // to select or patch length. if (bSrc[0] == 0xff && bSrc[1] == 0x25) { // jmp DWORD PTR ds:0x........ len = 6; } else if (bSrc[0] == 0x6a && bSrc[2] == 0x68) { // push 0x... (byte) // push 0x... (dword) len = 7; } else if (bSrc[0] == 0x6a && bSrc[2] == 0xb8) { // push 0x... (byte) // mov eax,0x... (dword) len = 7; } else if (bSrc[0] == 0x68) { // push 0x... (dword) len = 5; } else if (bSrc[0] == 0x55 && bSrc[1] == 0x8B && bSrc[2] == 0xEC && bSrc[3] == 0x83 && bSrc[4] == 0xE4) { // pusb ebp // mov ebp,esp // and esp,ffffff** len = 6; } else if (bSrc[0] == 0x55 && bSrc[1] == 0x8B && bSrc[2] == 0xEC && bSrc[3] == 0x8b && bSrc[4] == 0x45) { // pusb ebp // mov ebp,esp // mov eax,DWORD PTR [...] len = 6; } else if (bSrc[0] == 0x55 && bSrc[1] == 0x8B && bSrc[2] == 0xEC && bSrc[3] == 0x80 && bSrc[4] == 0x3D) { // pusb ebp // mov ebp,esp // cmd BYTE PTR ds:0x...,0x... len = 10; } else { log_error(plfHooks, "Unable to identify gateway length! Function peek:"); for (int i = 0; i < 16; i++) { printf("%02x ", ((LPBYTE)src)[i]); } puts(""); log_error(plfHooks, "Unsafely defaulting to 5!"); len = 5; } PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!gateway) return NULL; memcpy(gateway, src, len); *(PCHAR)((int)gateway + len) = '\xE9'; *(PINT)((int)gateway + len + 1) = (int)src - (int)gateway - 5; Detour(src, dst, len); return gateway; } extern FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName); void setup_hooks() { log_info(plfHooks, "attaching"); if (hook_list == NULL) { log_warning(plfHooks, "No hooks to register!"); return; } function_hook_t* hook = hook_list; do { if (hook->dll == NULL) continue; HMODULE dll = LoadLibraryA(hook->dll); if (dll == NULL) { log_error(plfHooks, "failed to load dll %s (%03x). %s skipped", hook->dll, GetLastError(), hook->name); hook = hook->next; continue; } // void* original = // (TrueGetProcAddress ? TrueGetProcAddress : GetProcAddress)(dll, hook->name); void* original = GetProcAddress(dll, hook->name); if (original == NULL) { log_warning(plfHooks, "failed to get original %s (%03x)", hook->name, GetLastError()); } else { void* gateway = CreateHook32(original, hook->patch); if (hook->store != NULL) *hook->store = gateway; log_misc(plfHooks, "hooked %s", hook->name); } hook = hook->next; } while (hook != NULL); log_info(plfHooks, "attach complete"); }