VC里面的钩子程序HOOK
?
引言
Windows操作系統是建立在事件驅動機制之上的,系統各部分之間的溝通也都是通過消息的相互傳遞而實現的。但在通常情況下,應用程序只能處理來自進程內部的消息或是從其他進程發過來的消息,如果需要對在進程外傳遞的消息進行攔截處理就必須采取一種被稱為HOOK(鉤子)的技術。鉤子是Windows操作系統中非常重要的一種系統接口,用它可以輕松截獲并處理在其他應用程序之間傳遞的消息,并由此可以完成一些普通應用程序難以實現的特殊功能。基于鉤子在消息攔截處理中的強大功能,本文即以VC++ 6.0為編程背景對鉤子的基本概念及其實現過程展開討論。為方便理解,在文章最后還給出了一個簡單的有關鼠標鉤子的應用示例。
鉤子的基本原理
鉤子的本質是一段用以處理系統消息的程序,通過系統調用,將其掛入到系統。鉤子的種類有很多,每一種鉤子負責截獲并處理相應的消息。鉤子機制允許應用程序截獲并處理發往指定窗口的消息或特定事件,其監視的窗口即可以是本進程內的也可以是由其他進程所創建的。在特定的消息發出,并在到達目的窗口之前,鉤子程序先行截獲此消息并得到對其的控制權。此時在鉤子函數中就可以對截獲的消息進行各種修改處理,甚至強行終止該消息的繼續傳遞。
任何一個鉤子都由系統來維護一個指針列表(鉤子鏈表),其指針指向鉤子的各個處理函數。最近安裝的鉤子放在鏈的開始,最早安裝的鉤子則放在最后,當鉤子監視的消息出現時,操作系統調用鏈表開始處的第一個鉤子處理函數進行處理,也就是說最后加入的鉤子優先獲得控制權。在這里提到的鉤子處理函數必須是一個回調函數(callback function),而且不能定義為類成員函數,必須定義為普通的C函數。在使用鉤子時可以根據其監視范圍的不同將其分為全局鉤子和線程鉤子兩大類,其中線程鉤子只能監視某個線程,而全局鉤子則可對在當前系統下運行的所有線程進行監視。顯然,線程鉤子可以看作是全局鉤子的一個子集,全局鉤子雖然功能強大但同時實現起來也比較煩瑣:其鉤子函數的實現必須封裝在動態鏈接庫中才可以使用。
鉤子的安裝與卸載
由于全局鉤子具有相當的廣泛性而且在功能上完全覆蓋了線程鉤子,因此下面就主要對應用較多的全局鉤子的安裝與使用進行討論。前面已經提過,操作系統是通過調用鉤子鏈表開始處的第一個鉤子處理函數而進行消息攔截處理的。因此,為了設置鉤子,只需將回調函數放置于鏈首即可,操作系統會使其首先被調用。在具體實現時由函數SetWindowsHookEx()負責將回調函數放置于鉤子鏈表的開始位置。 SetWindowsHookEx()函數原型聲明如下:
HHOOK SetWindowsHookEx(int idHook;
HOOKPROC lpfn;
HINSTANCE hMod;
DWORD dwThreadId);
其中:參數idHook 指定了鉤子的類型,總共有如下13種:
WH_CALLWNDPROC 系統將消息發送到指定窗口之前的"鉤子"
WH_CALLWNDPROCRET 消息已經在窗口中處理的"鉤子"
WH_CBT 基于計算機培訓的"鉤子"
WH_DEBUG 差錯"鉤子"
WH_FOREGROUNDIDLE 前臺空閑窗口"鉤子"
WH_GETMESSAGE 接收消息投遞的"鉤子"
WH_JOURNALPLAYBACK 回放以前通過WH_JOURNALRECORD"鉤子"記錄的輸入消息
WH_JOURNALRECORD 輸入消息記錄"鉤子"
WH_KEYBOARD 鍵盤消息"鉤子"
WH_MOUSE 鼠標消息"鉤子"
WH_MSGFILTER 對話框、消息框、菜單或滾動條輸入消息"鉤子"
WH_SHELL 外殼"鉤子"
WH_SYSMSGFILTER 系統消息"鉤子"
參數lpfn為指向鉤子處理函數的指針,即回調函數的首地址;參數hMod則標識了鉤子處理函數所處模塊的句柄;第四個參數dwThreadId 指定被監視的線程,如果明確指定了某個線程的ID就只監視該線程,此時的鉤子即為線程鉤子;如果該參數被設置為0,則表示此鉤子為監視系統所有線程的全局鉤子。此函數在執行完后將返回一個鉤子句柄。
雖然對于線程鉤子并不要求其象全局鉤子一樣必須放置于動態鏈接庫中,但是推薦其也在動態鏈接庫中實現。因為這樣的處理不僅可使鉤子可為系統內的多個進程訪問,也可以在系統中被直接調用,而且對于一個只供單進程訪問的鉤子,還可以將其鉤子處理過程放在安裝鉤子的同一個線程內,此時SetWindowsHookEx()函數的第三個參數也就是該線程的實例句柄。
在SetWindowsHookEx()函數完成對鉤子的安裝后,如果被監視的事件發生,系統馬上會調用位于相應鉤子鏈表開始處的鉤子處理函數進行處理,每一個鉤子處理函數在進行相應的處理時都要考慮是否需要把事件傳遞給下一個鉤子處理函數。如果要傳遞,就通過函數CallNestHookEx()來解決。盡管如此,在實際使用時還是強烈推薦無論是否需要事件傳遞而都在過程的最后調用一次 CallNextHookEx( )函數,否則將會引起一些無法預知的系統行為或是系統鎖定。該函數將返回位于鉤子鏈表中的下一個鉤子處理過程的地址,至于具體的返回值類型則要視所設置的鉤子類型而定。該函數的原型聲明如下:
LRESULT CallNextHookEx(HHOOK hhk;int nCode;WPARAM wParam;LPARAM lParam);
其中,參數hhk為由SetWindowsHookEx()函數返回的當前鉤子句柄;參數nCode為傳給鉤子過程的事件代碼;參數wParam和lParam 則為傳給鉤子處理函數的參數值,其具體含義同設置的鉤子類型有關。
最后,由于安裝鉤子對系統的性能有一定的影響,所以在鉤子使用完畢后應及時將其卸載以釋放其所占資源。釋放鉤子的函數為UnhookWindowsHookEx(),該函數比較簡單只有一個參數用于指定此前由SetWindowsHookEx()函數所返回的鉤子句柄,原型聲明如下:
BOOL UnhookWindowsHookEx(HHOOK hhk);
總結
以上是生活随笔為你收集整理的VC里面的钩子程序HOOK的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unity 原生版本管理工具Versio
- 下一篇: 如何用3DsMax制作笔记本电脑