我的学习笔记_Windows_HOOK编程 2009-12-03 11:19

一、什么是HOOK?
  "hook"这个单词的意思是“钩子”,"Windows Hook"是Windows消息处理机制的一个重要扩展,程序员可以通过它来钩住(截获)感兴趣的消息,并用事先编好的一个函数(钩子过程)来处理这些消息!当然,这个处理是在消息到达目标窗口之前进行的。
  钩子过程(hook procedure)实际上是一个用来处理消息的函数,通过系统调用,程序员可以把它挂入系统或进程的钩子链中,让它成为一个钩子。每当系统中产生特定的消息时,钩子就能在第一时间钩住(截获)它,也就是说钩子过程优先得到消息的控制权。这时钩子过程即可以加工、处理该消息,又可以不作任何改变而继续传递该消息,还可以强制结束这个消息的传递。
 
二、HOOK的实现原理
  每个Hook都挂在一个与之关联的链表上,这个链表由系统负责维护,称为钩子链表或钩子链。每当系统有消息产生时,这个消息都会依次流经钩子链上的每个钩子,当遇有相同类型的钩子时,这个消息就会被钩住(截获),随后钩子会将这个消息交给自己的钩子过程进行处理。一些钩子过程可以仅仅监视消息,或者修改消息,或者终止消息的传递,以避免这些消息传递到下一个钩子过程或目标窗口过程。注意,最晚安装的钩子位于钩子链的前端,而最早安装的钩子位于钩子链的末端,即最后安装的钩子总是最先得到消息通知的。
  Windows并不要求钩子的卸载顺序一定要和安装顺序相反。每当有一个钩子被卸载,Windows便释放其占用的内存,并更新整个钩子链。如果应用程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的操作。
  钩子过程是一个应用程序定义的回调函数(Callback Function),不能定义成某个类的成员函数,只能定义成普通的C函数。用以监视消息的钩子,既可以是跟某一特定线程相关的(进程内钩子),也可以是跟系统中所有线程相关的(全局钩子)。
 
三、进程内钩子和全局钩子
  SetWindowsHookEx()函数的最后一个参数决定了此钩子是进程内钩子还是全局钩子。
  进程内钩子用于监视指定线程的事件消息。它的钩子过程一般位于当前线程或当前线程创建的线程中。
  全局钩子监视系统中所有线程的消息。因为全局钩子会影响系统中所有的应用程序,所以钩子过程必须放在独立的动态链接库(DLL) 中。系统会自动将这个含有钩子过程(实质上是回调函数)的DLL映射到受钩子过程影响的所有进程的地址空间中,也就是将这个DLL注入所有进程。
  几点说明:
  1. 如果对于同一消息(如鼠标消息)既安装了进程内钩子又安装了全局钩子,那么系统会优先调用进程内钩子,然后调用全局钩子。
  2. 对于同一消息而言,可以安装多个钩子,消息被当前钩子的钩子过程处理完毕后应该把这个消息继续传递给下一个钩子。
  3. 钩子特别是全局钩子会降低消息处理效率,影响系统性能,因此只有在必要的时候才安装钩子,在使用完毕后应及时卸载。
 
四、HOOK编程中的常用函数
简单说明:
  SetWindowsHookEx()函数用来在系统中安装钩子;
  idHook参数指定了所安装的钩子类型,即这个钩子将对哪种消息感兴趣。它的值是系统事先定义好的一些宏(具体参见MSDN),比如用户想要安装一个用来截获键盘消息的钩子,那么他应该将这个参数设置为WH_KEYBOARD,又如用户想要安装一个用来截获鼠标消息的钩子,那么他应该将这个参数设置为WH_MOUSE;
  lpfn参数是一个指向钩子过程的指针,根据hMod参数的不同,这个指针既可能指向一个DLL空间,也可能指向当前进程的代码空间。对于初学者而言,可以暂且把它理解成钩子过程的函数名;
  hMod参数用来指定一个DLL句柄,而这个DLL包含着lpfn参数所指向的钩子过程。当然,这个参数与dwThreadId的设置有关,如果该参数被设置为0,那么这个钩子将会是一个全局钩子,如此hMod参数必然要发挥其作用,但反之则必须将hMod设置为NULL;
  dwThreadId参数用来指定一个与钩子过程相关的线程ID,但如果这个参数被设置为0,那么这个钩子将与所有线程相关,即作为一个全局钩子。事实上,我们可以通过这个参数来确定生成一个进程内钩子还是一个全局钩子,从而为设置其他参数提供依据;
  最后,如果这个函数执行成功,它将返回被生成钩子的句柄,如果执行失败它将返回NULL,用户可以通过调用GetLastError()函数获知详情。

 

简单说明:

  UnhookWindowsHookEx()函数用于从系统中卸载钩子;

  hhk参数是要被卸载的钩子的句柄,也就是SetWindowsHookEx()的返回值;

  最后,如果这个函数执行成功会返回非零值,如果执行失败会返回零值,用户可以通过调用GetLastError()函数获知详情。

 

<未完待续>

五、HOOK编程实例
1.新建一个基于对话框的工程"InnerHook",此工程的钩子是只拦截当前进程的。
2.在OnInitDialog()中添加代码:
3.完成钩子函数的编写:
HHOOK g_hKeyboard=NULL;
HHOOK g_hMouse;
HWND g_hWnd=NULL;
LRESULT CALLBACK MouseProc(
   int nCode,      // hook code
   WPARAM wParam,  // message identifier
   LPARAM lParam   // mouse coordinates
)
{
  return 1;
}
 
LRESULT CALLBACK KeyboardProc(
   int code,       // hook code
   WPARAM wParam,  // virtual-key code
   LPARAM lParam   // keystroke-message information
)
{
  //if(VK_SPACE==wParam || VK_RETURN==wParam)如果是空格键
  /*if(VK_F4==wParam && (1==(lParam>>29 & 1)))拦截ALT+F4按键!
   return 1;
  else
   return CallNextHookEx(g_hKeyboard,code,wParam,lParam);*/
  if(VK_F2==wParam)按F2时程序可以退出,这是留的后门。否则程序无法关闭,只能用任务管理器来关闭它了。
  {
   ::SendMessage(g_hWnd,WM_CLOSE,0,0);
   UnhookWindowsHookEx(g_hKeyboard);当程序退出时最好将钩子移除。
   UnhookWindowsHookEx(g_hMouse);
  }
  return 1;
}
3.编写一个屏屏蔽所有进程和所有线程的钩子程序。耸闭飧龉匙颖匦氚沧霸贒LL中,然后被某个程序调用才行。
  1.新建一个DLL工程名为Hook
  2.增加Hook.cpp
  3.代码如下:
#include <windows.h>包含头文件
 
HHOOK g_hMouse=NULL;
HHOOK g_hKeyboard=NULL;
 
#pragma data_seg("MySec")新建了一个节,用于将下 面的这个变量设为全局共享。
HWND g_hWnd=NULL;这个变量是全局共享的。
#pragma data_seg()
 
//#pragma comment(linker,"/section:MySec,RWS")
/*HINSTANCE g_hInst;
 
BOOL WINAPI DllMain(
   HINSTANCE hinstDLL,  // handle to the DLL module
   DWORD fdwReason,     // reason for calling function
   LPVOID lpvReserved   // reserved
)
{
  g_hInst=hinstDLL;
}*/
 
LRESULT CALLBACK MouseProc(
   int nCode,      // hook code
   WPARAM wParam,  // message identifier
   LPARAM lParam   // mouse coordinates
)
{
  return 1;拦截了鼠标消息。
}
 
LRESULT CALLBACK KeyboardProc(
   int code,       // hook code
   WPARAM wParam,  // virtual-key code
   LPARAM lParam   // keystroke-message information
)
{
  if(VK_F2==wParam)如果是F2键,则退出。
  {
   SendMessage(g_hWnd,WM_CLOSE,0,0);
   UnhookWindowsHookEx(g_hMouse);当退出时将钩子卸掉。
   UnhookWindowsHookEx(g_hKeyboard);
  }
  return 1;
}
 
void SetHook(HWND hwnd)此函数设置了钩子。
{
  g_hWnd=hwnd;注意这种传递调用它的进程的句柄的方法,比较巧妙!
  g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);
  g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("Hook"),0);
}
 
Hook.DEF的代码如下:
LIBRARY Hook
EXPORTS
SetHook  @2
SEGMENTS
MySec READ WRITE SHARED  也可以设置节的属性。
    4.新建一个工程调用此钩子函数。工程名为HookTest,基于对话框的。在OnInitDialog()中调用SetHook(),要事先声明_declspec(dllimport) void SetHook(HWND hwnd);
      然后在Project->Setting->Link->加入../Hook/Debug/Hook.lib,并将Hook.Dll拷贝到当前目录。
int cxScreen,cyScreen;
cxScreen=GetSystemMetrics(SM_CXSCREEN);
cyScreen=GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);将窗口保持在最前面。
SetHook(m_hWnd);
    5.DLL的调试方法,设置断点,然后运行时断点时,step into即可。

<未完待续>

参考书籍:
孙鑫《VC++深入详解》

参考资料:

 


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值