1. 程式人生 > >HOOK鉤子機制

HOOK鉤子機制

最近在看一些程式設計相關的書籍和資料,知識碰見了,就想把它記下來,以便日後能用的上,也可能只是淺顯的概念!可能有錯,但是有值得參考的地方,慢慢充電吧!

       一、理解:鉤子,顧名思義就是鉤東西的,來一個比喻吧。當我們在釣魚的時候,只要你扔出有誘餌的魚鉤(設定執行緒鉤子或系統鉤子),此後你可能會漫長的等待(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

在此感謝博主的分享!!