API HOOK解釋
在windows系統下編程,應該會接觸到api函式的使用,常用的api函式大概有2000個左右。今天隨著控制項,stl等高效編程技術的出現,api的使用機率在普通的用戶程式上就變得越來越小了。當諸如控制項這些現成的手段不能實現的功能時,我們還需要藉助api。最初有些人對某些api函式的功能不太滿意,就產生了如何修改這些api,使之更好的服務於程式的想法,這樣api hook就自然而然的出現了。我們可以通過api hook,改變一個系統api的原有功能。基本的方法就是通過hook“接觸”到需要修改的api函式入口點,改變它的地址指向新的自定義的函式。api hook並不屬於msdn上介紹的13類hook中的任何一種。所以說,api hook並不是什麼特別不同的hook,它也需要通過基本的hook提高自己的許可權,跨越不同進程間訪問的限制,達到修改api函式地址的目的。對於自身進程空間下使用到的api函式地址的修改,是不需要用到api hook技術就可以實現的。
API HOOK和PE檔案的關係
api hook技術的難點,並不在於hook技術,而在於對PE結構的學習和理解。如何修改api函式的入口地址?這就需要學習pe執行檔(.exe,.dll等)如何被系統映射到進程空間中,這需要學習pe格式的基本知識。windows已經提供了很多數據結構struct幫助我們訪問pe格式,記住它們,我們就不要自己計算格式的具體位元組位置這些繁瑣的細節。但是從api hook的實現來看,pe格式的訪問部分仍然是整個編程實現中最複雜的一部分,對於經常crack的朋友不在此列。
假設我們已經了解了pe格式,那么我們在哪裡修改api的函式入口點比較合適呢?這個就是輸入符號表imported symbols table(間接)指向的輸入符號地址。
下面對於pe格式的介紹這一部分,學習了pe格式後再看這些就很容易了。
pe格式的基本組成:
DOS檔案頭 | 以4D5A的16進制即MZ開頭 |
PE檔案頭 | 以50450000的PE00開頭 |
可選頭檔案 | 包含下面的數據目錄 |
數據目錄 | 函式入口地址,基地址,記憶體,檔案對齊粒度之類信息 |
節表 | 維護一個所有節的信息 |
節表1 | 具有同類特徵的信息,檔案的主體部分 |
節表2 | |
... | |
節表n |
我們需要從“可選頭”尾的“數據目錄”數組中的第二個元素——輸入符號表的位置,它是一個IMAGE_DATA_DIRECTORY結構,從它中的VirtualAddress地址,“順藤摸瓜”找到api函式的入口地點。
簡單說明如下:
OriginalFirstThunk 指向IMAGE_THUNK_DATA結構數組,為方便只畫了數組的一個元素,AddressOfData 指向IMAGE_IMPORT_BY_NAME結構。
IMAGE_IMPORT_DESCRIPTOR數組:每個引入的dll檔案都對應數組中的一個元素,以全0的元素(20個bytes的0)表示數組的結束
IMAGE_THUNK_DATA32數組:同一組的以全0的元素(4個bytes的0)表示數組的結束,每個元素對應一個IMAGE_IMPORT_BY_NAME結構
IMAGE_IMPORT_BY_NAME:如..@Consts@initialization$qqrv. 表示
Unmangled Borland C++ Function: qualified function __fastcall Consts::initialization()
如果PE檔案從kernel32.dll中引入10個函式,那么IMAGE_IMPORT_DESCRIPTOR 結構的 Name1域包含指向字元串"kernel32.dll"的RVA,同時每個IMAGE_THUNK_DATA 數組有10個元素。(RVA是指相對地址,每一個執行檔在載入到記憶體空間前,都以一個基址作為起點,其他地址以基址為準,均以相對地址表示。這樣系統載入程式到不同的記憶體空間時,都可以方便的算出地址)
上述這些結構可以在winnt.h,ImageHlp.h頭檔案里查到。
Hook解釋
Hook是Windows中提供的一種用以替換DOS下“中斷”的系統機制,中文譯為“掛鈎”或“鉤子”。在對特定的系統事件進行hook後,一旦發生已hook事件,對該事件進行hook的程式就會受到系統的通知,這時程式就能在第一時間對該事件做出回響。
另一解釋:鉤子(Hook),是Windows訊息處理機制的一個平台,應用程式可以在上面設定子程以監視指定視窗的某種訊息,而且所監視的視窗可以是其他進程所創建的。當訊息到達後,在目標視窗處理函式之前處理它。鉤子機制允許應用程式截獲處理window訊息或特定事件。
鉤子實際上是一個處理訊息的程式段,通過系統調用,把它掛入系統。每當特定的訊息發出,在沒有到達目的視窗前,鉤子程式就先捕獲該訊息,亦即鉤子函式先得到控制權。這時鉤子函式即可以加工處理(改變)該訊息,也可以不作處理而繼續傳遞該訊息,還可以強制結束訊息的傳遞。
Hook原理
每一個Hook都有一個與之相關聯的指針列表,稱之為鉤子鍊表,由系統來維護。這個列表的指針指向指定的,應用程式定義的,被Hook子程調用的回調函式,也就是該鉤子的各個處理子程。當與指定的Hook類型關聯的訊息發生時,系統就把這個訊息傳遞到Hook子程。一些Hook子程可以只監視訊息,或者修改訊息,或者停止訊息的前進,避免這些訊息傳遞到下一個Hook子程或者目的視窗。最近安裝的鉤子放在鏈的開始,而最早安裝的鉤子放在最後,也就是後加入的先獲得控制權。
Windows 並不要求鉤子子程的卸載順序一定得和安裝順序相反。每當有一個鉤子被卸載,Windows 便釋放其占用的記憶體,並更新整個Hook鍊表。如果程式安裝了鉤子,但是在尚未卸載鉤子之前就結束了,那么系統會自動為它做卸載鉤子的操作。
鉤子子程是一個應用程式定義的回調函式(CALLBACK Function),不能定義成某個類的成員函式,只能定義為普通的C函式。用以監視系統或某一特定類型的事件,這些事件可以是與某一特定執行緒關聯的,也可以是系統中所有執行緒的事件。
系統鉤子與執行緒鉤子
SetWindowsHookEx()函式的最後一個參數決定了此鉤子是系統鉤子還是執行緒鉤子。
執行緒鉤子用於監視指定執行緒的事件訊息。執行緒鉤子一般在當前執行緒或者當前執行緒派生的執行緒內。
系統鉤子監視系統中的所有執行緒的事件訊息。因為系統鉤子會影響系統中所有的應用程式,所以鉤子函式必須放在獨立的動態程式庫(DLL) 中。系統自動將包含“鉤子回調函式”的DLL映射到受鉤子函式影響的所有進程的地址空間中,即將這個DLL注入了那些進程。
幾點說明:
(1)如果對於同一事件(如滑鼠訊息)既安裝了執行緒鉤子又安裝了系統鉤子,那么系統會自動先調用執行緒鉤子,然後調用系統鉤子。
(2)對同一事件訊息可安裝多個鉤子處理過程,這些鉤子處理過程形成了鉤子鏈。當前鉤子處理結束後應把鉤子信息傳遞給下一個鉤子函式。
(3)鉤子特別是系統鉤子會消耗訊息處理時間,降低系統性能。只有在必要的時候才安裝鉤子,在使用完畢後要及時卸載。
Hook的套用模式
觀察模式
最為常用,像Windows提供的SetWindowHook就是典型地為這類套用準備的。而且這也是最普遍的用法。這個模式的特點是,在事情發生的時候,發出一個通知信息。觀察者只可以查看過程中的信息,根據自己關心的內容處理自己的業務,但是不可以更改原來的流程。
如全局鉤子中,經常使用的滑鼠訊息、鍵盤訊息的監視等套用。金山詞霸螢幕取詞的功能是一個典型的套用(具體技術可以參考此類文章)。
注入模式
這個模式和觀察模式最大的不一樣的地方在於,注入的代碼是為了擴展原始代碼的功能業務。外掛程式模式是此類模式的典型案例.不管瘦核心的外掛程式系統(如Eclipse)還是胖核心的外掛程式系統(如Delphi、Visual Studio等IDE環境),其對外提供的外掛程式接口都是為了擴展本身系統的功能的.這種擴展的套用方式的典型特點,就是新的擴展代碼和原來的代碼會協調處理同類業務。
替換模式
如果針對套用目的不同,可以叫修復模式或破解模式。前者是為了修改系統中的BUG,後者是為了破解原有系統的限制。很多黑客使用此種模式,將訪問加密鎖的DLL中的導出表,替換成自己的函式,這樣跳過對軟體的控制代碼。這類套用的難點是,找出函式的參數。這類模式的特點是,原有的代碼會被新的代碼所替換。
前面三個是基本模式,還有很多和實際套用相關的模式。
集權模式
此類模式的出現,大都是為了在全部系統中,統一處理某類事情。它的特點不在於注入的方式,而在於處理的模式。這個模式,大都套用到某類服務上,比如鍵盤服務,滑鼠服務,印表機服務等等特定服務上。通過統一接管此類服務的訪問,限制或者協調對服務的訪問。比如鍵盤鎖功能的實現,就是暫時關閉鍵盤的所有套用。這類模式的特點主要會和特點服務有關聯。
修復模式
替換模式的一種,這裡強調的是其套用的目的是為了修復或擴展原有系統的功能。
破解模式
替換模式的一種,這裡強調的是其套用的目的是為了跳過原有系統的一部分代碼。如加密檢測代碼,網路檢測代碼等等。
外掛程式模式
注入模式的一種,在系統的內部直接依靠HOOK機制進行擴展業務功能。
共享模式
這類套用中,經常是為了獲取對方的數據。必然我希望獲取對方系統中,所有字元串的值。可以通過替換對方的記憶體管理器,導出所有字元串。這個套用比較特殊。不過其特點在於,目的是達到系統之間的數據共享。其實現,可能是觀察模式,也可能是替換模式。
在VB6.0中的聲明
公有聲明:Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
私有聲明:Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long