《2022年2022年钩子函数的使用 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年钩子函数的使用 .pdf(12页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、微软的 windowsX 操作系 统是建立在事件 驱动 的机制上的,也就是通过消息 传递 来实现 。而钩子在 windows 操作系 统中,是一 种能在事件(比如:消息、鼠标激活、 键盘响应)到达 应用程序前中途接获事件的机制。而且,钩子函数 还可以通 过修改、 丢弃等手段来 对事件起作用。Windows 有两种钩 子,一种是特定 线程钩子( Thread specific hooks),一 种是全局系 统钩子(Systemwide hooks)。特定线程 钩子只是 监视 指定的 线程,而全局系 统钩子则可以监视 系统中所有的 线程。无论 是特定 线程钩 子, 还是全局系 统钩 子,都是通 过
2、 SetWindowsHookEx ()来设置钩子的。对于特定 线程钩子,钩子的函数既可以是包含在一个.exe 也可以是一个 .dll。但是对于一个全局系 统钩 子,钩子函数必 须包含在独立的dll 中,因此,当我们要捕捉 键盘 响应时 ,我们必须创 建一个 动态链 接 库。但是当钩子函数在得到了控制权,并对相关的事件 处理完后,如果想要 该消息得以 继续 的 传递 ,那 么则 必须调 用另一个函数: CallNextHookEx。由于系统必须对每 个消息 处理,钩子程序因此增加了处理的 负担,因此也降低了系统的性能。鉴 于这一点,在 windows ce中对钩 子程序并不支持。所以当程序完成
3、并退出时, 应当释放钩子,调用函数:UnhookWindowsHookEx。下面我 们将举一个例子(捕捉 键盘 )来 详细 的讲解钩子函数的程序设计 。I:设置 钩子设置钩子是通 过 SetWindowsHookEx ()的 API 函数 . 原形: HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 12 页 - - - - - - - -
4、 - dwThreadId) idhook: 装入 钩子的 类型 . lpfn: 钩子 进程的入口地址hMod: 应用程序的事件句柄dwThreadId: 装入 钩子的 线程 标示参数:idHook: 这个参数可以是以下值:WH_CALLWNDPROC、WH_CALLWNDPROCRET、 WH_CBT 、WH_DEBUG 、WH_FOREGROUNDIDLE、 WH_GETMESSAGE、 WH_JOURNALPLAYBACK、WH_JOURNALRECORD、 WH_KEYBOARD、 WH_KEYBOARD_LL、 WH_MOUSE 、WH_MOUSE_LL、 WH_MSGFILTER、
5、 WH_SHELL 、 WH_SYSMSGFILTER。对于这些参数,我不想一一加以解释,因为 MSDN 中有 关于他们的详细注解。我只挑 选其中的几个加以中文 说明。WH_KEYBOARD:一旦有键盘 敲打消息(键盘 的按下、键盘 的弹起),在 这个消息被放在 应用程序的消息 队列前,WINDOWS将会 调用你的 钩子函数。钩子函数可以改变和丢弃键盘敲打消息。WH_MOUSE : 每 个鼠 标 消息在被放在应用程序的消息 队列前,WINDOWS将会调用你的 钩子函数。钩子函数可以改变和丢弃鼠 标消息。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - -
6、 - - - - - 名师精心整理 - - - - - - - 第 2 页,共 12 页 - - - - - - - - - WH_GETMESSAGE: 每 次当你的 应用程序 调用一个 GetMessage()或者一个PeekMessage()为了去从 应 用程序的消息 队 列中要求一个消息时,WINDOWS都会调用你的钩子函数。而 钩子函数可以改 变和 丢弃这个消息。II:释放钩子钩子的 释放使用的是UnhookWindowsHookEx()函数原形: BOOL UnhookWindowsHookEx( HHOOK hhk ) UnhookWindowsHookEx()函数将 释放的是
7、钩 子链中函数 SetWindowsHookEx所装入的 钩子进程。hhk: 将要 释放的 钩子进程的句柄。III: 钩子 进程钩子 进程使用函数HookProc; 其实 HookProc 仅仅只是 应用程序定 义的符号。比如你可以写成 KeyBoardHook.但是参数是不变的。Win32 API提供了 诸如: CallWndProc、 GetMsgProc 、DebugProc 、 CBTProc 、 MouseProc 、 KeyboardProc、 MessageProc等函数,对于他 们的详细讲解,可以看 MSDN 我在此只 讲解一下 KeyBoardHook的含义。原形:LRESU
8、LT CALLBACK KeyBoardHook (int nCode, WPARAM wParam, LPARAM lParam) 说明: 钩子进程是一些依附在一个钩 子上的一些函数,因此钩子进程只被 WINDOWS 调用而不被应用程序 调用,他们有时就需要作 为一个回 调函数(CALLBACK )。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 12 页 - - - - - - - - - 参数 说明:nCode: 钩子代码 , 钩子 进程使用 钩子代 码去决定是否
9、执行。而钩子代码的值是依靠 钩子的种类 来定的。每种钩 子种类 都有他 们自己一系列特性的代码。比如对于 WH_KEYBOARD, 钩子代 码的参数有:HC_ACTION , HC_NOREMOVE。 HC_ACTION的意 义:参数wParam 和lParam 包含了 键盘 敲打消息的信息, HC_NOREMOVE的意 义:参数wParam 和 lParam 包含了键盘 敲打消息的信息,并且, 键盘 敲打消息一直没有从消息队列中 删除。(应用程序 调用PeekMessage函数,并且 设置 PM_NOREMOVE标志)。也就是说当 nCode 等于 HC_ACTION时, 钩子进程必 须处
10、理消息。而 为 HC_NOREMOVE时, 钩子进程必 须传递 消息给CallNextHookEx函数,而不能做 进一步的处 理,而且必 须有 CallNextHookEx函数的返回 值。wParam: 键盘 敲打所 产生的 键盘 消息,键盘 按键的虚 拟代码。lParam: 包含了消息 细节 。注意 :如果 钩子进 程中 nCode 小于零,钩子进 程必须返回(return) CallNextHookEx(nCode,wParam,lParam);而钩子进程中的 nCode 大于零,但是 钩子进程并不 处理消息,作者推荐你 调 用 CallNextHookEx并且返回 该函数的返回 值。否则
11、,如果另一个 应用程序也装入WH_KEYBOARD 钩子,那么该钩 子将不接受 钩子通知并且返回一个不正确的 值。如果钩 子进程处理了消息,它可能返回一个非零值去阻止系 统传递该 信息到其它剩下的 钩子或者 windows 进程。所以最好在 钩 子进程的最后都返回CallNextHookEx的返回值。IV:调用下一个 钩子函数名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 12 页 - - - - - - - - - 调用下一个 钩子函数 时使用 CallNexHookE
12、x函数。原形:LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam ) CallNexHookEx()函数用于 对当前 钩子链中的下一个 钩子进程传递钩 子信息,一个 钩子进程既可以在 钩子信息 处理前,也可以在 钩子信息 处理后 调用该函数。为什么使用 该函数已在iii 钩子进程中的 “ 注意 ” 中,加以了 详细 的说明。hhk: 当前 钩子的句柄nCode: 传送到 钩子 进程的 钩子代 码。wParam: 传送到 钩子进程的 值 。lParam: 传送到 钩子进程的 值。参数:hhk: 当前
13、 钩子的句柄 . 应用程序接受 这个句柄,作 为先前 调用 SetWindowsHookE函数的 结果nCode: 传送到 钩子 进程的 钩子代 码,下一个钩子进程使用 这个代 码以此决定如何 处理钩子信息wParam: 传送给钩 子进程的 wParam 参数 值 ,参数值的具体含 义与当前 钩子链的挂接的 钩子类型有 关lParam : 传送给钩 子进程的 wParam 参数 值 ,参数值的具体含 义与当前 钩子链的挂接的 钩子类型有 关名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - -
14、第 5 页,共 12 页 - - - - - - - - - 返回 值:返回值是链 中下一个 钩子进 程返回的 值,当前钩子进程必 须返回 这个值,返回值的具体含 义与挂接的 钩子类型有 关, 详细 信息 请参看具体的 钩子进程描述。V 建立一个 动态连 接库( DLL )当我 们熟悉了以上的各个函数后,现在我 们开 始编写一个 动态连 接库( DLL )。在 这儿我采用的是 WIN32 DLL, 而不是 MFC DLL 。而且以下所有的程序也都是采用C 语言去 编写。这主要是因为使用 WIN32 API 能够 更详细 、更全面的控制程序的如何执行,而使用 MFC ,一些低级的控制是不可能 实
15、现 的(当然,仅对该 程序来 说,也是可以使用MFC 的)。1:建立一个动态连 接库的.cpp 文件。比如我 们现 在建立一个名为 hookdll.cpp 的文件。在hookdll.cpp 的文件中加上如下内容:#include #include string.h #include stdio.h HINSTANCE hInst; #pragma data_seg(hookdata) HHOOK oldkeyhook=0; #pragma data_seg() #pragma comment(linker,/SECTION:hookdata,RWS) 名师资料总结 - - -精品资料欢迎下载
16、- - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 12 页 - - - - - - - - - #define DllExport extern C_declspec(dllexport) DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam ); DllExport void InstallHook(int nCode); DllExport void EndHook(void); BOOL WINAPI Dl
17、lMain(HINSTANCE hInstance,ULONG What,LPVOID NotUsed) switch(What) case DLL_PROCESS_ATTACH: hInst = hInstance; break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 12
18、页 - - - - - - - - - return 1; void InstallHook(int nCode) oldkeyhook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyBoardProc,hInst,0); DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam ) WPARAM j; FILE *fp; if(lParam&0 x80000000) j = wParam; fp=fopen(c:“ hook “ key.txt,a);
19、fprintf(fp,%4d,j); fclose(fp); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 12 页 - - - - - - - - - return CallNextHookEx(oldkeyhook,nCode,wParam,lParam); void EndHook(void) UnhookWindowsHookEx(oldkeyhook); 这个 动态连 接库的源代 码 hookdll.cpp 包含了 键盘处 理函数,设置钩子,退出钩子函数。并将
20、键盘 敲下的 键以值的格式存入到c: “hook“key.txt 文件中。以下是 对该 文件的 详细 的解 释。使用包含在DLL 的函数,必 须将其 导入。导入操作 时通过 dllimport来完成的, dllexport 和dllimport 都是 vc( visual C+ )和bc( Borland C+)所支持的扩展的关键 字。但是 dllexport 和dllimport 关键 字不能被自身所使用,因此它的前面必须有另一个 扩展关键 字_declspec。通用格式如下:_declspec(specifier) 其中 specifier 是存 储类标 示符。对于 DLL , speci
21、fier 将是 dllexport和 dllimport 。而且为 了简化说明导入和 导出函数的 语句,用一个宏名来代替_declspec.在此程序中,使用的是 DllExport 。如果用户的 DLL 被编译 成一个 C+程序,而且希望 C 程序也能使用它,就需要增加 “C”的连接 说明。#define DllExport extern C_declspec(dllexport), 这样就避免了标准 C+命名 损坏。(当然,如果 读者正在 编译 的是 C 程序,就不要加入extern “C”,因为不需要它,而且 编译器也不接受它)。有了宏定 义, 现在就可以用一个简单 的语句就可以 导出函数
22、了,比如:DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam ); DllExport void InstallHook(int nCode);DllExport void EndHook(void); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 12 页 - - - - - - - - - 第一个 #pragma 语句创造数据段, 这里命名 为 hookdata
23、。其实也可以命名 为您喜欢的任意的一个名称。#pragma 语句之后的所有初始化的变量都 进入 hookdata 段中。第二个 #pragma 语句是数据段的 结束标志。对变 量进行 专门 的初始化是很重要的,否则编译 程序将把它 们放在普通的未初始化的段中而不是放在hookdata 中。但是 链接程序必 须直到有一个 hookdata 段。我们可以在 Project Setting ( vc6.0 ) 对话 框中选择Link 选项 , 选中 HOOKDLL时在 Project Options 域(在Release 和 Debug 配置中均可),包含下面的 连接语句: /SECTION:hoo
24、kdata,RWS字母 RWS 是表明 该段具有 读、写、和共享属性。当然,您也可以直接用DLL 源代 码指定 链接程序就像HOOKDLL.c那样:#pragma comment(linker,/SECTION:hookdata,RWS)。由于有些 DLL 需要特殊的启动和终止代 码。 为此,所有的 DLL 都有一个名 为 DllMain() 的函数,当初始化或 终止 DLL 时调 用该函数。一般在 动态连结库 的资源文件中定 义此函数。不 过如果没有定 义它,则编译 器会自 动提供缺省的形式。原型 为: BOOL WINAPI DllMain(HINSTANCE hInstance,ULON
25、G What,LPVOID NotUsed) 参数:hInstance: DLL 实例句柄What:指定所 发生的操作NotUsed:保留参数其中 What 的值可以 为以下 值:DLL_PROCESS_ATTACH:进程开始使用 DLL DLL_PROCESS_DETACH: 进程正在 释放 DLL 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 12 页 - - - - - - - - - DLL_THREAD_ATTACH:进程已 创建一个新的 线程DLL_THR
26、EAD_DETACH:进程已舍弃了一个线程总的来 说,无论何时调 用 DllMain() 函数,都必 须根据 What 的内容来采取适当的动作。这种 适当的 动作可以什 么都不做,但不是返回非零值。DllMain() 接下来的便是设置 钩子,键盘处 理,和释放钩子。2:建立头文件正如 应用程序所使用的其它任何库函数一 样,程序也必须包含 dll 内的函数的原型。所有得Windows 程序都必 须包含 windows.h 的原因。所以我 们现在建立一个 头文件 hookdll.h 如下:#define DllImport externC_declspec(dllimport) DllImport
27、 void InstallHook(int nCode); DllImport LRESULT CALLBACK KeyBoardProc (int nCode,WPARAM wParam, LPARAM lParam ); DllImport void EndHook(void); 使用 dllimport 主要是 为了使代 码更高效,因此推荐使用它。但是在导入数据 时是需要 dllimport的。当完成了上面的程序后,建一个项目工程,不妨 为 hookdll ,然后将 hookdll.c 插入 导项 目工程中,编译 , 则可以生成了hookdll.dll 和 hookdll.lib 。3:
28、建立程序主文件我们 在上面作的所有得工作都是为现 在的主程序打得基础。其实当我 们完成了 Dll 文件后,剩下的就是 调用设置钩子函数:InstallHook 。如果你对 windows 编程十分的熟悉,那 么你可以名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 12 页 - - - - - - - - - 在你任何需要的时候来 调用 InstallHook 。但是在你必 须记住在你退出程序的时候你需要 调EndHook 以便 释放你所装入的钩子函数。现在我在建立了一个
29、hookspy.cpp,并将生成好的hookdll.dll 和 hookdll.lib 拷贝到从一个目 录下,并建立一个hookspy 的项目工程。将hookspy.cpp,hookdll.dll,hookdll.lib,hookdll.h插入到 项目工程中去。然后在建立windows 窗口 时就将 钩子设置,在退出程序 时退出 钩子函数。比如:case WM_CREATE: InstallHook(TRUE); break; case WM_DESTROY: /terminate the program EndHook(); PostQuitMessage(0); break; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 12 页 - - - - - - - - -