一、什么是HOOK?
  "hook"这个单词的意思是“钩子”,"Windows Hook"是Windows消息处理机制的一个重要扩展,程序猿能够通过它来钩住(截获)感兴趣的消息,并用事先编好的一个函数(钩子过程)来处理这些消息!当然,这个处理是在消息到达目标窗体之前进行的。
  钩子过程(hook procedure)实际上是一个用来处理消息的函数,通过系统调用,程序猿能够把它挂入系统或进程的钩子链中,让它成为一个钩子。每当系统中产生特定的消息时,钩子就能在第一时间钩住(截获)它,也就是说钩子过程优先得到消息的控制权。这时钩子过程即能够加工、处理该消息,又能够不作不论什么改变而继续传递该消息,还能够强制结束这个消息的传递。
 
二、HOOK的实现原理
  每一个Hook都挂在一个与之关联的链表上,这个链表由系统负责维护,称为钩子链表或钩子链。每当系统有消息产生时,这个消息都会依次流经钩子链上的每一个钩子,当遇有同样类型的钩子时,这个消息就会被钩住(截获),随后钩子会将这个消息交给自己的钩子过程进行处理。一些钩子过程能够只监视消息,或者改动消息,或者终止消息的传递,以避免这些消息传递到下一个钩子过程或目标窗体过程。注意,最晚安装的钩子位于钩子链的前端,而最早安装的钩子位于钩子链的末端,即最后安装的钩子总是最先得到消息通知的。
  Windows并不要求钩子的卸载顺序一定要和安装顺序相反。每当有一个钩子被卸载,Windows便释放其占用的内存,并更新整个钩子链。假设应用程序安装了钩子,可是在尚未卸载钩子之前就结束了,那么系统会自己主动为它做卸载钩子的操作。
  钩子过程是一个应用程序定义的回调函数(Callback Function),不能定义成某个类的成员函数,仅仅能定义成普通的C函数。用以监视消息的钩子,既能够是跟某一特定线程相关的(进程内钩子),也能够是跟系统中全部线程相关的(全局钩子)。
 
三、进程内钩子和全局钩子
  SetWindowsHookEx()函数的最后一个參数决定了此钩子是进程内钩子还是全局钩子。

  进程内钩子用于监视指定线程的事件消息。它的钩子过程一般位于当前线程或当前线程创建的线程中。

  全局钩子监视系统中全部线程的消息。由于全局钩子会影响系统中全部的应用程序,所以钩子过程必须放在独立的动态链接库(DLL) 中。系统会自己主动将这个含有钩子过程(实质上是回调函数)的DLL映射到受钩子过程影响的全部进程的地址空间中,也就是将这个DLL注入全部进程。

  几点说明:

  1. 假设对于同一消息(如鼠标消息)既安装了进程内钩子又安装了全局钩子,那么系统会优先调用进程内钩子,然后调用全局钩子。

  2. 对于同一消息而言,能够安装多个钩子,消息被当前钩子的钩子过程处理完成后应该把这个消息继续传递给下一个钩子。

  3. 钩子特别是全局钩子会减少消息处理效率,影响系统性能,因此仅仅有在必要的时候才安装钩子,在使用完成后应及时卸载。
 
四、HOOK编程中的经常使用函数
HHOOK SetWindowsHookEx(
int idHook, // type of hook to install
HOOKPROC lpfn, // address of hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // identity of thread to install hook for
);
HHOOK SetWindowsHookEx(
int idHook, // type of hook to install
HOOKPROC lpfn, // address of hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // identity of thread to install hook for
);
简单说明:
  SetWindowsHookEx()函数用来在系统中安装钩子;
  idHook參数指定了所安装的钩子类型,即这个钩子将对哪种消息感兴趣。它的值是系统事先定义好的一些宏(详细參见MSDN),比方用户想要安装一个用来截获键盘消息的钩子,那么他应该将这个參数设置为WH_KEYBOARD,又如用户想要安装一个用来截获鼠标消息的钩子,那么他应该将这个參数设置为WH_MOUSE;
  lpfn參数是一个指向钩子过程的指针,依据hMod參数的不同,这个指针既可能指向一个DLL空间,也可能指向当前进程的代码空间。对于刚開始学习的人而言,能够暂且把它理解成钩子过程的函数名;
  hMod參数用来指定一个DLL句柄,而这个DLL包括着lpfn參数所指向的钩子过程。当然,这个參数与dwThreadId的设置有关,假设该參数被设置为0,那么这个钩子将会是一个全局钩子,如此hMod參数必定要发挥其作用,但反之则必须将hMod设置为NULL;
  dwThreadId參数用来指定一个与钩子过程相关的线程ID,但假设这个參数被设置为0,那么这个钩子将与全部线程相关,即作为一个全局钩子。其实,我们能够通过这个參数来确定生成一个进程内钩子还是一个全局钩子,从而为设置其它參数提供根据;
  最后,假设这个函数运行成功,它将返回被生成钩子的句柄,假设运行失败它将返回NULL,用户能够通过调用GetLastError()函数获知详情。

BOOL UnhookWindowsHookEx(
HHOOK hhk // handle to hook procedure to remove
);

简单说明:

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

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

  最后,假设这个函数运行成功会返回非零值,假设运行失败会返回零值,用户能够通过调用GetLastError()函数获知详情。

<未完待续>

五、HOOK编程实例
1.新建一个基于对话框的project"InnerHook",此project的钩子是仅仅拦截当前进程的。

2.在OnInitDialog()中加入代码:
g_hWnd = m_hWnd;
g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, GetCurrentThreadId()); //设置了鼠标钩子
g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, GetCurrentThreadId()); //设置了键盘钩子
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.新建一个DLLproject名为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.新建一个project调用此钩子函数。project名为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++深入具体解释》

參考资料:

我的学习笔记_Windows_HOOK计划 2009-12-03 11:19的更多相关文章

  1. 《python基础教程(第二版)》学习笔记 文件和素材(第11章)

    <python基础教程(第二版)>学习笔记 文件和素材(第11章) 打开文件:open(filename[,mode[,buffering]]) mode是读写文件的模式f=open(r' ...

  2. [原创]java WEB学习笔记38:EL 中的 11个 隐含对象 详解

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

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

    一.什么是HOOK? "hook"这个单词的意思是"钩子","Windows Hook"是Windows消息处理机制的一个重要扩展,程序猿能 ...

  4. 前端学习笔记系列一:12 js中获取时间new date()的用法

    获取时间: 1  var myDate = new Date();//获取系统当前时间 获取特定格式的时间: 1 myDate.getYear(); //获取当前年份(2位) 2 myDate.get ...

  5. shell脚本调试 分类: 学习笔记 linux ubuntu 2015-07-14 12:49 53人阅读 评论(0) 收藏

    1.sh -x script 这将执行脚本并显示所有变量的值 如,脚本: #!/bin/bash #a test about shift if [ $# -le 0 ] then echo " ...

  6. 再起航,我的学习笔记之JavaScript设计模式12(适配器模式)

    适配器模式 适配器模式(Adapter): 将一个类(对象)的接口(方法或属性)转化成为另外一个接口,使类(对象)之间接口的不兼容问题通过适配器得以解决. 适配相似的框架 不知道大家有没有遇到过这种场 ...

  7. ThinkPHP - 4 - 学习笔记(2015.4.12)

    ThinkPHP D方法 D方法用于实例化自定义模型类,是ThinkPHP框架对Model类实例化的一种封装,并实现了单例模式,支持跨项目和分组调用,调用格式如下:D('[项目://][分组/]模型' ...

  8. MALL的学习笔记启动计划

    基本网络文档:http://www.macrozheng.com/#/ 电子书: Spring: <Spring实战(第4版)> Springboot: <Spring Boot实战 ...

  9. iOS 学习笔记 十 (2015.04.03)xcode第三方插件

    1.xcode第三方插件,存放路径:~/Library/Application Support/Developer/Shared/Xcode/Plug-ins

随机推荐

  1. [置顶] 简单解析linux下进程通信方法

    linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

  2. IDFA的值什么时候会发生改变

    在何种情况下 , 应用的IDFA值会发生改变? 近期工作中须要获得一个能够唯一地标示每个不同应用的ID,之前的苹果UDID已经不让使用了. 那么我们须要使用新的IDFA来引用.可是在某些情况下这个ID ...

  3. MongoDB查询命令具体解释

    1.查询全部记录 复制代码代码例如以下: db.userInfo.find(); 相当于:select* from userInfo; 默认每页显示20条记录,当显示不下的情况下,能够用it迭代命令查 ...

  4. Android开发之style属性和提前定义样式

    摘要 Android平台定义的主题样式: android:theme="@android:style/Theme.Dialog" // 将一个Activity显示为对话框模式and ...

  5. Windows平台Go调用DLL的坑(居然有这么多没听过的名词)

    最近的项目中,使用了GO来开发一些服务中转程序.业务比较简单,但是有一些业务需要复用原有C++开发的代码.而在WINDOWS,用CGO方式来集成C/C++代码并不是太方便.所以用DLL把C++的代码封 ...

  6. MySQL触发器 trigger之for each row

    for each row 每行受影响,触发器都运行.叫行级触发器. oracle 触发器中分行级触发器和语句级触发器,可不写for each row,不管影响多少行都仅仅运行一次. mysql不支持语 ...

  7. hdu 4739【位运算】.cpp

    题意: 给出n个地雷所在位置,正好能够组成正方形的地雷就可以拿走..为了简化题目,只考虑平行于横轴的正方形.. 问最多可以拿走多少个正方形.. 思路: 先找出可以组成正方形的地雷组合cnt个.. 然后 ...

  8. Notifications(通知)

    通知 通知是能在应用的普通用户界面外显示给用户的一种消息. 当你告诉系统公布一条通知时,它首先在通知栏中表现为一枚图标. 用户打开通知抽屉后就能查看通知的细节了. 通知栏和通知抽屉都是由系统控制的区域 ...

  9. SE 2014年5月22日

    一.   用自己的理解描述 tunnel接口状态 up和down的情况都有哪些 Tunnel接口的状态UP:隧道的目标有可达路由. Tunnel接口的状态Down:隧道的目标路由不可达. 如图配置实验 ...

  10. SE 2014年5月5日

    如图配置 某企业网络规划图(三台交换设备/三台路由设备) 接入层 SW1 连接终端用户 汇聚层 SW2 SW3 核心层 R1 R2 R5 1. 如图 SW1 SW2 SW3 物理链路两两相连接,网络中 ...