Hook技术简介

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

参考资料 

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

《Windows+sdk系列文章》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Hook是React 16.8版本引入的一种新的特性,它可以让你在无需编写类组件的情况下使用状态和其他React特性。TypeScript是一种静态类型检查的JavaScript超集,可以帮助我们在开发过程中发现并修复潜在的错误。 要深入学习React Hook和TypeScript技术栈,你可以按照以下步骤进行: 1. 学习React基础知识:在学习React Hook之前,确保你对React的基础知识有一定的了解。理解React组件、生命周期、状态管理等概念是很重要的。 2. 学习TypeScript基础知识:如果你还不熟悉TypeScript,可以先学习一些基础知识,比如类型注解、接口、泛型等。掌握这些概念可以帮助你更好地使用TypeScript进行开发。 3. 学习React Hook:阅读React官方文档中关于React Hook的内容,并尝试编写一些简单的Hook。掌握useState、useEffect、useContext等常用的Hook函数,并理解它们的使用方法和原理。 4. 使用TypeScript编写React Hook:在掌握了React Hook的基本知识后,你可以开始使用TypeScript编写React Hook。使用TypeScript可以为你的代码提供类型检查和智能提示,减少潜在的错误。 5. 实践项目:选择一个小型的项目或者练习,使用React Hook和TypeScript进行开发。通过实践项目可以帮助你更好地理解和掌握这两个技术栈。 6. 深入学习进阶内容:一旦你对React Hook和TypeScript有了基本的了解,你可以进一步学习一些进阶内容,比如自定义Hook、使用第三方库、使用Context API等。 记住,深入学习任何技术栈都需要时间和实践。通过不断地阅读文档、编写代码和解决问题,你会逐渐掌握React Hook和TypeScript技术栈。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值