原文地址:http://blog.csdn.net/g200407331/article/details/50982025
一、什麼是鉤子 我們可以首先從字面上瞭解鉤子,鉤子是幹什麼的呢。日常生活中,我們的鉤子是用來鉤住某種東西的,比如,說,魚鉤是用來釣魚的,一旦魚咬了鉤,鉤子就一直鉤住魚了,任憑魚在水裡怎麼遊,也逃不出魚鉤的控制。同樣的,Windows的鉤子Hook也是用來鉤東西的,比較抽象的是他是用來鉤Windows事件或者訊息的。最常見的就是滑鼠和鍵盤鉤子,用Hook鉤子鉤住滑鼠、鍵盤,當你的滑鼠、鍵盤有任何操作時,通過Hook就能知道他們都做了什麼了,多麼形象啊,把老鼠Mouse鉤住了,不管你幹什麼,都逃不過我鉤子Hook的手掌心。 技術上講,鉤子(Hook)是Windows訊息處理機制的一個很重要的內容,誰叫Windows是基於訊息的呢。應用程式可以通過鉤子機制截獲處理Window訊息或是其他一些特定事件。 我們可以在同一個鉤子上掛很多東西。 想起參加工作前要求被體檢的時候,當你被登記之後,按照你的登記表上的順序,就等著到各個科室一個一個的去檢查吧。每一個科室都有決定你是否繼續的可能,只有通過了這個,你才可以到下一個去,如果沒有通過,那麼,你是看不到最後的大夫了,可以直接over回家了。 如果把體檢比喻為事件的話,當事件發生時,應用程式(體檢過程)可以在相應的鉤子Hook上設定多個鉤子子程式(Hook Procedures)(多個科室的檢查),由其組成一個與鉤子相關聯的指向鉤子函數的指標列表(鉤子鏈表)(體檢表,確定了你要走的順序)。當鉤子所監視的訊息出現時(你拿著表格來體檢了),Windows(導診員)首先將其送到調用鏈表中所指向的第一個鉤子函數中(體檢表上第一個科室,一般是身高體重吧,呵呵),鉤子函數將根據其各自的功能(每個科室檢查的項目不一樣啊)對訊息進行監視(有的大夫就隨便看看了事),、修改(碰到好心的大夫還可以幫你往好裡添點呢,呵呵)和控制(有的大夫好嚴格啊),並在處理完成後(當然有的大夫就直接把你刷下了,回家吧,沒有下一個了)把訊息傳遞給下一鉤子函數(下一個項目的科室,當然,也可以強制訊息的傳遞,直接打發你回家)直至到達鉤子鏈表的末尾(檢查完了。)。在鉤子函數交出控制權後,被攔截的訊息最終仍將交還給視窗處理函數(好了,拿著表去上班吧)。 雖然鉤子函數對訊息的過濾將會略加影響系統的運行效率,但在很多場合下通過鉤子對訊息的過濾處理可以完成一些其他方法所不能完成的特殊功能。
二、比較專業的對鉤子的技術性理解
鉤子(Hook),是Windows訊息處理機制的一個平台,應用程式可以在上面設定子程以監視指定視窗的某種訊息,而且所監視的視窗可以是其他進程所建立的。當訊息到達後,在目標視窗處理函數之前處理它。鉤子機制允許應用程式截獲處理window訊息或特定事件。
Windows系統是建立在事件驅動的機制上的,說穿了就是整個系統都是通過訊息的傳遞來實現的。而鉤子是Windows系統中非常重要的系統介面,用它可以截獲並處理送給其他應用程式的訊息,來完成普通應用程式難以實現的功能。鉤子可以監視系統或進程中的各種事件訊息,截獲發往目標視窗的訊息並進行處理。這樣,我們就可以在系統中安裝自訂的鉤子,監視系統中特定事件的發生,完成特定的功能,比如截獲鍵盤、滑鼠的輸入,螢幕取詞,日誌監視等等。可見,利用鉤子可以實現許多特殊而有用的功能。
鉤子實際上是一個處理訊息的程式段,通過系統調用,把它掛入系統。每當特定的訊息發出,在沒有到達目的視窗前,鉤子程式就先捕獲該訊息,亦即鉤子函數先得到控制權。這時鉤子函數即可以加工處理(改變)該訊息,也可以不作處理而繼續傳遞該訊息,還可以強制結束訊息的傳遞。
一個Hook都有一個與之相關聯的指標列表,稱之為鉤子鏈表,由系統來維護。這個列表的指標指向指定的,應用程式定義的,被Hook子程調用的回呼函數,也就是該鉤子的各個處理子程。當與指定的Hook類型關聯的訊息發生時,系統就把這個訊息傳遞到Hook子程。一些Hook子程可以只監視訊息,或者修改訊息,或者停止訊息的前進,避免這些訊息傳遞到下一個Hook子程或者目的視窗。最近安裝的鉤子放在鏈的開始,而最早安裝的鉤子放在最後,也就是後加入的先獲得控制權。 zdwork.cn
Windows 並不要求鉤子子程的卸載順序一定得和安裝順序相反。每當有一個鉤子被卸載,Windows 便釋放其佔用的記憶體,並更新整個Hook鏈表。如果程式安裝了鉤子,但是在尚未卸載鉤子之前就結束了,那麼系統會自動為它做卸載鉤子的操作。
大多數人或者網上文章認為全域鉤子都要依賴於一個DLL才能正常工作的,常常會看到很多人在論壇上長期爭論一個話題:“全域鉤子一定要在DLL裡面嗎。”。實際上這裡有一個概念的問題,究竟上面提到的全域鉤子是指什麼。通過對上面各種鉤子的範圍的理解就會發現這個問題的答案。 本文來自智動軟體zdwork.cn
上面一共提到了15種鉤子,他們的範圍請看下錶:
Hook
Scope
WH_CALLWNDPROC
Thread or global
WH_CALLWNDPROCRET
Thread or global
WH_CBT
Thread or global
WH_DEBUG
Thread or global
WH_FOREGROUNDIDLE
Thread or global
WH_GETMESSAGE
Thread or global
WH_JOURNALPLAYBACK
Global only
WH_JOURNALRECORD
Global only
WH_KEYBOARD
Thread or global
WH_KEYBOARD_LL
Global only
WH_MOUSE
Thread or global
WH_MOUSE_LL
Global only
WH_MSGFILTER
Thread or global
WH_SHELL
Thread or global
WH_SYSMSGFILTER
Global only
表一:鉤子範圍
WH_JOURNALPLAYBACK,WH_JOURNALRECORD,WH_KEYBOARD_LL,WH_MOUSE_LL、WH_SYSMSGFILTER這5種鉤子本身的範圍就是全域的,不管鉤子是直接寫在應用程式的代碼裡還是放在DLL中,他們都能夠鉤住系統的訊息。剩下的10種鉤子,他們的範圍既可以是線程的又可以是全域的,當將相應的鉤子直接寫在應用程式的代碼中時,他們只能捕獲當前線程內容相關的訊息。那麼他們如何?捕獲全域訊息的功能呢。當把鉤子寫入到一個單獨的DLL中再引用後,系統自動將該DLL映射到受鉤子函數影響的所有進程的地址空間中,即將這個DLL注入了那些進程,從而達到捕獲全域訊息的目的。相對來說,前面5種鉤子本身就是全域的,是不需要注入的。 智動軟體
因此,對於前面問題的答案就是:要實現捕獲全域訊息功能的鉤子,是否要寫在單獨的DLL裡面,取決於鉤子的類型以及相應的範圍。 系統必須要處理每個訊息,而鉤子的使用增加了系統對每個訊息要執行的處理的數量,因此,鉤子會減慢系統。應該僅僅在必須的時候才安裝鉤子,並且儘可能早的將其卸載掉。
三、Hook Chain(鉤子鏈表)
系統支援很多不同種類的鉤子,每種類型提供對訊息處理機制裡的某一不同方面的訪問。例如,應用程式可以使用WH_MOUSE Hook監視滑鼠訊息的傳遞。
系統為每類鉤子維護著一個獨立的鉤子鏈表。鉤子鏈表是一個指標的列表,其中的指標指向特定的、應用程式定義的回呼函數,該函數被叫做鉤子子程(hook procedure)。當與某種特定類型的鉤子相關聯(鉤住)的訊息發生時,系統將訊息一個接一個地傳遞給鉤子鏈中的每一個鉤子子程(hook procedure),鉤子子程能夠採取的動作取決於涉及的鉤子的類型。某些類型的鉤子子程僅僅能監視訊息;另外一些就能夠修改訊息或者終止訊息在鉤子鏈表中的前進,這樣就阻止了訊息到達下一個鉤子子程或者目標表單。
這裡有幾個概念上的翻譯,主要有:
Hook Chain : 鉤子鏈表
hook procedures : 鉤子子程(即得到訊息後進行處理的程式段)
如果對於同一事件既安裝了線程勾子又安裝了全域勾子,那麼系統會自動先調用線程勾子,然後調用全域勾子。
最近學習hook,看了幾個教程:
1)http://blog.sina.com.cn/s/articlelist_1585708262_3_1.html
2)http://www.lellansin.com/windows-api-%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89-hook-%E9%92%A9%E5%AD%90%E7%9B%91%E5%90%AC%EF%BC%88%E7%BC%96%E5%86%99%E4%B8%AD%EF%BC%89.html
3)http://blog.csdn.NET/camly/article/details/1752798