MFC中的HOOK编程

HOOK,n.钩, 吊钩,通常称钩子。


在计算机中,是Windows消息处理机制的一个平台,应用程序能够在上面设置子程以监视指定窗体的某种消息,并且所监视的窗体能够是其它进程所创建的。当消息到达后,在目标窗体处理函数之前处理它。钩子机制同意应用程序截获处理window消息或特定事件。
      钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗体前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即能够加工处理(改变)该消息,也能够不作处理而继续传递该消息,还能够强制结束消息的传递。


Hook原理
      每个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程能够仅仅监视消息,或者改动消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗体。近期安装的钩子放在链的開始,而最早安装的钩子放在最后,也就是后增加的先获得控制权。
      Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个Hook链表。假设程序安装了钩子,可是在尚未卸载钩子之前就结束了,那么系统会自己主动为它做卸载钩子的操作。
  钩子子程是一个应用程序定义的回调函数(CALLBACK Function),不能定义成某个类的成员函数,仅仅能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件能够是与某一特定线程关联的,也能够是系统中全部线程的事件。
  系统钩子与线程钩子
      SetWindowsHookEx()函数的最后一个參数决定了此钩子是系统钩子还是线程钩子。
      线程勾子用于监视指定线程的事件消息。线程勾子一般在当前线程或者当前线程派生的线程内。
      系统勾子监视系统中的全部线程的事件消息。由于系统勾子会影响系统中全部的应用程序,所以勾子函数必须放在独立的动态链接库(DLL) 中。系统自己主动将包括“钩子回调函数”的DLL映射到受钩子函数影响的全部进程的地址空间中,即将这个DLL注入了那些进程。


//MSDN

HHOOK SetWindowsHookEx(
int
idHook, // hook type
HOOKPROC lpfn, // hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // thread identifier
);
当中第四个參数:

dwThreadId
[in] Specifies the identifier of the thread with which the hook procedure is to be associated.
If this parameter is zero, the hook procedure is associated with all existing threads running
in the same desktop as the calling thread.

//For example


DLL中设置HOOK


void SetHook(HWND hwnd)
{
 g_hWnd=hwnd;//这样的传递调用它的进程的句柄的方法非常巧妙
 g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);//第四个參数为0,表示此钩子关系当前桌面的全部进程,系统自己主动将包括“钩子回调函数”的DLL映射到受钩子函数影响的全部进程的地址空间中,即将这个DLL注入了那些进程。
 g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("Hook"),0);
}


HOOK的应用:
  观察模式
  最为常常使用,像Windows提供的SetWindowHook就是典型地为这类应用准备的。并且这也是最普遍的使用方法。
  这个模式的特点是,在事情发生的时候,发出一个通知信息。观察者仅仅能够查看过程中的信息,依据自己关心的内容处理自己的业务,可是不能够更改原来的流程。
  如全局钩子中,常常使用的鼠标消息、键盘消息的监视等应用。金山词霸屏幕取词的功能是一个典型的应用(详细技术能够參考此类文章)。
  注入模式
  这个模式和观察模式最大的不一样的地方在于,注入的代码是为了扩展原始代码的功能业务。插件模式是此类模式的典型案例。
  无论瘦核心的插件系统(如Eclipse)还是胖核心的插件系统(如Delphi、Visual Studio等IDE环境),其对外提供的插件接口都是为了扩展本身系统的功能的。
  这样的扩展的应用方式的典型特点,就是新的扩展代码和原来的代码会协调处理同类业务。
  替换模式
  假设针相应用目的不同,能够叫修复模式或破解模式。前者是为了改动系统中的BUG,后者是为了破解原有系统的限制。
  非常多黑客使用此种模式,将訪问加密锁的DLL中的导出表,替换成自己的函数,这样跳过对软件的控制代码。这类应用的难点是,找出函数的參数。
  这类模式的特点是,原有的代码会被新的代码所替换。
  前面三个是基本模式,还有非常多和实际应用相关的模式。
  集权模式
  此类模式的出现,大都是为了在全部系统中,统一处理某类事情。它的特点不在于注入的方式,而在于处理的模式。
  这个模式,大都应用到某类服务上,比方键盘服务,鼠标服务,打印机服务等等特定服务上。通过统一接管此类服务的訪问,限制或者协调对服务的訪问。
  比方键盘锁功能的实现,就是临时关闭键盘的全部应用。
  这类模式的特点主要会和特点服务有关联。
  修复模式
  替换模式的一种,这里强调的是其应用的目的是为了修复或扩展原有系统的功能。
  破解模式
  替换模式的一种,这里强调的是其应用的目的是为了跳过原有系统的一部分代码。如加密检測代码,网络检測代码等等。
  插件模式
  注入模式的一种,在系统的内部直接依靠HOOK机制进行扩展业务功能。
  共享模式
  这类应用中,常常是为了获取对方的数据。必定我希望获取对方系统中,全部字符串的值。能够通过替换对方的内存管理器,导出全部字符串。
  这个应用比較特殊。只是其特点在于,目的是达到系统之间的数据共享。
  事实上现,可能是观察模式,也可能是替换模式。

上一篇:C#程序集系列10,强名称程序集


下一篇:iOS 字符串删除 DOM