深入浅出HOOKS(上)

2004-2-18加入  来自未知  作者佚名  1条评论  点击3585
       
HOOKS 说明书

hook是WINDOWS提供的一种消息处理机制,它使得程序员可以使用子过程来监视系统消息,并在消息到达目标过程前得到处理。

下面将介绍WINNDOWS HOOKS并且说明如何在WINDOWS 程序中使用它。

使用HOOK 将会降低系统效率,因为它增加了系统处量消息的工作量。建议在必要时才使用HOOK,并在消息处理完成后立即移去该HOOK。

HOOK链

WINDOWS提供了几种不同类型的HOOKS;不同的HOOK可以处理不同的消息。例如,WH_MOUSE HOOK用来监视鼠标消息。

WINDOWS为这几种HOOKS维护着各自的HOOK链。HOOK链是一个由应用程序定义的回调函数队列,当某种类型的消息发生时,WINDOWS向此种类型的HOOK链的第一个函数发送该消息,在第一函数处理完该消息后由该函数向链表中的下一个函数传递消息,依次向下。如果链中某个函数没有向下传送该消息,那么链表中后面的函数将得不到此消息。(对于某些类型的HOOK,不管HOOK链中的函数是否向下传递消息,与此类型HOOK联系的所有HOOK函数都会收到系统发送的消息)

 

===========================HOOK过程========================

为了拦截特定的消息,你可以使用SetWindowsHookEx函数在该类型的HOOK链中安装你自己的HOOK函数。该函数语法如下:

public function MyHook(nCode,wParam,iParam) as long

‘加入代码

end function

其中MyHook可以随便命名,其它不能变。该函数必须放在模块段。nCode指定HOOK类型。wParam,iParam的取值随nCode不同而不同,它代表了某种类型的HOOK的某个特定的动作。

SetWindowsHookEx总是将你的HOOK函数放置在HOOK链的顶端。你可以使用CallNextHookEx函数将系统消息传递给HOOK链中的下一个函数。

[注释]对于某些类型的HOOK,系统将向该类的所有HOOK函数发送消息,这时,HOOK函数中的CallNextHookEx语句将被忽略。 

全局HOOK函数可以拦截系统中所有线程的某个特定的消息(此时该HOOK函数必须放置在DLL中),局部HOOK函数可以拦截指定线程的某特定消息(此时该HOOK函数可以放置在DLL中,也可以放置在应用程序的模块段)。

[注释] 建议只在调试时使用全局HOOK函数。全局HOOK函数将降低系统效率,并且会同其它使用该类HOOK的应用程序产生冲突。

 

========================HOOK类型=================================

WH_CALLWNDPROC 和 WH_CALLWNDPROCRET HOOK

WH_CALLWNDPROC 和WH_CALLWNDPROCRET HOOK可以监视SendMessage发送的消息。系统在向窗体过程发送消息前,将调用WH_CALLWNDPROC;在窗体过程处理完该消息后系统将调用WH_CALLWNDPROCRET。

WH_CALLWNDPROCRET HOOK会向HOOK过程传送一个CWPRETSTRUCT结构的地址。该结构包含了窗体过程处理系统消息后的一些信息。

WH_CBT Hook

系统在激活,创建,消毁,最小化,最大化,移动,改变窗体前;在完成一条系统命令前;在从系统消息队列中移去鼠标或键盘事件前;在设置输入焦点前,或同步系统消息队列前,将调用WH_CBT HOOK。你可以在你的HOOK 过程拦截该类HOOK,并返回一个值,告诉系统,是否继续执行上面的操作。

WH_DEBUG HOOK

系统在调用与某种HOOK类型联系的HOOK过程前,将调用WH_DEBUG ,应用程序可以使用该HOOK决定是否让系统执行某种类型的HOOK。

WH_FOREGROUNDIDLE Hook

系统在空闲时调用该HOOK,在后台执行优先权较低的应用程序。

WH_GETMESSAGE Hook

WH_GETMESSAGE Hook使应用程序可以拦截GetMessage 或 PeekMessage的消息。应用程序使用WH_GETMESSAGE HOOK监视鼠标、键盘输入和发送到队列中的其它消息。

WH_JOURNALRECORD Hook

WH_JOURNALRECORD Hook使应用程序可以监视输入事件。典型地,应用程序使用该HOOK记录鼠标、键盘输入事件以供以后回放。该HOOK是全局HOOK,并且不能在指定线程中使用。

WH_JOURNALPLAYBACK Hook

` WH_JOURNALPLAYBACK Hook使应用程序可以向系统消息队列中插入消息。该HOOK可以回放以前由WH_JOURNALRECORD HOOK录制的鼠标、键盘输入事件。在WH_JOURNALPLAYBACK Hook安装到系统时,鼠标、键盘输入事件将被屏蔽。该HOOK同样是一个全局HOOK,不能在指定线程中使用。

WH_JOURNALPLAYBACK Hook返回一个时间暂停值,它告诉系统,在处理当前回放的消息时,系统等待百分之几秒。这使得此HOOK可以控制在回放时的时间事件。

WH_KEYBOARD Hook

WH_KEYBOARD Hook使应用程序可以监视由GetMessage和PeekMessage返回的WM_KEYDOWN 及WM_KEYUP消息。应用程序使用该HOOK监视发送到消息队列中的键盘输入。

WH_MOUSE Hook

WH_MOUSE Hook 使应用程序可以监视由GetMessage和PeekMessage返回的消息。应用程序使用该HOOK监视发送到消息队列中的鼠标输入。

WH_MSGFILTER and WH_SYSMSGFILTER Hooks

WH_MSGFILTER 和WH_SYSMSGFILTER Hooks使应用程序可以监视菜单、滚动条、消息框、对话框,当用户使用ALT+TAB或ALT+ESC来切换窗体时,该HOOK也可以拦截到消息。WH_MSGFILTER仅在应用程序内部监视菜单、滚动条、消息框、对话框,而WH_SYSMSGFILTER则可以在系统内监视所有应用程序的这些事件。

WH_SHELL Hook

一个SHELL程序可以使用WH_SHELL Hook来接收重要的信息。当一个SHELL程序被激活前或当前窗体被创建、消毁时,系统会调用WH_SHELL Hook过程。

 

=======================使用HOOK============================

安装、消毁HOOK过程

监视系统事件

 

安装、消毁HOOK过程

使用SetWindowsHookEx函数,指定一个HOOK类型,自己的HOOK过程是全局还是局部HOOK,同时给出HOOK过程的进入点,就可以轻松的安装你自己的HOOK过程。

为了安装一个全局HOOK过程,必须在应用程序外建立一个DLL,并将该HOOK函数封装到其中,应用程序在安装全局HOOK过程时必须先得到该DLL模块的句柄。将DLL名传递给LoadLibrary 函数,就会得到该DLL模块的句柄;得到该句柄 后,使用GetProcAddress函数可以得到HOOK过程的地址。最后,使用SetWindowsHookEx将HOOK过程的首址嵌入相应的HOOK链中,SetWindowsHookEx传递一个模块句柄,它为HOOK过程的进入点,线程标识符置为0,指出:该HOOK过程同系统中的所有线程关联。

以下是C写的例程,大家可以方便的转换为VB程序。

HOOKPROC hkprcSysMsg; 

static HINSTANCE hinstDLL; 

static HHOOK hhookSysMsg; 







 

hinstDLL = LoadLibrary((LPCTSTR) "c://windows//sysmsg.dll"); 

hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc"); 

hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER, 

hkprcSysMsg, hinstDLL, 0); 

 
Hook简介

2000-03-18· -·cww

 

  Hook这个东西有时令人又爱又怕,Hook是用来拦截系统某些信息之用,例如说,我们想 让系统不管在什麽地方只要按个Ctl-B便执行NotePad,或许您会使用Form的KeyPreview,设定为True,但在其他Process中按Ctl-B呢?那就没有用,这时就得设一个Keyboard Hook来拦截所有Key in的键;再如:MouseMove的Event只在该Form或Control上有效,如 果希望在Form的外面也能得知Mouse Move的信息,那只好使用Mouse Hook来栏截Mouse 的信息。再如:您想记录方才使用者的所有键盘动作或Mosue动作,以便录巨集,那就使用JournalRecordHook,如果想停止所有Mosue键盘的动作,而放(执行)巨集,那就使用JournalPlayBack Hook;Hook呢,可以是整个系统为范围(Remote Hook),即其他 Process的动作您也可以拦截,也可以是LocalHook,它的拦截范围只有Process本身。Remote Hook的Hook Function要在.Dll之中,Local Hook则在.Bas中。

在VB如何设定Hook呢?使用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代表是何种Hook,有以下几种

Public Const WH_CALLWNDPROC = 4

Public Const WH_CALLWNDPROCRET = 12

Public Const WH_CBT = 5

Public Const WH_DEBUG = 9

Public Const WH_FOREGROUNDIDLE = 11

Public Const WH_GETMESSAGE = 3

Public Const WH_HARDWARE = 8

Public Const WH_JOURNALPLAYBACK = 1

Public Const WH_JOURNALRECORD = 0

Public Const WH_KEYBOARD = 2

Public Const WH_MOUSE = 7

Public Const WH_MSGFILTER = (-1)

Public Const WH_SHELL = 10

Public Const WH_SYSMSGFILTER = 6

 

lpfn代表Hook Function所在的Address,这是一个CallBack Fucnction,当挂上某个Hook时,我们便得定义一个Function来当作某个信息产生时,来处理它的Function,这个Hook Function有一定的参数格式

 

Private Function HookFunc(ByVal nCode As Long,ByVal wParam As Long, ByVal lParam As Long ) As Long

 

nCode 代表是什麽请况之下所产生的Hook,随Hook的不同而有不同组的可能值wParam lParam 传回值则随Hook的种类和nCode的值之不同而不同。

 

因这个参数是一个 Function的Address所以我们固定将Hook Function放在.Bas中,并以AddressOf HookFunc传入。至于Hook Function的名称我们可以任意给定,不一定叫HookFunc

 

hmod 代表.DLL的hInstance,如果是Local Hook,该值可以是Null(VB中可传0进去),而如果是Remote Hook,则可以使用GetModuleHandle(".dll名称")来传入。

 

dwThreadId 代表执行这个Hook的ThreadId,如果不设定是那个Thread来做,则传0(所以 一般来说,Remote Hook传0进去),而VB的Local Hook一般可传App.ThreadId进去

 

值回值 如果SetWindowsHookEx()成功,它会传回一个值,代表目前的Hook的Handle, 这个值要记录下来。

 

因为A程序可以有一个System Hook(Remote Hook),如KeyBoard Hook,而B程序也来设一 个Remote的KeyBoard Hook,那麽到底KeyBoard的信息谁所拦截?答案是,最後的那一个 所拦截,也就是说A先做keyboard Hook,而後B才做,那信息被B拦截,那A呢?就看B的 Hook Function如何做。如果B想让A的Hook Function也得这个信息,那B就得呼叫 CallNextHookEx()将这信息Pass给A,於是产生Hook的一个连线。如果B中不想Pass这信息给A,那就不要呼叫CallNextHookEx()。

 

Declare Function CallNextHookEx Lib "user32" Alias "CallNextHookEx" _

(ByVal hHook As Long, _

ByVal ncode As Long, _

ByVal wParam As Long, _

lParam As Any) As Long

 

hHook值是SetWindowsHookEx()的传回值,nCode, wParam, lParam则是Hook Procedure 中的三个参数。

 

最後是将这Hook去除掉,请呼叫UnHookWindowHookEx()

 

Declare Function UnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx" _

(ByVal hHook As Long) As Long

 

hHook便是SetWindowsHookEx()的传回值。此时,以上例来说,B程序结束Hook,则换A可 以直接拦截信息。

 

 

KeyBoard Hook的范例

 

Hook Function的三个参数

 

 

nCode wParam lParam 传回值 

HC_ACTION或HC_NOREMOVE 表按键Virtual Key 与WM_KEYDOWN同 若信息要被处理传0 反之传1

 

 

Public hHook as Long

 

Public Sub UnHookKBD()

 

If hnexthookproc <> 0 Then

 

UnhookWindowsHookEx hHook

hHook = 0

 

End If

 

End Sub

 

 

Public Function EnableKBDHook()

 

If hHook <> 0 Then Exit Function

hhook = SetWindowsHookEx(WH_KEYBOARD, AddressOf MyKBHFunc, App.hInstance, App.ThreadId)

 

End Function

 

Public Function MyKBHFunc(ByVal iCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

 

MyKBHfunc = 0 '表示要处理这个信息

 

If wParam = vbKeySnapshot Then '侦测 有没有按到PrintScreen键

 

MyKBHFunc = 1 '在这个Hook便吃掉这个信息

 

End If

Call CallNextHookEx(hHook, iCode, wParam, lParam) '传给下一个Hook

 

End Function

 

  至於其他的 Hook的详细资料与nCode,wParam, lParam的意义,请查Win32 Help

                  如何获得密码窗口的内容------揭开Hook的面纱 

 

                                          Pan Ying(zero world)

 

  现在的不少程序都有取得密码窗口的内容的功能,你有没有想过是如何做到这一切的呢?我有一个同学就问过我这样一个问题,当时我也回答不出来,现在我研究了视窗的Hook函数之后总算有了一定的了解。下面就有我来揭开Hook函数的神秘面纱。 

 
  先来介绍Hook的含义: 

  Hook是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息。举例来说,当你在一个窗口上点击鼠标以后,首先接收信息的是相应的Hook函数,然后才传到相应的应用程序。 

 
  如何定义Hook函数: 

SetWindowsHookEx: 

  用来装入新的Hook函数,其参数列表为下: 

int idHook:装入Hook类型,有WH_MOUSE 等。 

HOOKPROC lpfn:要装入的Hook函数地址。 

HINSTANCE hMod:函数所在的进程,如果为全局Hook函数该函数必须在Dll中。 

DWORD dwThreadId:装入哪个进程,如果为全局,则为0。 

  返回相应Hook标识。 

HookProc: 

  您自定义的Hook函数,应具有的参数如下: 

int nCode:传入的信息类型。 

WPARAM wParam:短整型参数。 

LPARAM lParam:长整型参数。 

  要在函数中调用CallNextHookEx把信息传给下一个Hook函数。 

CallNextHookEx: 

  用于将信息传给下一个Hook函数,需要将得到的Hook标识和相应参数传入。 

UnhookWindowsHookEx: 

  用于将装入的Hook函数从Hook链表中剔除,应传入得到的Hook标识。 

下面我们来看一个例子: 

  例子原码的下载:HookTest.zip 本程序在Window98和Delphi5下通过。 

 一、调用LoadLibrary和GetProcAddress取得函数地址。 

  hinstDLL := LoadLibrary(LPCTSTR( 'hooktest.dll')); 

  @hkprcSysMsg:=GetProcAddress(hinstDLL, 'MouseProc'); 

 

二、用SetWindowsHookEx将得到的函数装入。 

  hhk:= SetWindowsHookEx(WH_MOUSE,@hkprcSysMsg,hinstDLL, 0); 

 

三、Windows会将函数装入到每一个进程中。 

 

四、每当鼠标点击,自定义的Hook函数会将点击的窗口标题传给程序的标题。 

if (nCode=HC_ACTION)and(WPARAM=WM_LBUTTONDOWN) 

 then 

  begin 

   MyMouse:=CPointer(lPARAM); 

   MyHandle2:=MyMouse^.hwnd; 

   GetMem(MyString,GetWindowTextlength(myhandle2)+1); 

   GetWindowText(MyHandle2,MyString,GetWindowTextlength(myhandle2)+1); 

   TempHandle:=myhandle2; 

   while (TempHandle<>0) do 

   begin 

    myHandle2:=TempHandle; 

    TempHandle:=GetParent(TempHandle); 

   end; 

   if (myhandle2<>0) 

   then 

    SetWindowText(myhandle2,MyString); 

   FreeMem(MyString); 

  end 

就这样完成了得到密码窗口内容的功能。 



关于 HOOK 
[ 作者: 陆麟   添加时间: 2001-6-2 0:04:44 ]
来源:lu0.126.com

大家讨论HOOK太多了.在网络中,概凡谈论到进程控制,十有八九最后会得到一句话:写HOOK. 
嘿嘿,知道HOOK运作机理的有几个呢?下面,本人就MSDN文档中没有写到的一点东西稍微讲几句. 

以下讲述乃针对全局HOOK而发. 

1.设置HOOK过程时返回的前一HOOK地址必须被保存到一个全局共享的内存地址段中.这个共享段的地址不是什么本进程的全局变量,而是所有进程都可以看见的变量.因为,进程级变量进在本进程内可见.当其他进程加载HOOK DLL时,HOOK DLL里的所有变量都会被RESET.这也就是说: 

HHOOK hk; 

//set and get HHOOK here 

return hk(); 

这样的描述是不能跳转到前一HOOK的.这一点,甚至在Jeffrey Richter的经典书籍<>里都描述错了. 

正确的做法是: 

#pragma data_seg("dt") 

HHOOK prehook=0; 

#pragma data_seg() 

然后到VC的LINK OPITION里加上: 

-SECTION:dt,RWS 

这样,prehook就被搞到系统中被共享了.记住,一定要给prehook初始化.否则,MS编译器的编译器会LINK错误. 

 

2.只有使用USER32.DLL的进程才会被INJECT.所以,HOOK并不是万能的.而且,用了USER32.DLL,也不一定会被INJECT.这里有个很好的例子就是整个OS启动中第一个被启动的WIN32进程:KERNEL32.DLL.大家很奇怪,KERNEL32.DLL是个DLL,怎么也会被作为进程加载?但是事实的确是这样的,顺便给大家再上一节98启动课吧.KERNEL32.DLL作为一个独立的进程,启动时加载了MSGSRV32.EXE.而MSGSRV32.EXE又启动了SPOOL32.EXE, SPOOL32.EXE启动了MPREXE.EXE.MPREXE.EXE可不能小看.我敢担保全中国没几个人真正知道它的作用的.MPREXE.EXE不仅是网络客户端部件启动的核心,更是WIN98的SERVICE的SCM.所有的WIN98的SERVICE都是由MPREXE.EXE启动的.WIN98的SERVICE都在HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/RunServices里呆者哩.大家都傻眼了吧.:DDD 有一点很令人奇怪, 那就是如果MPREXE.EXE运作不正常,那么SHELL绝对起不来.SHELL却是有MSGSRV32.EXE启动的.看来MPREXE和MSGSRV32有一套内部沟通机制啊.有了SHELL,就什么都有了.其他的东西被SHELL启动就难说准了.反正80%的程序是由SHELL启动的.好了,WIN98启动暂且讲到这里.我们继续原先的话题.KERNEL32.DLL居然就无法用HOOK入侵.大家如果不信的话,就试试看吧. 

3.尽管使用USER32.DLL的进程会被INJECT. 但是这里还有一个技巧,那就是HOOK DLL是在进程第一次发出USER32调用的时候才被加载. 大家又目瞪口呆了吧.:) 这也就是说,在你发出USER32调用之前, HOOK DLL根本拿你没办法. 哇,真够幽默啊.:)))由于在启动HOOK前的进程绝对都是在调用GetMessage(...)/PeekMessage(...)中,那么HOOK DLL一下子满足了加载条件了. 

 
4.加载HOOK时,HMODULE一定要正确,否则,系统就无法正确加载HOOK过程.千万不要用0代替HMODULE,因为0代表的是EXE映象的HINSTANCE(其实就是HMODULE). 

好了.今天就写到这里.此文该算本主页里又一篇经典了吧.:) 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值