钩子(Hook)

1、基本概念web

    钩子(Hook)Windows消息处理机制的一个平台,能够在应用程序上面设置本身的消 息回调函数以监视指定窗口的某种消息,并且所监视的窗口能够是其余进程所建立的。ide

    当消息到达后,在目标窗口处理函数以前处理它。函数

    钩子机制容许应用程序截获(且或)处理window消息或特定事件。spa

    钩子其实是一个处理消息的程序段,经过系统调用,把它挂入系统。每当特定的消息发出, 在没有到达目的窗口前,钩子程序就先捕获该消息,即钩子函数先获得控制权。这时钩子函数便可以加工处理(改变)该消息,也可 以不做处理而继续传递该消息,还能够强制结束消息的传递操作系统

2、运行机制线程

    1、钩子链表和钩子回调函数:指针

    每个Hook都 有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。orm

    这个列表的每个节点中都有一个指针指向指定的,自定义的被系统回调的消息处理函数,也 就是该种类型钩子的各个处理函数。xml

    当与指定的类型钩子有关联的消息发生时,系统就把这个消息传递到钩子消息处理函数。对象

    最后安装的钩子放在链表的开始,而最早安装的钩子放在最后,也就是后加入的先得到控制 权。

    Windows 并不要求钩子消息处理函数的卸载顺序必定得和安装顺序相 反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个钩子链表。若是程序安装了钩子,可是在还没有卸载钩子以前就结束了,那么系统会自动为它作卸载钩子的操做。

    钩子消息处理函数是一个自定义的回调函数(CALLBACK Function)不能定义成某个类的成员函数, 只能定义为普通的C函数。用以监视系统或某一特定类型的事件, 这些事件能够是与某一特定线程关联的,也能够是系统中全部线程的事件。

    钩子回调函数必须按照如下的语法:

 LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam); 1)HookProc是自定义的名字。 2)nCode参数是Hook代 码,Hook子程使用这个参数来肯定任务。 这个参数的值依赖于Hook类型,每一种Hook都 有本身的Hook代码特征字符集。   3)wParamlParam参数的值依赖于nCode,可是它们的典型值 是包含了关于发送或者接收消息的信息。

  2、 钩子的安装与释放:

使用API函数SetWindowsHookEx()把一个应用程序定义的钩子回调函数安装到钩子链表中的开头。当指定类 型的Hook监视的事件发生时,系统就调用与这个Hook关联的Hook链的开头的Hook子 程。每个Hook链中的Hook子程都决定是否把这个事件传递到下一个Hook子程。

Hook子程传递事件到下一个Hook子程须要调用API函数CallNextHookEx()

HHOOK SetWindowsHookEx(int idHook, // 钩子的类型,即它处理的消息类型 HOOKPROC lpfn, // 钩子回调函数地址,                  // 即当钩到了指定类型消息后回调这个函数。 HINSTANCEhMod, // 系统钩子则为DLL的 实例句柄, // 线程钩子乃为NULL DWORD dwThreadId); // 系统钩子则为 零,线程钩子为指定线程ID 函数成功则返回钩子的句柄,失败返回NULL

  发送给(线 程钩子是指定的线程,系统钩子则是所有线程)线程的消息被钩子 回调函数先处理。

在钩子回调函数中完成对消息的处理后,若是想要该消息继续传 递,那么它必须调用另一个SDK中的API函数CallNextHookEx来传递它,以执行钩子链表所指的下一个钩子回调函数。这个函数成功时返回钩子链中 下一个钩子过程的返回值,返回值的类型依赖于钩子的类型。这个函数的原型以下:

LRESULT CallNextHookEx(HHOOK hhk, // SetWindowsHookEx()函数返回的钩子句柄。 int nCode, // 传给钩子过程的事件代码。 WPARAM wParam, // 分别是传给钩子回调函数的参数值, LPARAM lParam); // 其具体含义与钩子类型有关。

钩子函数也能够经过直接返回TRUE来丢弃该消息,并阻止该消息的传递,其余安装了钩子的应用程序将不 会接收到钩子的通知并且还有可能产生不正确的结果。

钩子在使用完以后须要用UnHookWindowsHookEx()卸载,不然会形成麻烦。

BOOL UnhookWindowsHookEx(HHOOK hhk); // SetWindowsHookEx()函数返回的钩子句柄。

函数成功返回TRUE, 不然返回FALSE

3、一些运行机制:

Win16环境中,DLL的 全局数据对每一个载入它的进程来讲都是相同的;

而在Win32环境中,状况却发生了变化,DLL函数中的代码所建立的任何对象与变量都归调用它的进程全部。当进程在载入DLL时,操做系统自动把DLL映射到该进程的私有空间,也就是进程的虚拟地址空间,并且也复制该DLL的全局变量的一份拷贝到该进程空间。也就是说每一个进程所拥有相同的DLL全局变量,它们的名称相同,但其值却并不必定是相同的,并且是互不 干涉的。

所以,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共享存储器是经过存储器映射文件技术实现的。 也能够把这些须要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,不然编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。

#pragma data_seg预处理指令用于设置共享数据段。例如:

// 告诉编译器MyData数 据段要可读可写可共享

#pragma comment(linker, "/section:MyData,rws") #pragma data_seg("MyData") int g_iProNum = -1;#pragma data_seg()

全部对这些数据的操做都针对同一个实例的,而不是在每一个进程 的地址空间中都有一份。

当进程隐式或显式调用一个动态库里的函数时,系统都要把这个 动态库映射到这个进程的虚拟地址空间里(如下简称"地址空间")。这使得DLL成 为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。

相关文章
相关标签/搜索