HOOK鉤子機制
阿新 • • 發佈:2019-01-22
最近在看一些程式設計相關的書籍和資料,知識碰見了,就想把它記下來,以便日後能用的上,也可能只是淺顯的概念!可能有錯,但是有值得參考的地方,慢慢充電吧!
一、理解:鉤子,顧名思義就是鉤東西的,來一個比喻吧。當我們在釣魚的時候,只要你扔出有誘餌的魚鉤(設定執行緒鉤子或系統鉤子),此後你可能會漫長的等待(HOOK等待訊息或者訊號的來臨),但是一旦這條不幸的魚上鉤了(有訊息傳遞,截獲住了訊息),它就跑不了了,這條魚就任憑我們處置,我們可以選擇放生或者報餐一頓等等(對截獲的訊息進行處理,呼叫函式,阻止訊息的傳送,改變訊息都可以,要是被黑客利用感覺好危險啊)!雖然有些殘忍,但是沒辦法,達爾文進化論,物競天擇,優勝劣汰,原諒自私貪婪好吃的人類吧!這就是鉤子。鉤子(hook)就是一個Windows訊息的攔截機制
因為windows系統是建立在事件驅動的機制上,整個系統是通過訊息的傳遞來實現的,例如只有我們在點選滑鼠或者按下某個鍵時,系統才會執行相應的功能,點選滑鼠和按鍵都是一種訊息機制通知windows來做某件事(HOOKS)就是一種特殊的訊息處理機制,HOOK可以監視系統的各種事件訊息,截獲發往目標視窗的訊息進行處理。這樣我們就可以在系統中安裝自定義的鉤子,監視系統中特定事情的發生,完成相應的功能。
或者 鉤子實際上是一個處理訊息的程式段,通過系統呼叫,把它掛入系統。每當特定的訊息發出,在沒有到達目的視窗前
鉤子的種類有很多,每種鉤子可以截獲並處理相應的訊息,如鍵盤鉤子,外殼鉤子可以擷取、啟動和關閉應用程式的訊息。鉤子可以分為:執行緒鉤子和系統鉤子執行緒鉤子監視指定執行緒的事件訊息;系統鉤子監視系統中的所有執行緒的時間訊息,因為系統鉤子會影響系統中所有的應用程式,所以鉤子函式必須放在獨立的動態連結庫中;
Windows訊息帶了一些程式有用的資訊,比如Mouse類資訊,就帶有滑鼠所在窗體控制代碼、滑鼠位置等資訊(具體可參考相應的訊息定義文件),攔截了這些訊息,就可以做出例如金山詞霸一類的螢幕取詞功能。
二、鉤子的工作原理
在正確使用鉤子函式前,我們先講解鉤子函式的工作原理。當您建立一個鉤子時,WINDOWS會先在記憶體中建立一個數據結構,該資料結構包含了鉤子的相關資訊,然後把該結構體加到已經存在的鉤子連結串列中去,成為鉤子連結串列,由系統維護。新的鉤子將加到老的前面。當一個事件發生時,如果您安裝的是一個程序鉤子,您程序中的鉤子函式將被呼叫。如果是一個系統鉤子,系統就必須把鉤子函式插入到其它程序的地址空間,要做到這一點要求鉤子函式必須在一個動態連結庫中,所以如果您想要使用系統鉤子,就必須把該鉤子函式放到動態連結庫中去。一般鉤子程式和回撥函式配合使用,在接收到某一訊息時呼叫某一函式進行相應的操作。
當然有兩個例外:工作日誌鉤子和工作日誌回放鉤子。這兩個鉤子的鉤子函式必須在安裝鉤子的執行緒中,也就是必須監視每個執行緒的先後順序。
原因是:這兩個鉤子是用來監控比較底層的硬體事件的,既然是記錄和回放,所有的事件就當然都是有先後次序的。所以如果把回撥函式放在DLL中,輸入的事件被放在幾個執行緒中記錄,所以我們無法保證得到正確的次序。故解決的辦法是:把鉤子函式放到單個的執行緒中,譬如安裝鉤子的執行緒。
三、值得注意的是:
(1) 如果對於同一事件(如滑鼠訊息)既安裝了執行緒鉤子又安裝了系統鉤子,那麼系統會自動先呼叫執行緒鉤子,然後呼叫系統鉤子。
(2) 對同一事件訊息可安裝多個鉤子處理過程,這些鉤子處理過程形成了鉤子鏈。當前鉤子處理結束後應把鉤子資訊傳遞給下一個鉤子函式。
而且最近安裝的鉤子放在鏈的開始,而最早安裝的鉤子放在最後,也就是後加入的先獲得控制權,有點兒棧的意思。
(3) 鉤子特別是系統鉤子會消耗訊息處理時間,降低系統性能。只有在必要的時候才安裝鉤子,在使用完畢後要及時解除安裝。
1、建立鉤子函式,函式中通過CallNextHookEx傳遞訊息
在鉤子函式中使用,將鉤子資訊傳遞給鉤子鏈的下一個鉤子函式。原型如下:
LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam )
引數說明:
hhk -- 鉤子控制代碼。
nCode、wParam和lParam 是鉤子函式對應的入參。
2、呼叫SetWindowsHookEx建立鉤子
建立新的鉤子函式加入到鉤子鏈中,一般在鉤子程式初始化時使用.
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId)
返回值:
HHOOK -- 鉤子控制代碼,需要保留,等不使用鉤子時通過UnhookWindowsHookEx函式解除安裝鉤子
引數說明:
idHook -- 鉤子的攔截訊息型別,選擇鉤子程式的攔截範圍,具體值參考文章結尾的訊息型別
lpfn -- 訊息的回撥函式地址,一般是填函式名
hMod -- 鉤子函式所在的例項的控制代碼。對於執行緒鉤子,該引數為NULL;對於系統鉤子,該引數為鉤子函式所在的DLL控制代碼。在dll中可通過AfxInitExtensionModule(MousehookDLL, hInstance)獲得DLL控制代碼。
dwThreadId -- 鉤子所監視的執行緒的執行緒號,可通過GetCurrentThreadId()獲得執行緒號。對於全域性鉤子,該引數為NULL(或0)。
3、通過UnhookWindowsHookEx解除安裝鉤子
當不再使用鉤子時,必須及時解除安裝。簡單地呼叫函式 BOOL UnhookWindowsHookEx( HHOOK hhk)即可。
最後:鉤子攔截訊息型別
WH_CALLWNDPROC :攔截系統發向目標窗體的訊息,在目標窗體處理訊息前;
WH_CALLWNDPROCRET :在目標窗體處理完系統傳送的訊息後,攔截該訊息,訊息中包含處理返回結果;
WH_CBT :在以下事件之前,系統都會呼叫WH_CBT Hook子程,這些事件包括:
(1). 啟用,建立,銷燬,最小化,最大化,移動,改變尺寸等視窗事件;
(2). 完成系統指令;
(3). 來自系統訊息佇列中的移動滑鼠,鍵盤事件;
(4). 設定輸入焦點事件;
(5). 同步系統訊息佇列事件。
鉤子函式的返回值確定系統是否允許或者防止這些操作中的一個。
其他資料參考:
http://blog.csdn.net/astraylinux/article/details/8223256
http://blog.csdn.net/mingojiang/article/details/7908818
在此感謝博主的分享!!