钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。这和前面我博客的窗口子类化都异曲同工,但是Hook可强大多了,我是这两天才开始看的,所以略知皮毛。

/* 钩子的原理 */

我听完孙鑫老师C++教程里的解释,觉得还是把Hook讲得比较形象,加上我自己的一些理解就觉得Hook原理不是很难。windows一直都是有自己处理各种消息的函数,Hook其实就能够做到程序员自己处理自己感兴趣的事情。这样说,假设Windows的消息就是马路上的车辆,一般情况下是Windows自己派人在检查,然后呢,Hook是拥有这个能力能在Windows自己安排的检查站之前也进行抽查,Hook根据程序员的需求可以变化,比如我就感兴趣100万以上的车(可能是走私的(*^__^*)),Hook就能在检查的时候专门找100万以上的车,至于其他不上档次的车Hook就放行,交还给Windows自己的检查站。同样Hook可以“为所欲为”,可以擅自设立一个检查站,也可以两个,三个···换成程序来说,钩子函数的工作原理是:当我们创建一个钩子时,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当一个事件发生时,如果我们安装的是一个局部钩子(下面有解释,暂时理解为你程序本身中的),我们进程中的钩子函数将被调用。

/* 钩子链表和函数 */

每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。钩子子程是一个应用程序定义的回调函数(CALLBACKFunction),不能定义成某个类的成员函数,只能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。
钩子子程必须按照以下的语法:

LRESULT CALLBACK HookProc
(
  int nCode, //指定是否需要处理该消息 
WPARAM wParam, 
LPARAM lParam  //包含该消息的附加消息 ,
);
这个回调函数的名字可以随你取,但形式可一定要满足以上要求,其实钩子的回调函数和Windows的差不多一个德行。看看钩子函数的返回值,若是返回非0值,表示我们已经自己处理了该消息,则消息就不被传递到目标窗口过程。
看看LRESULT CallNextHookEx
( HHOOK hhk;
int nCode;
WPARAM wParam;

LPARAM lParam;)这个函数把钩子信息传递给下一个钩子函数,也就是可以理解成把车辆放行到下一个检查站,这个可以根据自己的需要进行调用。若是我们只设定了一个钩子函数,那么我们假设把钩子消息用CallNextHookEx传给下个钩子函数,因为不存在所以就传递回了目标窗口函数。

/* 钩子的安装和释放 */

调用SetWindowHookEx函数,该函数的原型如下:
HHOOK SetWindowsHookEx( int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId );返回值是一个hook的句柄。
idHook是我们感兴趣的消息类型,比如我们对鼠标消息感兴趣就是WH_MOUSE,再者比如键盘消息WH_KEYBOARD,我们可以通过查找Win32 API使用手册来找到自己感兴趣的消息。
第二个参数是钩子函数的地址,这里就有两种情况:其实钩子有两种,一种是局部钩子,这种钩子只能关注自己所在的进程的事件,另一种钩子叫做远程钩子,这里又有两种:1.基于线程的它将捕获其它进程中某一特定线程的事件。简言之,就是可以用来观察其它进程中的某一特定线程将发生的事件。2.系统范围的 将捕捉系统中所有进程将发生的事件消息。 看上去局部钩子的功能没有远程钩子的给力,但是凡事都是要付出代价的,远程钩子会影响系统的性能,特别是监视系统范围的钩子,因为要监视系统范围的消息,明显就会影响系统的速度。
第三个参数和第四个参数相关,所以一起解释。
如果第四个参数是NULL,则说明是全局钩子,那么就是钩子子程与所有的线程关联,此时第三个参数是程序实例句柄;
如果第三个参数是NULL,则说明钩子是局部钩子,说明子程代码位于当前进程,这时候第四个参数就是当前进程的ID,可以用GetCurrentThreadID()填充,或者可以保存实例来填充,再做介绍···
再看看钩子函数的卸载,用UnHookWindowsHookEx(HHOOK hhk);参数就是SetWindowsHookEx返回的句柄。

下面是是一个小程序,大概的功能就是实现在所在进程内的鼠标消息和键盘消息的截获,一旦点击了“LockMouse”那么就在目标窗口截获了所以鼠标的消息,这里实现的是屏蔽鼠标消息,只能通过按回车键恢复鼠标功能。若是点击了“LockKeyBoard”按钮,那么只能在编辑框输入0或者1,但是在没有点击的情况下是正常的编辑框。这点可是比窗口子类化更加简单。

  1. #include "Windows.h"
  2. #include "tchar.h"
  3. #include "resource.h"
  4. HINSTANCE g_hInstance ;
  5. static HHOOK hHook = NULL;
  6. INT_PTR CALLBACK ProcWinMain(HWND hWnd, UINT Msg, WPARAM wParam ,LPARAM lParam);
  7. LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam,LPARAM lParam);
  8. LRESULT CALLBACK BoardProc(int nCode, WPARAM wParam,LPARAM lParam);
  9. int WINAPI WinMain(     HINSTANCE hInstance,
  10. HINSTANCE hPrevInstance,
  11. LPSTR lpCmdLine,
  12. int nCmdShow
  13. )
  14. {
  15. static TCHAR DlgName[] = _T("InnerHook");
  16. g_hInstance = hInstance ;
  17. DialogBoxParam(hInstance,DlgName,NULL,( DLGPROC)ProcWinMain,NULL);
  18. return 0;
  19. }
  20. INT_PTR CALLBACK ProcWinMain(   HWND hWnd,
  21. UINT Msg,
  22. WPARAM wParam,
  23. LPARAM lParam
  24. )
  25. {
  26. static TCHAR unLockStr[] = _T("Unlocking");
  27. static TCHAR LockStr[] = _T("Locking");
  28. static BOOL isLock = FALSE;
  29. static BOOL isLock2 = FALSE;
  30. static HHOOK hHook2 = NULL;
  31. switch(Msg)
  32. {
  33. case WM_INITDIALOG:
  34. {
  35. SetFocus(GetDlgItem(hWnd,IDC_EDITTEXT));
  36. }
  37. break;
  38. case WM_CLOSE:
  39. EndDialog(hWnd,NULL);
  40. break;
  41. case WM_COMMAND:
  42. {
  43. switch(LOWORD(wParam))
  44. {
  45. case ID_BTNHOOKBOARD :
  46. {
  47. if(isLock == FALSE)
  48. {
  49. hHook = SetWindowsHookEx(WH_KEYBOARD,BoardProc,NULL,GetCurrentThreadId());
  50. SetDlgItemText(hWnd,ID_BTNHOOKBOARD,LockStr);
  51. isLock = TRUE;
  52. }
  53. else
  54. {
  55. SetDlgItemText(hWnd,ID_BTNHOOKBOARD,unLockStr);
  56. isLock = FALSE;
  57. UnhookWindowsHookEx(hHook);
  58. }
  59. }
  60. break;
  61. case ID_BTNHOOKMOUSE :
  62. {
  63. if(isLock2 == FALSE)
  64. {
  65. hHook2 = SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
  66. SetDlgItemText(hWnd,ID_BTNHOOKMOUSE,LockStr);
  67. isLock2 = TRUE;
  68. }
  69. else
  70. {
  71. SetDlgItemText(hWnd,ID_BTNHOOKMOUSE,unLockStr);
  72. isLock2 = FALSE;
  73. UnhookWindowsHookEx(hHook2);
  74. }
  75. }
  76. break;
  77. }
  78. }
  79. break;
  80. default:
  81. return FALSE;
  82. }
  83. return TRUE;
  84. }
  85. LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam,LPARAM lParam)
  86. {
  87. return 1;           //返回非0值,表示处理了该消息
  88. }
  89. LRESULT CALLBACK BoardProc(int nCode, WPARAM wParam,LPARAM lParam)
  90. {
  91. if (wParam == VK_RETURN || wParam == '1' || wParam == '0')
  92. {
  93. return CallNextHookEx(hHook,nCode,wParam,lParam);   //表示不处理该消息,交还给Windows自己处理
  94. }
  95. else
  96. return 1;       //表示已经处理了该消息
  97. }

参考资料

http://www.microsoft.com/china/community/program/originalarticles/techdoc/hook.mspx

《Windows+sdk系列文章》

Hook技术简介(有用SDK写的例子)的更多相关文章

  1. Java Servlet 技术简介

    Java Servlet 技术简介 Java 开发人员兼培训师 Roy Miller 将我们现有的 servlet 介绍资料修改成了这篇易于学习的实用教程.Roy 将介绍并解释 servlet 是什么 ...

  2. 20145307陈俊达_安卓逆向分析_Xposed的hook技术研究

    20145307陈俊达_安卓逆向分析_Xposed的hook技术研究 引言 其实这份我早就想写了,xposed这个东西我在安卓SDK 4.4.4的时候就在玩了,root后安装架构,起初是为了实现一些屌 ...

  3. 程序破解之 API HOOK技术 z

    API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socke ...

  4. ar技术序章-SDK介绍和选择

    转自: http://blog.csdn.net/kun1234567/article/details/10402535 ar技术序章-SDK介绍和选择 分类: Augmented Reality20 ...

  5. HTC VIVE SDK 中的例子 hellovr_opengl 程序流程分析

    最近Vive的VR头盔设备很火,恰逢项目需求,所以对 SDK 中的例子 hellovr_opengl 做了比较细致的代码分析,先将流程图绘制如下,便于大家理解. 在ViVe头盔中实现立体效果的技术核心 ...

  6. HOOK技术的一些简单总结

    好久没写博客了, 一个月一篇还是要尽量保证,今天谈下Hook技术. 在Window平台上开发任何稍微底层一点的东西,基本上都是Hook满天飞, 普通应用程序如此,安全软件更是如此, 这里简单记录一些常 ...

  7. Hook技术

    hook钩子: 使用技术手段在运行时动态的将额外代码依附现进程,从而实现替换现有处理逻辑或插入额外功能的目的. 它的技术实现要点有两个: 1)如何注入代码(如何将额外代码依附于现有代码中). 2)如何 ...

  8. 【转】Android 防破解技术简介

    http://www.cnblogs.com/likeandroid/p/4888808.html Android 防破解技术简介 这几年随着互联网的不断发展,Android App 也越来越多!但是 ...

  9. 【Hook技术】实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展

    [Hook技术]实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展 公司有个监控程序涉及到进程的保护问题,需要避免用户通过任务管理器结束掉监控进程,这里使用 ...

随机推荐

  1. 嵌入式 Linux应用程序如何读取(修改)芯片寄存器的值

    这一问题来自项目中一个实际的需求:我需要在Linux启动之后,确认我指定的芯片寄存器是否与我在uboot的配置一致. 举个例子:寄存器地址:0x20000010负责对DDR2的时序配置,该寄存器是在u ...

  2. 基于Linux系统WINE虚拟机技术的研究

    650) this.width=650;" onclick="window.open("http://blog.51cto.com/viewpic.php?refimg= ...

  3. GetListToJson

    List<Models.ArticleModel> list = GetList(page);    return Newtonsoft.Json.JsonConvert.Serializ ...

  4. C++编码优化之减少冗余拷贝或赋值

    临时变量 目前遇到的一些产生临时变量的情况:函数实参.函数返回值.隐式类型转换.多余的拷贝 1. 函数实参 这点应该比较容易理解,函数参数,如果是实参传递的话,函数体里的修改并不会影响调用时传入的参数 ...

  5. TabControl里面添加From

    private void dynamicDll() { string dllName = "dll"; Assembly ass = Assembly.Load(dllName); ...

  6. 洛谷 P1808 单词分类_NOI导刊2011提高(01)

    P1808 单词分类_NOI导刊2011提高(01) 题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且仅当 ...

  7. 位数(digits)的处理

    主要针对:二进制表示法,以及十进制表示法: 1. 获取位数 已知该数 n 采用十进制进行表示 二进制形式的位数:⌊log2n⌋+1 十进制形式的位数:⌊log10n⌋+1 2. 截断(保留前/后 m ...

  8. vue使用(二)

    本节目标:           1.数据路径的三种方式          2.{{}}和v-html的区别 1.绑定图片的路径 方法一:直接写路径 <img src="http://p ...

  9. 关于python的深浅拷贝、赋值

    https://blog.csdn.net/weixin_39750084/article/details/81435454

  10. Flask项目之手机端租房网站的实战开发(二)

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...