Hook入门之鼠标钩子

发布时间:2025-12-09 19:17:16 浏览次数:4

   之前有一次吃饭的时候,听前辈聊到猜想某某输入法的钩子,导致了我们软件crash了,问用户是不是用的某某输入法。当时就比较好奇钩子是啥。

   一百度,也能发现网上有非常多的资料可以参考,阅读了一些资料,这里就用比较新手的语言去描述钩子,在系统的消息队列之前拦截消息,对消息进行修改或者拦截,或者原封不动,传递下去。当然,更好的教科书式学习是参考《Windows核心编程》的第22章《DLL注入和API拦截》。参考网上获得的鼠标钩子的源代码,解析和学习一下做一个简单的鼠标钩子的流程和步骤,以及涉及到的知识。

(1)

首先,新建DLL模块,在DLL中声明几个全局变量,并且放入共享的数据段中,如下:

//// 共享代码段,所有线程共享//#pragma data_seg("SHARED")static HHOOK hhkMouse = NULL; // 鼠标钩子句柄static HINSTANCE g_hInstance = NULL; // 本DLL的实例句柄static HWND g_hWnd = NULL; // 调用DLL的主窗口句柄,这样就可以SendMessage给主窗口鼠标消息及其参数#pragma data_seg()#pragma comment(linker,"/section:SHARED,rws")

延伸问题一: 那几个变量为什么要放入共享段呢?放进去共享段的实际意义是啥呢?

首先,通过我个人的测试而言,这几个变量作为DLL中的全局变量也是不影响使用的。

1,#pragma data_seg()一般用于DLL中。也就是说,在DLL中定义一个共享的,有名字的数据段。最关键的是:这个数据段中的全局变量可以被多个进程共享。否则多个进程之间无法共享DLL中的全局变量。

2,共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。

3. 字母RWS表示段具有读、写和共享属性


在DLL中定义低级鼠标处理函数,就是预先处理对应消息的“拦截函数”,如下:

//// 定义低级鼠标钩子函数//LRESULT CALLBACK LowLevelMouseProc(int nCode,// hook code WPARAM wParam,// message identifierLPARAM lParam// mouse coordinates){// 有鼠标消息时,将其发给主程序if ( g_hWnd != NULL && nCode == HC_ACTION){::SendMessage(g_hWnd,WM_HOOKMSG,wParam,lParam);}return CallNextHookEx(hhkMouse,nCode,wParam,lParam);}

延伸问题二: 什么叫低级?那高级是怎么样的?

 

在DLL中,定义安装钩子函数和卸载钩子函数:

//// 安装低级鼠标子函数,从而截获系统所有的鼠标消息//BOOL WINAPI StartHookMouse(HWND hwnd){g_hWnd = hwnd;hhkMouse = SetWindowsHookEx(WH_MOUSE_LL,LowLevelMouseProc,g_hInstance,0);if ( NULL == hhkMouse){return FALSE;}else{return TRUE;}}//// 卸载低级鼠标钩子//VOID WINAPI StopHookMouse(){if (hhkMouse != NULL){::UnhookWindowsHookEx(hhkMouse);}}

延伸问题三: 为什么我们安装钩子要在DLL的函数中进行呢,可不可以在主程序中安装钩子(虽然DLL起码可以把“拦截函数”封装起来)

全局钩子必须安装在DLL中,局部的钩子可以写在主程序中。消息队列是以线程为基础的.一个局部HOOK勾挂的是一个进程内所有线程的消息。此类实现由于不涉及进程CONTEXT切换,是轻量级的HOOK。全局的HOOK会映射到所有加载USER32.DLL的进程中,其实是USER32.DLL为这些进程调用LOADLIBRARY来加载HOOK所在的DLL,并且在所有的消息在被送到消息处理前先调用HOOKPROC。

 全局的钩子对系统所有进程有效,当某个进程触发钩子事件时,就会从钩子链中依次执行对应的钩子函数,如果钩子链中某个全局钩子没有出现在进程空间,就会加载对应的钩子Dll(loadlibrary)。这个全局钩子的dll是会被所有能钩触发进程给加载的,如果是exe,显然不能实现

接下来注意的一个问题,我们使用的是def文件,它用来定义DLL中导出的函数,比如,def文件中定义导出的函数:

; hookDll.def : 声明 DLL 的模块参数。LIBRARY "MouseHook"EXPORTS; 此处可以是显式导出StartHookMouseStopHookMouse

(2)

MFC中的小窗口实现主程序,与Hook的技术无关,只要实现按钮和消息即可。

(3)

DLL与主程序进行通信,主要是通过在DLL中和主程序中,自定义消息,DLL的“拦截函数”将拦截到的鼠标信息发送给主程序,从而可以让主程序打印出对应的鼠标消息

延伸问题四: 为什么要进行通信呢?

通信是为了让DLL的“拦截函数”把捕获到的鼠标信息发送给调用窗口,使得调用窗口显示出鼠标消息展示给我们看。

效果大致如图所示:

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477