API HOOK有两种做法,一种是SetWindowHookEx,简单易用,但如果做其它的HOOK,如HOOK OpenProcess,就需要修改内存地址了,内存地址可以通过WriteProcessMemory来修改,先将调用函数的地址改成自己的(jmp到自己的函数),然后需要时,再改回来。
#pragma once #ifdef _M_IX86 template <typename T> class Hooker { protected: static DWORD HookFunction(LPCWSTR lpModule, LPCSTR lpFuncName, PROC lpFunction) { DWORD dwAddr = (DWORD) GetProcAddress(GetModuleHandle(lpModule), lpFuncName); BYTE jmp [] = { 0xe9, //jmp 0x00, 0x00, 0x00, 0x00, //address 0xc3 //retn }; ReadProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 6, 0); DWORD dwCalc = ((DWORD) lpFunction - dwAddr - 5); //((to)-(from)-5) memcpy(&jmp[1], &dwCalc, 4); //build the jmp WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, jmp, 6, 0); return dwAddr; } static BOOL UnHookFunction(LPCWSTR lpModule, LPCSTR lpFuncName) { DWORD dwAddr = (DWORD) GetProcAddress(GetModuleHandle(lpModule), lpFuncName); if (WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 6, 0)) return TRUE; return FALSE; } static BYTE* MemoryAddress() { static BYTE backup[6]; return backup; } }; #elif _M_AMD64 template <typename T> class Hooker { protected: static UINT64 HookFunction(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction) { UINT64 dwAddr = (UINT64) GetProcAddress(GetModuleHandle(lpModule), lpFuncName); BYTE jmp [] = { 0x48, 0xb8, //jmp 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //address 0x50, 0xc3 //retn }; ReadProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 12, 0); UINT64 dwCalc = (UINT64) lpFunction; memcpy(&jmp[2], &dwCalc, 8); //build the jmp WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, jmp, 12, nullptr); return dwAddr; } static BOOL UnHookFunction(LPCWSTR lpModule, LPCSTR lpFuncName) { UINT64 dwAddr = (UINT64) GetProcAddress(GetModuleHandle(lpModule), lpFuncName); if (WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 12, 0)) return TRUE; return FALSE; } static BYTE* MemoryAddress() { static BYTE backup[12]; return backup; } }; #endif
值得注意的是,64位和32位的注入字节有些许不同。
由于目前Visual Studio 2013 Preview实现的C++类中,还是不允许有非int静态变量,但却允许函数中有静态变量,所以我将目标指针数据备份到静态成员中:
static BYTE* MemoryAddress() { static BYTE backup[6]; return backup; }
然后,在使用时,从Hooker继承一个类即可:
class MessageBoxHooker : Hooker<MessageBoxHooker> { public: static void BeginHook() { HookFunction(L"user32.dll", "MessageBoxW", (PROC) MyMessageBoxW); } static void StopHook() { UnHookFunction(L"user32.dll", "MessageBoxW"); } private: static int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { StopHook(); int x = MessageBox(hWnd, L"hooked", lpCaption, uType); BeginHook(); return x; } };
要开启Hook,只需调用:
MessageBoxHooker::BeginHook();
这个API HOOK库我使了一个模板,之所以用模板是因为C++函数指针不包含实例的指针。这种使用模板来解决C++指针的缺点的做法很常见,ATL也是这样实现的。
本文提供的代码可以随意引用,但请充分测试后再部署,出问题本人不承担任何责任,欢迎有任何建议和补充~