hook函數教程(一)什么是鈎子


一、什么是鈎子  

我們可以首先從字面上了解鈎子,鈎子是干什么的呢?日常生活中,我們的鈎子是用來鈎住某種東西的,比如,說,魚鈎是用來釣魚的,一旦魚咬了鈎,鈎子就一直鈎住魚了,任憑魚在水里怎么游,也逃不出魚鈎的控制。同樣的,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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM