前言
Windows 系统中钩子具有相当强大的功能,通过这种技术可以对几乎所有的 Windows 系统中的消息进行拦截、监视、处理。这种技术可以广泛应用于各种软件,尤其是需要有监控、自动记录等对系统进行监测功能的软件。本文针对这个专题进行了探讨,希望可以为读者朋友们起到抛砖引玉的作用。
一、钩子的机制及类型
Windows 的应用程序都是基于消息驱动的,应用程序的操作都依赖于它所得到的消息的类型及内容。钩子与 Dos 中断截获处理机制有类似之处。钩子 (Hook) 是 Windows 消息处理机制的一个平台,通过安装各种钩子,应用程序可以在上面设置子程序以监视指定窗口的某种消息,并且当消息到达目标窗口之前处理它。
在 Windows 中,钩子有两种,一种是系统钩子 (RemoteHook) ,它对消息的监视是整个系统范围,另一种是线程钩子 (LocalHook) ,它的拦截范围只有进程内部的消息。对于系统钩子,其钩子函数( HookFunction )应在 Windows 系统的动态链接库 (DLL) 中实现,而对于线程钩子来说 , 钩子函数可以在 DLL 之中实现,也可以在相应的应用程序之中实现。这是因为当开发人员创建一个钩子时, Windows 先在系统内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去,并且新的钩子将排在老的钩子的前面。当一个事件发生时,如果安装的是一个局部钩子,当前进程中的钩子函数将被调用。如果是一个远程钩子,系统就必须把钩子函数插入到其它进程的地址空间,要做到这一点就要求钩子函数必须在一个动态链接库中,所以如果想要使用远程钩子,就必须把该钩子函数放到动态链接库中去。对于钩子所监视的消息类型来说, Windws 一共提供了如下几种类型:如表 1 所示 :
表一、 Windows 消息类型
消息类型常量标识
|
值
|
消息类型
|
适用范围
---|---|---|---
WH_CALLWNDPROC
|
4
|
发给窗口的消息
|
线程或系统
WH_CALLWNDPROCRET
|
12
|
窗口返回的消息
|
线程或系统
WH_CBT
|
5
|
窗口变化、焦点设定等消息
|
线程或系统
WH_DEBUG
|
9
|
是否执行其它 Hook 的 Hook
|
线程或系统
WH_FOREGROUNDIDLE
|
11
|
前台程序空闲
|
线程或系统
WH_GETMESSAGE
|
3
|
投放至消息队列中的消息
|
线程或系统
WH_JOURNALPLAYBACK
|
1
|
将所记载的消息进行回放
|
系统
WH_JOURNALRECORD
|
0
|
监视并记录输入消息
|
系统
WH_KEYBOARD
|
2
|
键盘消息
|
线程或系统
WH_MOUSE
|
7
|
鼠标消息
|
线程或系统
WH_MSGFILTER
|
-1
|
菜单滚动条、对话框消息
|
线程或系统
WH_SHELL
|
10
|
外壳程序的消息
|
线程或系统
WH_SYSMSGFILTER
|
6
|
所有线程的菜单滚动条、对话框消息
|
系统
二、 ** VB ** ** 编程中钩子的实现 **
(一)钩子函数 (HOOK Function) 的格式。 Hook Function 实际上是一个函数,如果是系统钩子,该函数必须放在动态链接库中。该函数有一定的参数格式,在 VB 中如下 :
Private Function HookFunc(ByVal nCode As Long , ByVal wParam As Long , ByVal lParam As Long)As Long
其中, nCode 代表是什么情况之下所产生的钩子,随钩子的不同而有不同组的可能值;参数 wParam , lParam 传回值包括了所监视到的消息内容,它随 Hook 所监视消息的种类和 nCode 的值不同而不同。对于用 VB 所设置的钩子函数 , 一般的框架形式如下 :
Private Function HookFunc(ByVal nCode As Long , ByVal wParam As Long , ByVal lParam As Long)As Long
Select case of nCode
case ncode<0:hookfunc=callnexthookex(hHookFunc , nCode , wParam , lParam)
case 值 1: 处理过程 1:HookFunc=X1
case2: 处理过程 2:HookFunc=X1
……
end select
end Function
函数的传回值,如果消息要被处理,则传 0 ,否则传 1 ,吃掉消息。
(二)钩子的安装及执行。钩子的安装要用到几个 API 函数 : 可以使用 API 函数 SetWindowsHookEx() 把一个应用程序定义的钩子子程安装到钩子链表中。 SetWindowsHookEx() 函数的声明如下 :
Declare function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA"(ByVal idHook As Long , ByVal lpfn As Long , ByVal hmod As Long , ByVal dwThreadId As Long)As Long
idHook 值为它处理的消息类型; lpfn 值为钩子子程序的地址指针。如果 dwThreadId 参数为 0 或是一个由别的进程创建的线程的标识, lpfn 必须指向 DLL 中的钩子子程。除此以外, lpfn 可以指向当前进程的一段钩子子程代码。 hMod 值为应用程序的句柄,标识包含 lpfn 所指的子程的 DLL 。如果 dwThreadId 标识当前进程创建的一个线程,而且子程代码位于当前进程, hMod 必须为 0 。 dwThreadId 值为与安装的钩子子程相关联的线程的标识符,如果为 0 ,钩子子程与所有的线程关联。钩子安装成功则返回钩子子程的句柄,失败返回 0 。
另外,一般应在钩子子程中调用 CallNextHookEx() 函数以执行钩子链表所指的下一个钩子子程,否则安装了别的钩子的应用程序就会收不到钩子通知,从而产生错误的结果。 CallNextHookEx() 函数的声明如下 :
Declare Function CallNextHookEx Lib"user32" Alias "CallNextHookEx"(ByVal hHook As Long , ByVal ncode As Lonog , ByVal wParam As Long , lParam As Any)As Long
hHook 值是 SetWindowsHookEx() 的传回值, nCode 、 wParam 、 lParam 则是 Hook 函数中的三个参数。在程序终止之前,必须调用 UnhookWindowsHookEx() 函数释放与钩子关联的系统资源。 UnhookWindowsEx() 函数声明如下 :
Declare Function Unhook WindowsHookEx Lib "user32" Alias "Unhook WindowsHookEx(ByVal hHook As Long)As Long
hHook 为安装钩子时的返回值,即钩子子程的句柄。
(三) VB 中钩子安装应注意的问题。 lpfn 参数是一个 HookFunc 的地址 ,VB 规定必须将 HookFunc 代码放到标准的 .BAS 模块中,并以 "Address Of HookFunc" 传入,而不可以将其放到类模块中,也不能将其附加到窗体上。而对于 </SPA