在介绍 截获系统消息钩子 之前,这几个函数是密切相关的:
SetWindowsHookEx() 介绍:
功能:将应用程序定义的挂钩过程安装到挂钩链中。
函数原型:HHOOK SetWindowsHookEx(
int idHook, // 钩子类型。
HOOKPROC lpfn, // 指向挂钩过程的指针。
HINSTANCE hmod, // 包含 lpfn 参数指向的挂钩过程的 DLL 的句柄。
DWORD dwThreadId // 与挂钩过程关联的线程的标识符。如果为 0,则为全局钩子。
);
返回值:如果函数成功, 则返回值是挂钩过程的句柄。如果函数失败, 返回值为 NULL。
参数 idHook:
值 | 含义 |
WH_CALLWNDPROC | 安装的钩子过程监视信息在系统将它们发送给目标窗口之前。 |
WH_CALLWNDPROCRET | 安装的钩子过程监视信息在系统将它们发送给目标窗口之后。 |
WH_KEYBOARD | 安装监视击键消息的挂钩过程。 |
WH_MOUSE | 安装监视鼠标消息的挂钩过程。 |
WH_GETMESSAGE | 安装用于监视将消息发送给消息队列的挂钩过程 |
WH_DEBUG | 安装用于调试其他挂钩过程的挂钩过程。 |
CallNextHookEx() 介绍:
功能:将挂钩信息传递到当前挂钩链中的下一个挂钩过程。钩子过程可以在处理钩子信息之前或之后调用此函数。
函数原型:LRESULT CallNextHookEx(
HHOOK hhk, // 通常被忽略。
int nCode, // 传递给当前挂钩过程的挂钩代码。下一个挂钩过程使用此代码来确定如何处理挂钩信息。
WPARAM wParam, // 传递给当前挂钩过程的 wParam 值。此参数的含义取决于与当前挂钩链关联的挂钩的类型。
LPARAM lParam // 传递给当前挂钩过程的 lParam 值。此参数的含义取决于与当前挂钩链关联的挂钩的类型。
);
返回值:此值由链中的下一个挂钩过程返回。当前挂钩过程还必须返回此值。返回值的含义取决于挂钩类型。
UnhookWindowsHookEx() 介绍:
功能:移除由 SetWindowsHookEx 函数安装在钩子链中的挂钩过程。
函数原型:BOOL UnhookWindowsHookEx(
HHOOK hhk // 要移除的钩子的句柄。
);
返回值:非零表示成功,零表示失败。
用户自定义钩子:(生成 dll 文件,并注入到相应的进程)
#include<windows.h> #include<stdlib.h> HANDLE hProc; FARPROC pfMessageBoxA; FARPROC pfMessageBoxW;
// 注意:自定义函数得和被 HOOK 函数的形式一样,否则会发生异常。 int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR sl, UINT u); int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR sl, UINT u); BYTE OldMessageBoxACode[5], NewMessageBoxACode[5]; BYTE OldMessageBoxWCode[5], NewMessageBoxWCode[5]; DWORD CurrentProcessId, dwOldProtect;; BOOL BHook = FALSE; BOOL Init(); void HookOn(); void HookOff(); BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:Init();break; case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;case DLL_PROCESS_DETACH:HookOff();break;}return TRUE; } BOOL Init() {HMODULE hModule;DWORD Address;hModule = LoadLibraryA("user32.dll");pfMessageBoxA = GetProcAddress(hModule, "MessageBoxA");pfMessageBoxW = GetProcAddress(hModule, "MessageBoxW");if (pfMessageBoxA == NULL || pfMessageBoxW == NULL)return FALSE;memcpy(OldMessageBoxACode,pfMessageBoxA,5); // 拷贝原来函数地址的前五个字节以备复原。NewMessageBoxACode[0] = 0xe9; // 即 jmp 指令。Address = (DWORD)MyMessageBoxA - (DWORD)pfMessageBoxA - 5; // 自定义函数与原函数的偏移地址。memcpy(NewMessageBoxACode+1,&Address,4); memcpy(OldMessageBoxWCode,pfMessageBoxW,5);NewMessageBoxWCode[0] = 0xe9;Address = (DWORD)MyMessageBoxW - (DWORD)pfMessageBoxW - 5;memcpy(NewMessageBoxWCode+1,&Address,4);CurrentProcessId = GetCurrentProcessId();HookOn();return TRUE; }int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR pl, UINT u) {HookOff();MessageBoxA(hWnd, "请重新安装系统", "重要提示", MB_OK);HookOn();return TRUE; }int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR pl, UINT u) {HookOff();MessageBoxW(hWnd, L"请重新安装系统", L"重要提示", MB_OK);HookOn();return TRUE; }void HookOn() {hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, CurrentProcessId);// 打开进程,关闭内存保护,向内存空间前五个字节写入 jmp 指令,最后打开进程保护。VirtualProtectEx(hProc, pfMessageBoxA, 5, PAGE_READWRITE, &dwOldProtect);WriteProcessMemory(hProc, pfMessageBoxA, NewMessageBoxACode, 5, 0);VirtualProtectEx(hProc, pfMessageBoxA, 5, dwOldProtect, &dwOldProtect);VirtualProtectEx(hProc, pfMessageBoxW, 5, PAGE_READWRITE, &dwOldProtect);WriteProcessMemory(hProc, pfMessageBoxW, NewMessageBoxWCode, 5, 0);VirtualProtectEx(hProc, pfMessageBoxW, 5, dwOldProtect, &dwOldProtect);CloseHandle(hProc);BHook = TRUE; }void HookOff() {hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, CurrentProcessId);// 同理,只不过是复原内存指令。VirtualProtectEx(hProc, pfMessageBoxA, 5, PAGE_READWRITE, &dwOldProtect);WriteProcessMemory(hProc, pfMessageBoxA, OldMessageBoxACode, 5, 0);VirtualProtectEx(hProc, pfMessageBoxA, 5, dwOldProtect, &dwOldProtect);VirtualProtectEx(hProc, pfMessageBoxW, 5, PAGE_READWRITE, &dwOldProtect);WriteProcessMemory(hProc, pfMessageBoxW, OldMessageBoxWCode, 5, 0);VirtualProtectEx(hProc, pfMessageBoxW, 5, dwOldProtect, &dwOldProtect);CloseHandle(hProc);BHook = FALSE; }
注入后,如下图所示: