基本概念
鉤子實際上是一個處理訊息的程式段,通過系統調用,把它掛入系統。每當特定的訊息發出,在沒有到達目的視窗前,鉤子程式就先捕獲該訊息,亦即鉤子函式先得到控制權。這時鉤子函式即可以加工處理(改變)該訊息,也可以不作處理而繼續傳遞該訊息,還可以強制結束訊息的傳遞。鉤子也可以理解為WINDOWS留給我們的後門,比如你想控制鍵盤,在DOS時代很簡單通過INT即可,而WINDOWS時代不允許我們直接操作硬體;由於WINDOWS是訊息驅動,所以我們可以攔截鍵盤訊息以達到控制鍵盤的目的。但是控制自己進程的訊息固然很簡單,要控制所有進程訊息要利用鉤子了。將鉤子函式放在DLL中,所有的有關鍵盤的訊息都必須經過鉤子函式過濾,這樣你就可以為所欲為了。
WINDOWS下的鉤子程式就像DOS下的TSR(記憶體駐留程式)一樣,用來截獲WINDOWS下的
特定的訊息,進行相應的處理。比如可以截獲鍵盤輸入的訊息,來獲得鍵盤輸入的信息等。鉤子程式可以通過API調用來駐留和脫鉤。
運行機制
每一個Hook(鉤子)都有一個與之相關聯的指針列表,稱之為鉤子鍊表,由系統來維護。這個列表的指針指向指定的,應用程式定義的,被Hook子程調用的回調函式,也就是該鉤子的各個處理子程。當與指定的Hook類型關聯的訊息發生時,系統就把這個訊息傳遞到Hook子程。 一些Hook子程可以只監視訊息,或者修改訊息,或者停止訊息的前進,避免這些訊息傳遞到下一個Hook子程或者目的視窗。最近安裝的鉤子放在鏈的開始, 而最早安裝的鉤子放在最後,也就是後加入的先獲得控制權。Windows 並不要求鉤子子程的卸載順序一定得和安裝順序相反。每當有一個鉤子被卸載,Windows 便釋放其占用的記憶體,並更新整個Hook鍊表。如果程式安裝了鉤子,但是在尚未卸載鉤子之前就結束了,那么系統會自動為它做卸載鉤子的操作。
鉤子的分類
一. 按事件分類
有如下的幾種常用類型(1) 鍵盤鉤子和低級鍵盤鉤子可以監視各種鍵盤訊息。
(2) 滑鼠鉤子和低級滑鼠鉤子可以監視各種滑鼠訊息。
(3) 外殼鉤子可以監視各種Shell事件訊息。比如啟動和關閉應用程式。
(4) 日誌鉤子可以記錄從系統訊息佇列中取出的各種事件訊息。
(5) 視窗過程鉤子監視所有從系統訊息佇列發往目標視窗的訊息。
此外,還有一些特定事件的鉤子提供給我們使用,不一一列舉。
二. 按使用範圍分類
主要有執行緒鉤子和系統鉤子(1) 執行緒鉤子監視指定執行緒的事件訊息。
(2) 系統鉤子監視系統中的所有執行緒的事件訊息。因為系統鉤子會影響系統中所有的應用程式,所以鉤子函式必須放在獨立的動態程式庫(DLL)
中。這是系統鉤子和執行緒鉤子很大的不同之處。
幾點需要說明的地方:
(1) 如果對於同一事件(如滑鼠訊息)既安裝了執行緒鉤子又安裝了系統鉤子,那么系統會自動先調用執行緒鉤子,然後調用系統鉤子。
(2) 對同一事件訊息可安裝多個鉤子處理過程,這些鉤子處理過程形成了鉤子鏈。當前鉤子處理結束後應把鉤子信息傳遞給下一個鉤子函式。而且最近安裝的鉤子放在鏈的開始,而最早安裝的鉤子放在最後,也就是後加入的先獲得控制權。
(3) 鉤子特別是系統鉤子會消耗訊息處理時間,降低系統性能。只有在必要的時候才安裝鉤子,在使用完畢後要及時卸載。
常用鉤子的類型
1、WH_CALLWNDPROC
1、WH_CALLWNDPROC和WH_CALLWNDPROCRET HooksWH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以監視傳送到視窗過程的訊息。系統在訊息傳送到接收視窗過程之前調用WH_CALLWNDPROC Hook子程,並且在視窗過程處理完訊息之後調用WH_CALLWNDPROCRET Hook子程。
WH_CALLWNDPROCRET Hook傳遞指針到CWPRETSTRUCT結構,再傳遞到Hook子程。CWPRETSTRUCT結構包含了來自處理訊息的視窗過程的返回值,同樣也包括了與這個訊息關聯的訊息參數。
2、WH_CBT Hook
在以下事件之前,系統都會調用WH_CBT Hook子程,這些事件包括:1. 激活,建立,銷毀,最小化,最大化,移動,改變尺寸等視窗事件;
2. 完成系統指令;
3. 來自系統訊息佇列中的移動滑鼠,鍵盤事件;
4. 設定輸入焦點事件;
5. 同步系統訊息佇列事件。
Hook子程的返回值確定系統是否允許或者防止這些操作中的一個。
3、WH_DEBUG Hook
在系統調用系統中與其他Hook關聯的Hook子程之前,系統會調用WH_DEBUG Hook子程。你可以使用這個Hook來決定是否允許系統調用與其他Hook關聯的Hook子程。4、WH_FOREGROUNDIDLE Hook
當應用程式的前台執行緒處於空閒狀態時,可以使用WH_FOREGROUNDIDLE Hook執行低優先權的任務。當應用程式的前台執行緒大概要變成空閒狀態時,系統就會調用WH_FOREGROUNDIDLE Hook子程。5、WH_GETMESSAGE Hook
應用程式使用WH_GETMESSAGE Hook來監視從GetMessage or PeekMessage函式返回的訊息。你可以使用WH_GETMESSAGE Hook去監視滑鼠和鍵盤輸入,以及其他傳送到訊息佇列中的訊息。6、WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook使應用程式可以插入訊息到系統訊息佇列。可以使用這個Hook回放通過使用WH_JOURNALRECORD Hook記錄下來的連續的滑鼠和鍵盤事件。只要WH_JOURNALPLAYBACK Hook已經安裝,正常的滑鼠和鍵盤事件就是無效的。WH_JOURNALPLAYBACK Hook是全局Hook,它不能象執行緒特定Hook一樣使用。 WH_JOURNALPLAYBACK Hook返回逾時值,這個值告訴系統在處理來自回放Hook當前訊息之前需要等待多長時間(毫秒)。這就使Hook可以控制實時事件的回放。
WH_JOURNALPLAYBACK是system-wide local hooks,它們不會被注射到任何行程位址空間。(估計按鍵精靈是用這個hook做的)
7、WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook用來監視和記錄輸入事件。典型的,可以使用這個Hook記錄連續的滑鼠和鍵盤事件,然後通過使用WH_JOURNALPLAYBACK Hook來回放。WH_JOURNALRECORD Hook是全局Hook,它不能象執行緒特定Hook一樣使用。
WH_JOURNALRECORD是system-wide local hooks,它們不會被注射到任何行程位址空間。
8、WH_KEYBOARD Hook
在應用程式中,WH_KEYBOARD Hook用來監視WM_KEYDOWN and WM_KEYUP訊息,這些訊息通過GetMessage or PeekMessage function返回。可以使用這個Hook來監視輸入到訊息佇列中的鍵盤訊息。9、WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook監視輸入到執行緒訊息佇列中的鍵盤訊息。10、WH_MOUSE Hook
WH_MOUSE Hook監視從GetMessage 或者 PeekMessage 函式返回的滑鼠訊息。使用這個Hook監視輸入到訊息佇列中的滑鼠訊息。11、WH_MOUSE_LL Hook
WH_MOUSE_LL Hook監視輸入到執行緒訊息佇列中的滑鼠訊息。12、WH_MSGFILTER / hook
12、WH_MSGFILTER 和 WH_SYSMSGFILTER HooksWH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我們可以監視選單,滾動條,訊息框,對話框訊息並且發現用戶使用ALT+TAB or ALT+ESC 組合鍵切換視窗。
WH_MSGFILTER Hook只能監視傳遞到選單,滾動條,訊息框的訊息,以及傳遞到通過安裝了Hook子程的應用程式建立的對話框的訊息。
WH_SYSMSGFILTER Hook監視所有應用程式訊息。
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我們可以在模式循環期間過濾訊息,這等價於在主訊息循環中過濾訊息。通過調用CallMsgFilter function可以直接的調用WH_MSGFILTER Hook。通過使用這個函式,應用程式能夠在模式循環期間使用相同的代碼去過濾訊息,如同在主訊息循環里一樣。
13、WH_SHELL Hook
外殼應用程式可以使用WH_SHELL Hook去接收重要的通知。當外殼應用程式是激活的並且當頂層視窗建立或者銷毀時,系統調用WH_SHELL Hook子程。WH_SHELL 共有5鍾情況:
1. 只要有個top-level、unowned 視窗被產生、起作用、或是被摧毀;
2. 當Taskbar需要重畫某個按鈕;
3. 當系統需要顯示關於Taskbar的一個程式的最小化形式;
4. 當目前的鍵盤布局狀態改變;
5. 當使用者按Ctrl+Esc去執行Task Manager(或相同級別的程式)。
按照慣例,外殼應用程式都不接收WH_SHELL訊息。所以,在應用程式能夠接收WH_SHELL訊息之前,應用程式必須調用SystemParametersInfo function註冊它自己。