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也是這樣實現的。
本文提供的代碼可以隨意引用,但請充分測試后再部署,出問題本人不承擔任何責任,歡迎有任何建議和補充~