主页 > 创业  > 

Windows核心编程HOOK

Windows核心编程HOOK

目录

HOOK概述

HOOK API

SetWindowsHookExA 函数(winuser.h)

UnhookWindowsHookEx 函数(winuser.h)

NextHookEx 函数(winuser.h)

局部钩子

全局钩子

为什么全局钩子需要用dll作为过程函数?


HOOK概述

本质:Windows消系统的消息过滤器。

全局钩子原理:将自己的dll注入到别的进程。并不是一开始就注入所有程序。

钩子种类:

局部钩子:仅仅在当前进程下有效全局钩子:又称为系统钩子,在WIndows所有的进程都有效。

不用种类的钩子有自己的不同的回调函数。

钩子原理:回调函数,操作系统先发给我们,然后在发送给窗口。

系统给w2的消息;正常情况下我们w1是获取不到的,但是可以使用hook技术,将原来的消息先勾到我们(w1)这里,然后再回给系统,系统再重新转发给w2;这样w1就可以看到w2的消息;

HOOK作为注入的技术手段之一,可以利用hook技术,往对方的进程里面注入代码,获取进程相关的信息;作监控的东西,eg:spy++

HOOK API SetWindowsHookExA 函数(winuser.h)

将应用程序定义的钩子子程安装到钩子链中。您将安装一个钩子子程来监视系统的某些类型的事件。这些事件或者与特定的线程相关联,或者与调用线程在同一桌面中的所有线程相关联。

WINUSERAPI HHOOK WINAPI SetWindowsHookEx( //钩子类型 _In_ int idHook, //回调函数地址 _In_ HOOKPROC lpfn, //实例句柄(包含有钩子函数) _In_opt_ HINSTANCE hmod, //线程ID,欲勾住的线程(为0则不指定,全局) _In_ DWORD dwThreadId); 参数1 int idHook:钩子类型 参数2 HOOKPROC lpfn:回调函数,每个类型的钩子需匹配各自对应的回调函数参数3 HINSTANCE hMod:实例句柄,局部钩子填NULL;全局钩子填dll的模块句柄(钩子的回调函数会填入dll)。使用 GetModuleHandle("Dll1")  获取参数4 DWORD dwThreadId:线程ID,局部钩子填自己窗口的线程ID(UI主线程);全局钩子填0会钩系统范围内所有窗口的消息。

参数一:idHook的选项:

价值意义WH_CALLWNDPROC安装一个钩子子程,在系统将消息发送到目标窗口过程之前监视消息。WH_CALLWNDPROCRET安装一个钩子子程,在消息被目标窗口过程处理后监视消息。WH CBT安装一个钩子子程来接收对CBT应用程序有用的通知。WH_DEBUG安装一个钩子子程,用于调试其他钩子子程。WH _FOREGROUNDIDLEz安装一个钩子子程,当应用程序的前台线程即将空闲时,将调用这个钩子子程。这个挂钩对于在空闲时间执行低优先级任务很有用。WH_GETMESSAGE安装一个钩子子程来监视发送到消息队列的消息。WH_JOURNALPLAYBACK安装一个钩子子程,该钩子子程发送WH日志WH_JOURNALRECORD安装一个钩子子程,记录发送到系统消息队列的输入消息。这个钩子对于记录宏很有用。WH_KEYBOARD安装一个钩子子程来监视击键消息。WH_KEYBOARD_LL安装一个钩子子程来监视低级键盘输入事件。WH_MOUSE安装一个钩子子程来监视鼠标消息。WH_MOUSE_LL安装一个钩子子程来监视低级别的鼠标输入事件。WH_MSGFILTER安装一个钩子子程,监视对话框、消息框、菜单或滚动条中的输入事件所生成的消息。WH_SHELL安装一个钩子子程来接收对shell应用程序有用的通知。WH_SYSMSGFILTER安装一个钩子子程,监视对话框、消息框、菜单或滚动条中的输入事件所生成的消息。钩子子程在与调用线程相同的桌面中为所有应用程序监视这些消息。

参数二:lpfn

类型:函数指针 回调函数,钩子拿到这些信息怎么给你,通过回调函数把信息交给你;需要注意,不同钩子的回调函数不一样,可以通过msdn查看; 钩子子程的指针。如果_dwThreadId_参数为零或指定由不同进程创建的线程的标识符,则_lpfn_参数必须指向DLL中的钩子子程。否则,_lpfn_可以指向与当前进程关联的代码中的钩子子程。

参数三:hmod

类型:实例句柄 局部钩子填写NULL;全局钩子填窗口所在模块的句柄,(全局程序会卡)DLL的句柄

参数四:dwThreadId

类型:双字节值 钩子子程要关联的线程的id,要钩的窗口所在的线程所在的id,每个进程的主线程id;

类型:钩子的句柄 如果函数成功,返回值是钩子子程的句柄。 如果函数失败,返回值为NULL。若要获取扩展的错误信息,请调用错误码.

 

UnhookWindowsHookEx 函数(winuser.h)

移除安装在钩子链中的钩子子程钩子函数功能。

BOOL UnhookWindowsHookEx( [in] HHOOK hhk );

参数:[in] hhk 类型:钩子的句柄 要移除的钩子的句柄,SetWindowsHookExA的返回值。此参数是通过以前调用钩子函数

返回值:类型:布尔 如果函数成功,返回值是非零的。 如果函数失败,返回值为零。若要获取扩展的错误信息,请调用错误码

NextHookEx 函数(winuser.h)

将钩子信息传递给当前钩子链中的下一个钩子子程。钩子子程可以在处理钩子信息之前或之后调用这个函数

LRESULT CallNextHookEx( [in, optional] HHOOK hhk, [in] int nCode, [in] WPARAM wParam, [in] LPARAM lParam );

参数

[in, optional] hhk 类型:钩子的句柄 该参数被忽略。

[in] nCode 类型:(同Internationalorganizations)国际组织 传递给当前钩子子程的钩子代码。下一个钩子子程使用这个代码来决定如何处理钩子信息。

[in] wParam 类型:WPARAM 这_参数_传递给当前钩子子程的值。此参数的含义取决于与当前挂钩链相关联的挂钩类型。

[in] lParam 类型:参数 这_参数_传递给当前钩子子程的值。此参数的含义取决于与当前挂钩链相关联的挂钩类型。

返回值 类型:LRESULT 该值由链中的下一个钩子子程返回。当前钩子子程也必须返回这个值。返回值的含义取决于钩子的类型。

局部钩子

只能钩自己的窗口

// MFC基于对话框项目 HHOOK g_hHook; // 键盘回调函数 LRESULT CALLBACK KeyboardProc( _In_ int code, _In_ WPARAM wParam, _In_ LPARAM lParam ) { // 特殊检查 if (code < 0) { return CallNextHookEx(g_hHook, code, wParam, lParam); } CString strFmt; strFmt.Format("HT:%c", wParam); OutputDebugString(strFmt); return CallNextHookEx(g_hHook, code, wParam, lParam); } // 局部Hook 安装 void CHookTestDlg::OnBnClickedButton1() { // 设置钩子 g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, GetCurrentThreadId()); if (g_hHook == NULL) { AfxMessageBox("局部钩子安装失败"); } } // 局部Hook 卸载 void CHookTestDlg::OnBnClickedButton3() { UnhookWindowsHookEx(g_hHook); // 卸载钩子 } 执行结果

全局钩子

钩子的回调函数会填入DLL,以便按需注入

// 动态链接库项目 HookDll.cpp代码 HHOOK g_hHook; LRESULT CALLBACK MyKeyboardProc(int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ) { if (code < 0) { return CallNextHookEx(g_hHook, code, wParam, lParam); } char szBufff[MAXBYTE]; wsprintf(szBufff, "HT:%c pid:%d", wParam, GetCurrentProcessId()); OutputDebugString(szBufff); return CallNextHookEx(g_hHook, code, wParam, lParam); } __declspec(dllexport) BOOL InstallHook() { g_hHook = SetWindowsHookEx( WH_KEYBOARD, MyKeyboardProc, GetModuleHandle("HookDll"), 0); if (g_hHook != NULL) { return TRUE; } return FALSE; } __declspec(dllexport) VOID UnInstallHook() { UnhookWindowsHookEx(g_hHook); } // 使用dll的MFC对话框项目代码 __declspec(dllimport) BOOL InstallHook(); __declspec(dllimport) VOID UnInstallHook(); #pragma comment(lib, "./Debug/HookDll.lib") // 安装全局钩子 void CHookTestDlg::OnBnClickedButton2() { if (!InstallHook()) { AfxMessageBox("安装全局钩子失败"); } } // 卸载全局钩子 void CHookTestDlg::OnBnClickedButton4() { UnInstallHook(); }

或者填写def文件

为什么全局钩子需要用dll作为过程函数?

在别的程序运行过程函数监听消息。

全局钩子在安装钩子后,如果安装钩子的程序关闭,目标进程的dll也会自动卸载。

安装了同一时间的全局钩子和局部钩子,系统优先调用局部钩子,然后调用全局钩子。安装多个钩子处理过程,形成钩子链。当钩子结束后赢吧钩子信息传递给下一个钩子函数。钩子链式栈结构,最后安装的,最先获得控制权。全局钩子会消耗消息处理的时间,降低系统性能,所以全局钩子并不是全部注入到所有程序中,而是在发生消息事件的时候,才将dll注入到目标程序中安装钩子。安装的钩子需要释放,安装钩子的主程序关闭,其他程序的钩子也会自动释放。在键盘钩子回调函数中,修改wparam的值不会影响目标进程的值。

标签:

Windows核心编程HOOK由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Windows核心编程HOOK