首页 > 开发 > 综合 > 正文

VB编程中钩子的实现及应用

2024-07-21 02:25:34
字体:
来源:转载
供稿:网友
 前言

  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"传入,而不可以将其放到类模块中,也不能将其附加到窗体上。而对于remotehook来说,hookfunc应包含在动态链接库中,因此如果在vb中使用remotehook,则还要用到getmodulehandle()、getprocaddress()两个api函数,它们的声明如下:

declare function getmodulehandle lib"kernel32" alias "getmodulehandlea"(byval lpmodulename as string)as long
declare function getprocaddress lib "kernel32" alias "getprocaddress"(byval hmodule as long,byval lpprocname as string)as long



  hmod值是含钩子过程的模块名柄,如果是localhook,该值可以是null(vb中传0),而如果是remotehook,则可以使用getmodulehandle("名称.dll")来传入。
三、实例--键盘消息的拦截

  在程序开发时常用的有对输入消息进行监视的键盘钩子,对于所监视到的消息应进行处理,下面对键盘钩子参数的具体内容组成进行说明:

  如果有键盘消息(wm_keyup或wm_keydown)将被处理时,则系统调用键盘钩子。

  ncode为hc_action或hc_noremove,若小于0,则要求处理函数向下传递该消息。

  wparam表示按键键码常数,a键到z键与其ascii码的相应值'a'到'z'是一致的,例如按c键,则wparam值为67。

  lparam与wm_keydown同,占四个字节,其包括的内容较多,其二进制结构如下:

0
1
……
15
16
………
23
24
25
……
28
29
30
31



  0-15位(key repeat count),键码重复次数。16-23位(scan code),按键的扫描码。24位(extended_key flag),扩展键(功能键、数字小键盘上的键)标志,为1则是扩展键,否则为0。25-28位被保留。29位(context code),状态描述码,alt键被按下则为1,否则为0。30位(previouskey_stateflag)指定先前的键状态,如果消息被发出之前键处于按下状态,则为1;键处于释放状态则为0。31位(transiton_stateflag)状态转换标志,如果键是被按下值为1,如果键被放开值为0。

  本例中的钩子用来监视并记录应用程序中的按键信息。在程序中,alt+f4组合键被屏蔽。下面是部分代码:

public hhook as long
private sub form_load()′程序启动时安装钩子
hhook=setwindowshookex(2,address of mykbhook,0,app.threadid)
end sub
′具体的钩子程序,本例中该过程被包含在module1中
public function mykbhook(byval ncode as long,byval wparam as long,byval lparam as long)as long
if ncode>=0 then
open "c:/keyfile.txt" for append as #1 '将键盘的操作记录在keyfile.txt文件之中
'记录所操作的键、操作时间、日期操作时的按键状态,用16进制记录
write #1,wparam,hex(lparam),date,time
close #1
mykbhook=0 '表示要处理这个消息
'屏蔽alt+f4组合键
if wparam=115 and(lparam and&h20000000)<>0 then
if(lparam and &hc000000)=0 then  '是否进行alt+f4操作
myhbhook=1 '钩子吃掉这个消息
end if
end if
end if
call callnexthookex(hhook,ncode,wparam,lparam)'将消息传给下一个钩子
end function
'程序退出时卸载钩子
private sub form_unload(cancel as interger)
call unhook windowshookex(hhook)
end sub



  四、总结

  钩子处理程序是windows高级编程技术,一般程序员都使用vc++等程序设计工具实现,本文表明,对于vb来说,虽然很多人认为是非专业的设计工具,但实现钩子这样的高级技术也是非常方便的。另外在使用钩子时应注意到,钩子虽然功能比较强,但如果使用不当将会严重影响系统的效率,所以要尽量避免使用系统钩子,并且在不用钩子时,应将钩子及时卸载。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表