Windows系統中鉤子具有相當強大的功能,通過這種技術可以對幾乎所有的Windows 系統中的消息進行攔截、監(jiān)視、處理。這種技術可以廣泛應用于各種軟件,尤其是需要有監(jiān)控、自動記錄等對系統進行監(jiān)測功能的軟件。本文針對這個專題進行了探討,希望可以為讀者朋友們起到拋磚引玉的作用。
一、鉤子的機制及類型
Windows的應用程序都是基于消息驅動的,應用程序的操作都依賴于它所得到的消息的類型及內容。鉤子與Dos中斷截獲處理機制有類似之處。鉤子(Hook)是Windows消息處理機制的一個平臺,通過安裝各種鉤子,應用程序可以在上面設置子程序以監(jiān)視指定窗口的某種消息,并且當消息到達目標窗口之前處理它。
在Windows中,鉤子有兩種,一種是系統鉤子(RemoteHook),它對消息的監(jiān)視是整個系統范圍,另一種是線程鉤子(LocalHook),它的攔截范圍只有進程內部的消息。對于系統鉤子,其鉤子函數(HookFunction)應在Windows系統的動態(tài)鏈接庫(DLL)中實現,而對于線程鉤子來說,鉤子函數可以在DLL之中實現,也可以在相應的應用程序之中實現。這是因為當開發(fā)人員創(chuàng)建一個鉤子時,Windows先在系統內存中創(chuàng)建一個數據結構,該數據結構包含了鉤子的相關信息,然后把該結構體加到已經存在的鉤子鏈表中去,并且新的鉤子將排在老的鉤子的前面。當一個事件發(fā)生時,如果安裝的是一個局部鉤子,當前進程中的鉤子函數將被調用。如果是一個遠程鉤子,系統就必須把鉤子函數插入到其它進程的地址空間,要做到這一點就要求鉤子函數必須在一個動態(tài)鏈接庫中,所以如果想要使用遠程鉤子,就必須把該鉤子函數放到動態(tài)鏈接庫中去。對于鉤子所監(jiān)視的消息類型來說,Windws一共提供了如下幾種類型:如表1所示:
表一、Windows消息類型
消息類型常量標識 |
值 |
消息類型 |
適用范圍 |
WH_CALLWNDPROC |
4 |
發(fā)給窗口的消息 |
線程或系統 |
WH_CALLWNDPROCRET |
12 |
窗口返回的消息 |
線程或系統 |
WH_CBT |
5 |
窗口變化、焦點設定等消息 |
線程或系統 |
WH_DEBUG |
9 |
是否執(zhí)行其它Hook的Hook |
線程或系統 |
WH_FOREGROUNDIDLE |
11 |
前臺程序空閑 |
線程或系統 |
WH_GETMESSAGE |
3 |
投放至消息隊列中的消息 |
線程或系統 |
WH_JOURNALPLAYBACK |
1 |
將所記載的消息進行回放 |
系統 |
WH_JOURNALRECORD |
0 |
監(jiān)視并記錄輸入消息 |
系統 |
WH_KEYBOARD |
2 |
鍵盤消息 |
線程或系統 |
WH_MOUSE |
7 |
鼠標消息 |
線程或系統 |
WH_MSGFILTER |
-1 |
菜單滾動條、對話框消息 |
線程或系統 |
WH_SHELL |
10 |
外殼程序的消息 |
線程或系統 |
WH_SYSMSGFILTER |
6 |
所有線程的菜單滾動條、對話框消息 |
系統 |
二、VB編程中鉤子的實現
(一)鉤子函數(HOOK Function)的格式。Hook Function實際上是一個函數,如果是系統鉤子,該函數必須放在動態(tài)鏈接庫中。該函數有一定的參數格式,在VB中如下:
Private Function HookFunc(ByVal nCode As Long,ByVal wParam As Long,ByVal lParam As Long)As Long |
其中,nCode代表是什么情況之下所產生的鉤子,隨鉤子的不同而有不同組的可能值;參數wParam,lParam傳回值包括了所監(jiān)視到的消息內容,它隨Hook所監(jiān)視消息的種類和nCode的值不同而不同。對于用VB所設置的鉤子函數,一般的框架形式如下:
Private Function HookFunc(ByVal nCode As Long,ByVal wParam As Long,ByVal lParam As Long)As Long |
函數的傳回值,如果消息要被處理,則傳0,否則傳1,吃掉消息。
(二)鉤子的安裝及執(zhí)行。鉤子的安裝要用到幾個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或是一個由別的進程創(chuàng)建的線程的標識,lpfn必須指向DLL中的鉤子子程。除此以外,lpfn可以指向當前進程的一段鉤子子程代碼。hMod值為應用程序的句柄,標識包含lpfn所指的子程的DLL。如果dwThreadId標識當前進程創(chuàng)建的一個線程,而且子程代碼位于當前進程,hMod必須為0。dwThreadId值為與安裝的鉤子子程相關聯的線程的標識符,如果為0,鉤子子程與所有的線程關聯。鉤子安裝成功則返回鉤子子程的句柄,失敗返回0。
另外,一般應在鉤子子程中調用CallNextHookEx()函數以執(zhí)行鉤子鏈表所指的下一個鉤子子程,否則安裝了別的鉤子的應用程序就會收不到鉤子通知,從而產生錯誤的結果。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規(guī)定必須將HookFunc代碼放到標準的.BAS模塊中,并以"Address Of HookFunc"傳入,而不可以將其放到類模塊中,也不能將其附加到窗體上。而對于RemoteHook來說,HookFunc應包含在動態(tài)鏈接庫中,因此如果在VB中使用RemoteHook,則還要用到GetModuleHandle()、GetProcAddress()兩個API函數,它們的聲明如下:
Declare Function GetModuleHandle Lib"kernel32" Alias "GetModuleHandleA"(ByVal lpModuleName As String)As Long |
hmod值是含鉤子過程的模塊名柄,如果是LocalHook,該值可以是Null(VB中傳0),而如果是RemoteHook,則可以使用GetModuleHandle("名稱.dll")來傳入。
新聞熱點
疑難解答