訊息鉤子

訊息鉤子

鉤子是WINDOWS中訊息處理機制的一個要點,通過安裝各種鉤子,應用程式能夠設定相應的子例程來監視系統里的訊息傳遞以及在這些訊息到達目標視窗程式之前處理它們。 鉤子的種類很多,每種鉤子可以截獲並處理相應的訊息,如鍵盤鉤子可以截獲鍵盤訊息,滑鼠鉤子可以截獲滑鼠訊息,外殼鉤子可以截獲啟動和關閉應用程式的訊息,日誌鉤子可以監視和記錄輸入事件。

簡介

若在dll中使用SetWindowsHookEx設定一全局鉤子,系統會將其載入入使用user32的進程中,因而它也可被利用為無進程木馬的進程注入手段。</CA>

Hook解釋

Hook是Windows中提供的一種用以替換DOS下“中斷”的系統機制,中文譯為“掛鈎”或“鉤子”。在對特定的系統事件進行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

UnhookWindowsHookExhHook

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

只要將上面代碼放在VB的模組中,用標準VB程式就可以了,當運行該程式後,就能攔截所有鍵盤操作。

相關詞條

熱門詞條

聯絡我們