原理:通过SetWindowsHookEx函数将DLL注入到进程的地址空间中,最后一个参数dwThreadId指向的是被注入进程内的某个线程ID。
(1) 进程A对线程dwThread挂键盘钩子
(2) 线程dwThreadId获取到的键盘消息会实现被钩子拦截
(3) 系统检查hMod指向的DLL是否已被载入到线程dwThreadId所在的进程地址空间中,若否,则载入。这时,假设DLL被载入到进程B
(4) 系统在进程B的地址空间中调用lpfn函数
钩子的回调函数格式
1 2 3 4 5
| LRESULT CALLBACK FunProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information )
|
消息框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <windows.h>
/* * @brief 显示一个消息框,并等待用户的响应。 * * @param hwndParent 父窗口的句柄,如果为nullptr,则消息框将居中显示在屏幕上。 * @param lpText 要显示的消息文本。 * @param lpCaption 消息框标题。 * @param uType 消息框的类型,可以是以下值的组合: * - MB_ABORTRETRYIGNORE * - MB_CANCELTRYCONTINUE * - MB_HELP * - MB_OK * - MB_OKCANCEL * - MB_RETRYCANCEL * - MB_YESNO * - MB_YESNOCANCEL * @return 用户的响应。可能的值包括: * - IDABORT * - IDCANCEL * - IDCONTINUE * - IDIGNORE * - IDNO * - IDOK * - IDRETRY * - IDTRYAGAIN * - IDYES */ int MessageBox( HWND hwndParent, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );
|
CallNextHookEx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <windows.h>
/** * @brief 调用下一个钩子程序在钩子链中。 * * @param hhk 钩子句柄,由SetWindowsHookEx函数返回。 * @param nCode 钩子代码,表示事件类型。具体取值取决于使用的钩子类型。 * @param wParam 与事件相关的附加信息,具体含义取决于使用的钩子类型。 * @param lParam 与事件相关的附加信息,具体含义取决于使用的钩子类型。 * @return 下一个钩子程序的返回值,具体含义取决于使用的钩子类型。 */ LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam );
CallNextHookEx是Windows API中用于调用下一个钩子程序的函数。在使用钩子函数时,它允许当前的钩子程序调用下一个钩子程序,以确保整个钩子链能够正常运行。
参数说明:
hhk:钩子句柄,由 SetWindowsHookEx 函数返回。 nCode:钩子代码,表示事件类型。具体取值取决于使用的钩子类型。 wParam:与事件相关的附加信息,具体含义取决于使用的钩子类型。 lParam:与事件相关的附加信息,具体含义取决于使用的钩子类型。 返回值: CallNextHookEx 的返回值取决于使用的钩子类型,通常是下一个钩子程序的返回值。
|
FindWindow
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <windows.h>
/** * @brief 根据窗口类名和窗口标题查找顶层窗口的句柄。 * * @param lpClassName 窗口类名,如果为NULL,则匹配所有类名。 * @param lpWindowName 窗口标题,如果为NULL,则匹配所有标题。 * @return 找到的窗口的句柄,如果未找到则为NULL。 */ HWND FindWindow( LPCSTR lpClassName, LPCSTR lpWindowName );
lpClassName:窗口类名,如果为NULL,则匹配所有类名。 lpWindowName:窗口标题,如果为NULL,则匹配所有标题。 返回值:找到的窗口的句柄,如果未找到则为NULL。
|
GetWindowThreadProcessId
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <windows.h>
/** * @brief 获取指定窗口的线程标识符和进程标识符。 * * @param hWnd 目标窗口的句柄。 * @param lpdwProcessId 接收进程标识符的指针,如果为NULL则不检索。 * @return 返回目标窗口所在的线程标识符。 */ DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );
hWnd:目标窗口的句柄。 lpdwProcessId:接收进程标识符的指针。如果为NULL,则不检索进程标识符。 返回值:返回目标窗口所在的线程标识符。 该函数允许您获取与指定窗口相关联的线程标识符和进程标识符。可以使用这些标识符来进行诸如线程注入和进程间通信等操作。
|
SetWindowsHookEx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <windows.h>
/** * @brief 安装一个钩子函数来监视指定类型的事件。 * * @param idHook 要安装的钩子类型。 * @param lpfn 钩子过程的地址。 * @param hMod 包含钩子过程的 DLL 的句柄。如果为NULL,则将使用当前进程的句柄。 * @param dwThreadId 与要监视的事件相关联的线程的标识符。如果为0,则表示安装全局钩子。 * @return 成功时返回钩子的句柄,失败时返回NULL。 */ HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId );
其中idHook参数可以取如下常量: WH_CALLWNDPROC //窗口钩子,当系统向目标窗口发送消息时将触发此钩子 WH_CALLWNDPROCRET //窗口钩子,当窗口处理完消息后将触发此钩子 WH_CBT //当Windows激活、产生、释放(关闭)、最小化、最大化或改变窗口时都将触发此事件 WH_DEBUG //调试钩子 WH_GETMESSAGE //当往消息队列中增加一个消息时将触发此钩子 WH_JOURNALPLAYBACK //回放钩子,可以用于播放已记录的鼠标和键盘的操作 WH_JOURNALRECORD //记录钩子,可以用于记录鼠标和键盘的操作,木马程序可以使用此钩子窃取受控方在屏幕中敲入的密码 WH_KEYBOARD //当敲击键盘时将触发此钩子 WH_MOUSE //当有鼠标操作时将触发此钩子 WH_MSGFILTER //消息过滤钩子 WH_SHELL //Shell钩子 WH_SYSMSGFILTER //系统消息过滤钩子 其他特定类型的钩子,具体取决于您的需求。
lpfn:指向钩子过程的函数指针。此函数在发生事件时被调用。 hMod:包含钩子过程的 DLL 的句柄。如果为NULL,则将使用当前进程的句柄。 dwThreadId:与要监视的事件相关联的线程的标识符。如果为0,则表示安装全局钩子,针对所有线程的事件。 返回值:成功时返回钩子的句柄,失败时返回NULL。 SetWindowsHookEx函数用于安装一个钩子,允许您监视并拦截指定类型的事件。成功安装后,钩子过程将在事件发生时被调用。通常,钩子过程是在DLL中实现的,以便可以在不同进程间共享。
|
UnhookWindowsHookEx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <windows.h>
/** * @brief 卸载之前安装的钩子。 * * @param hhk 先前安装的钩子的句柄。 * @return 如果成功,返回非零值;如果失败,返回零。 */ BOOL UnhookWindowsHookEx( HHOOK hhk );
hhk:先前安装的钩子的句柄,由 SetWindowsHookEx 返回。 返回值:如果成功,返回非零值;如果失败,返回零。 UnhookWindowsHookEx函数用于卸载之前通过 SetWindowsHookEx 安装的钩子。在不再需要钩子时,调用此函数以确保释放相关资源,并停止钩子过程的调用。成功卸载后,钩子句柄将不再有效。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <Windows.h>
LRESULT CALLBACK FunProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ) { MessageBox(NULL,"KEY PRESS","hook inject",MB_OK); return CallNextHookEx(0,code,wParam,lParam); }
HHOOK g_HookHandle;
__declspec(dllexport) void SetHook() { DWORD tid = 0; // 获取窗口句柄 HWND gameh = FindWindow(NULL,"test.txt - 记事本"); if (gameh == 0) { return; } // 获取创建这个窗口的线程 tid = GetWindowThreadProcessId(gameh,NULL); // 安装钩子到指定线程 WH_KEYBOARD 键盘钩子 g_HookHandle = SetWindowsHookEx(WH_KEYBOARD, FunProc, GetModuleHandle("HOOKInject.dll"),tid); }
__declspec(dllexport) void UnHook() { UnhookWindowsHookEx(g_HookHandle); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <stdio.h> #include <windows.h>
typedef void (*lpFun)(); int main() { HINSTANCE hDll; //DLL句柄 lpFun SetHook; //函数指针 lpFun UnHook; //函数指针 hDll = LoadLibrary("..\\Debug\\HOOKInject.dll"); if (hDll != NULL) { SetHook = (lpFun)GetProcAddress(hDll, "SetHook"); UnHook = (lpFun)GetProcAddress(hDll, "UnHook"); }
if (SetHook != NULL) { SetHook(); } getchar(); UnHook(); if (hDll != NULL) { FreeLibrary(hDll); }
return 0; }
|