2006-10-24

Windows 钩子(Hook)简介

钩子(Hook)是 Windows 消息处理机制的重要组成部分,通过使用钩子,应用程序可以安装一个子程序监视系统消息,并且在它们抵达目标进程之前处理这些消息。由于对系统消息增加了处理步骤,所以钩子往往会降低系统性能。因此,你应该只在必要的时候使用钩子,并尽可能早的卸载它们。
系统支持很多种不同类型的钩子,每种类型的钩子提供了访问消息处理机制的不同方面的能力。对于每种钩子,系统都维持了一个钩子链(Hook Chain)。钩子链是一个由指向钩子程序(Hook Procedure)的指针构成的链表,钩子程序是特殊的,应用程序定义的回调函数。消息在产生的时候,被关联到钩子类型的一种,系统使消息一个接一个的通过整条钩子链,让它们处理。钩子程序能采取的动作取决于钩子的类型,有些钩子程序只能监视消息,另一些则可以修改消息,阻止消息抵达钩子链中的下一个钩子或消息的目标进程。
为了利用钩子,开发人员提供了钩子程序,并使用 SetWindowsHookEx 将钩子程序安装到钩子链中,钩子程序是一个声明如下的函数:

LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
);

参数
HookProc,应用程序定义的名字。
nCode,钩子代码,用来决定钩子的动作,每个值具体的作用跟钩子的类型有关。
wParam和lParam,参数,通常用来保存对应消息的有关信息。

SetWindowsHookEx 函数总是将钩子程序安装到钩子链的最前端,事件在发生的时候,被一个特殊的钩子监听到,系统调用有关钩子链的第一个钩子程序,钩子链中的每一个钩子程序都能决定是否将这个事件传递到下一个钩子,钩子程序可以通过调用 CallNextHookEx 来完成传递操作。
需要说明的是有些类型的钩子程序只能监视消息,这时不论是否调用 CallNextHookEx 函数,系统都将消息传递到钩子链中的每一个钩子程序。
全局钩子(Global Hook)能监视到同一个桌面下所有线程的消息,线程特定的钩子(Thread-Specific Hook)只能监视指定线程的消息。全局钩子程序能在任何进程的上下文(Context)中作为调用线程被调用,所以程序通过独立的动态连接库(DLL) 模块来实现。线程特定的钩子程序只在关联线程的上下文中被调用,所以,如果一个进程安装钩子程序处理自己的线程,钩子程序可以在这个程序的代码或动态连接库中实现;如果一个进程安装钩子程序处理其它进程的线程,钩子程序必须在动态连接库中实现。

每种类型的钩子使应用程序能监视系统消息处理机制的不同方面,下面列出了可用的钩子:

WH_CALLWNDPROC 和 WH_CALLWNDPROCRET
这两种钩子使你能监视发送到 windows 程序的消息。其中,系统将在消息发送到目标程序之前调用 WH_CALLWNDPROC 钩子程序,而在目标程序处理完成消息后调用 WH_CALLWNDPROCRET 钩子程序。
更多的信息,可以参考 CallWndProc 和 CallWndRetProc 函数。

WH_CBT
系统将会调用 WH_CBT 钩子程序在以下情况出现时:
激活,创建,销毁,最小化,最大化,移动窗口,改变窗口大小之前;完成系统命令之前;从系统消息队列中删除鼠标或键盘消息之前;设置输入焦点之前;以及同步系统消息队列之前。 WM_CBT 钩子程序主要是被 CBT (Computer-Based Training)程序使用。
更多的信息,可以参考 CBTProc 函数。

WH_DEBUG
系统将在其它任何钩子程序关联时调用 WH_DEBUG 钩子程序。你可以用这个钩子决定是否允许系统调用其它的钩子程序。
更多的信息,可以参考 DebugProc 函数。

WH_FOREGROUNDIDLE
系统将在背景线程空闲的时候调用 WH_FOREGROUNDIDLE 钩子程序,所以你可以用它来执行那些低优先级的任务。
更多的信息,可以参考 ForegroundIdleProc 函数。

WH_GETMESSAGE
WH_GETMESSAGE 钩子使应用程序能够监视 GetMessage 和 PeekMessage 函数的返回。你可以用这个钩子监视鼠标和键盘输入,以及其他添加到消息队列的消息。
更多的信息,可以参考 GetMsgProc 函数。

WH_JOURNALPLAYBACK
WH_JOURNALPLAYBACK 钩子使应用程序能够将消息插入到消息队列中。你可以用这个钩子回放一系列由 WH_JOURNALRECORD 钩子记录的鼠标和键盘事件。 一旦 WH_JOURNALPLAYBACK 钩子被安装,正常的鼠标和键盘输入就是无效的。 WH_JOURNALPLAYBACK 钩子是全局钩子,不能用作线程特定的钩子。
更多的信息,可以参考 JournalPlaybackProc 函数。  

WH_JOURNALRECORD
WH_JOURNALRECORD 钩子使你能够监视和记录输入事件。你可以用这个钩子记录一个鼠标和键盘输入事件的序列,稍后通过 WH_JOURNALPLAYBACK 回放出来。 WH_JOURNALRECORD 钩子是全局钩子,不能用作线程特定的钩子。
更多的信息,可以参考 JournalRecordProc 函数。

WH_KEYBOARD_LL
WH_KEYBOARD_LL 钩子使你能够记录添加到线程输入队列中的键盘输入事件。
更多的信息,可以参考 LowLevelKeyboardProc 函数。

WH_KEYBOARD
WH_KEYBOARD 钩子使应用程序可以监视 WM_KEYDOWN 和 WM_KEYUP消息, 这些消息通过 GetMessage 或 PeekMessage 函数返回。可以使用这个钩子来监视输入到消息队列中的键盘输入。
更多的信息,可以参考 KeyboardProc 函数。

WH_MOUSE_LL
WH_MOUSE_LL 钩子使你能够记录添加到线程输入队列中的鼠标输入事件。
更多的信息,可以参考 LowLevelMouseProc 函数。

WH_MOUSE
WH_MOUSE 钩子使你能够监视通过 GetMessage 或 PeekMessage 函数返回的鼠标消息。可以使用这个钩子来监视输入到消息队列中的鼠标输入。
更多的信息,可以参考 MouseProc 函数。

WH_MSGFILTER 和 WH_SYSMSGFILTER
这两种钩子使你能够监视菜单,滚动条,消息框,对话框的处理,并且发现用户使用 ALT+TAB 或 ALT+ESC 快捷键切换窗口。 WH_MSGFILTER 钩子只能监视传递到菜单,滚动条,消息框的消息,以及通过安装了钩子程序的应用程序建立的对话框的消息。WH_SYSMSGFILTER 钩子监视所有应用程序消息。
更多的信息,可以参考 MessageProc 和 SysMsgProc 函数。

WH_SHELL
外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是激活的并且当顶层窗口建立或者销毁时,系统调用 WH_SHELL 钩子程序。
更多的信息,可以参考 ShellProc 函数。

0 Comments: