複製鏈接
請複製以下鏈接發送給好友

hook

(Windows系統機制)

鎖定
Hook是Windows中提供的一種用以替換DOS下“中斷”的系統機制,中文譯為“掛鈎”或“鈎子”。在對特定的系統事件進行hook後,一旦發生已hook事件,對該事件進行hook的程序就會收到系統的通知,這時程序就能在第一時間對該事件做出響應。
中文名
掛鈎
外文名
hook
別    名
鈎子

目錄

hook解釋

鈎子(Hook),是Windows消息處理機制的一個平台,應用程序可以在上面設置子程以監視指定窗口的某種消息,而且所監視的窗口可以是其他進程所創建的。當消息到達後,在目標窗口處理函數之前處理它。鈎子機制允許應用程序截獲處理window消息或特定事件。
鈎子實際上是一個處理消息的程序段,通過系統調用,把它掛入系統。每當特定的消息發出,在沒有到達目的窗口前,鈎子程序就先捕獲該消息,亦即鈎子函數先得到控制權。這時鈎子函數即可以加工處理(改變)該消息,也可以不作處理而繼續傳遞該消息,還可以強制結束消息的傳遞。

hook原理

每一個Hook都有一個與之相關聯的指針列表,稱之為鈎子鏈表,由系統來維護。這個列表的指針指向指定的,應用程序定義的,被Hook子程調用的回調函數,也就是該鈎子的各個處理子程序。當與指定的Hook類型關聯的消息發生時,系統就把這個消息傳遞到Hook子程。一些Hook子程可以只監視消息,或者修改消息,或者停止消息的前進,避免這些消息傳遞到下一個Hook子程或者目的窗口。最近安裝的鈎子放在鏈的開始,而最早安裝的鈎子放在最後,也就是後加入的先獲得控制權。
Windows 並不要求鈎子子程的卸載順序一定得和安裝順序相反。每當有一個鈎子被卸載,Windows 便釋放其佔用的內存,並更新整個Hook鏈表。如果程序安裝了鈎子,但是在尚未卸載鈎子之前就結束了,那麼系統會自動為它做卸載鈎子的操作。
鈎子子程是一個應用程序定義的回調函數(CALLBACK Function),不能定義成某個類的成員函數,只能定義為普通的C函數。用以監視系統或某一特定類型的事件,這些事件可以是與某一特定線程關聯的,也可以是系統中所有線程的事件。
系統鈎子與線程鈎子
SetWindowsHookEx()函數的最後一個參數決定了此鈎子是系統鈎子還是線程鈎子。
線程鈎子用於監視指定線程的事件消息。線程鈎子一般在當前線程或者當前線程派生的線程內。
系統鈎子監視系統中的所有線程的事件消息。因為系統鈎子會影響系統中所有的應用程序,所以鈎子函數必須放在獨立的動態鏈接庫(DLL) 中。系統自動將包含“鈎子回調函數”的DLL映射到受鈎子函數影響的所有進程的地址空間中,即將這個DLL注入了那些進程。
幾點説明:
(1)如果對於同一事件(如鼠標消息)既安裝了線程鈎子又安裝了系統鈎子,那麼系統會自動先調用線程鈎子,然後調用系統鈎子。
(2)對同一事件消息可安裝多個鈎子處理過程,這些鈎子處理過程形成了鈎子鏈。當前鈎子處理結束後應把鈎子信息傳遞給下一個鈎子函數。
(3)鈎子特別是系統鈎子會消耗消息處理時間,降低系統性能。只有在必要的時候才安裝鈎子,在使用完畢後要及時卸載。

hook應用模式

觀察模式
最為常用,像Windows提供的SetWindowHook就是典型地為這類應用準備的。而且這也是最普遍的用法。
這個模式的特點是,在事情發生的時候,發出一個通知信息。觀察者只可以查看過程中的信息,根據自己關心的內容處理自己的業務,但是不可以更改原來的流程。
全局鈎子中,經常使用的鼠標消息、鍵盤消息的監視等應用。金山詞霸屏幕取詞的功能是一個典型的應用(具體技術可以參考此類文章)。
注入模式
這個模式和觀察模式最大的不一樣的地方在於,注入的代碼是為了擴展原始代碼的功能業務。插件模式是此類模式的典型案例。
不管瘦核心的插件系統(如Eclipse)還是胖核心的插件系統(如Delphi、Visual Studio等IDE環境),其對外提供的插件接口都是為了擴展本身系統的功能的。
這種擴展的應用方式的典型特點,就是新的擴展代碼和原來的代碼會協調處理同類業務。
替換模式
如果針對應用目的不同,可以叫修復模式或破解模式。前者是為了修改系統中的BUG,後者是為了破解原有系統的限制。
很多黑客使用此種模式,將訪問加密鎖的DLL中的導出表,替換成自己的函數,這樣跳過對軟件的控制代碼。這類應用的難點是,找出函數的參數。
這類模式的特點是,原有的代碼會被新的代碼所替換。
前面三個是基本模式,還有很多和實際應用相關的模式。
集權模式
此類模式的出現,大都是為了在全部系統中,統一處理某類事情。它的特點不在於注入的方式,而在於處理的模式。
這個模式,大都應用到某類服務上,比如鍵盤服務,鼠標服務,打印機服務等等特定服務上。通過統一接管此類服務的訪問,限制或者協調對服務的訪問。
比如鍵盤鎖功能的實現,就是暫時關閉鍵盤的所有應用。
這類模式的特點主要會和特點服務有關聯。
修復模式
替換模式的一種,這裏強調的是其應用的目的是為了修復或擴展原有系統的功能。
破解模式
替換模式的一種,這裏強調的是其應用的目的是為了跳過原有系統的一部分代碼。如加密檢測代碼,網絡檢測代碼等等。
插件模式
注入模式的一種,在系統的內部直接依靠HOOK機制進行擴展業務功能。
共享模式
這類應用中,經常是為了獲取對方的數據。必然我希望獲取對方系統中,所有字符串的值。可以通過替換對方的內存管理器,導出所有字符串。
這個應用比較特殊。不過其特點在於,目的是達到系統之間的數據共享。
其實現,可能是觀察模式,也可能是替換模式。
VB中的Hook技術應用
一、Hook簡介
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
WH_CALLWNDPROC 當調用SendMessage時
WH_CALLWNDPROCRET 當SendMessage的調用返回時
WH_GETMESSAGE 當調用GetMessage 或 PeekMessage時
WH_KEYBOARD 當調用GetMessage 或 PeekMessage 來從消息隊列中查詢WM_KEYUP 或 WM_KEYDOWN 消息時
WH_MOUSE 當調用GetMessage 或 PeekMessage 來從消息隊列中查詢鼠標事件消息時
WH_HARDWARE 當調用GetMessage 或 PeekMessage 來從消息隊列種查詢非鼠標、鍵盤消息時
WH_MSGFILTER 當對話框、菜單或滾動條要處理一個消息時。該鈎子是局部的。它時為那些有自己的消息處理過程的控件對象設計的。
WH_SYSMSGFILTER 和WH_MSGFILTER一樣,只不過是系統範圍的
WH_JOURNALRECORD 當WINDOWS從硬件隊列中獲得消息時
WH_JOURNALPLAYBACK 當一個事件從系統的硬件輸入隊列中被請求時
WH_SHELL 當關於WINDOWS外殼事件發生時,譬如任務條需要重畫它的按鈕.
WH_CBT 當基於計算機的訓練(CBT)事件發生時
WH_FOREGROUNDIDLE 由WINDOWS自己使用,一般的應用程序很少使用
WH_DEBUG 用來給鈎子函數除錯
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' _
(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 FunctionUnhookWindowsHookExLib 'user32' (ByVal hHook As Long) As Long
hHook便是SetWindowsHookEx()的傳回值。此時,以上例來説,B程式結束Hook,則換A可
以直接攔截訊息。
KeyBoard Hook的範例
Hook Function的三個叁數
nCode wParam lParam 傳回值
HC_ACTION 表按鍵Virtual Key 與WM_KEYDOWN同 若訊息要被處理傳0
或 反之傳1
HC_NOREMOVE
Public hHook As Long
Public Sub UnHookKBD()
If hnexthookproc <> 0 Then
hHook = 0
End If
End Sub
Public Function EnableKBDHook()
If hHook <> 0 Then
Exit Function
End If
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
[1] 
只要將上面代碼放在VB的模塊中,用標準VB程序就可以了,當運行該程序後,就能攔截所有鍵盤操作。
參考資料