天天看點

通過Hook将DLL注入程序

首先,讀這篇文章之前,預設已經掌握了程序位址空間,dll加載,windows Hook技術。

1. 為什麼需要dll注入?

如果一個程序的程式是我們自己編寫的,我們可以在程式中隐式或者顯式地加載需要的dll,不需要dll注入。但是,當一個程序的程式不是我們編寫的,而我們又需要該程式加載指定的dll,以便進行某些操作,這是就需要dll注入。

我們知道,dll可以被多個程序加載,當一個程序加載dll時,dll被映射到該程序的位址空間。dll注入的最大目的,進入目标程序的位址空間,這樣就可以操作目标程序中的對象了。

2. 通過Hook将dll注入程序

Hook技術是基于windows消息機制的。如果給某個消息安裝了Hook,當該消息發生時,會先調用Hook函數。下面是設定Hook的函數原型:

HHOOK WINAPI SetWindowsHookEx(
  _In_  int idHook,
  _In_  HOOKPROC lpfn,
  _In_  HINSTANCE hMod,
  _In_  DWORD dwThreadId
);
           

該函數的詳細細節可以參考msdn:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx

第一個參數idHook,表示要安裝的Hook的類型,即我們要在哪個消息上安裝Hook,也可以了解為消息類型。

第二個參數lpfn,是一個函數指針,即視窗處理idHook指定類型的消息時,先調用該函數。

第三個參數hMod,lpfn函數所在的子產品,即lpfn所在dll的句柄。

第四個參數dwThreadId,需要在哪個線程上安裝Hook。如果為0,則在所有線程上安裝。注意dwThreadId是系統級變量,也就說可以是任何程序中的任何線程。

通過以上函數安裝Hook後,對整個系統大緻産生如下效果:當Id為dwThreadId的線程(當dwThreadId=0時,指系統中所有線程)中有消息類型為idHood的消息需要處理時,先調用hMod子產品中的lpfn函數。

現在我們需要應對以下情景:我們需要将MyDll.dll注入到程序B中。注入之前,我們要确定程序B中使用了windows消息,因為我們即将采用Hook的方法來注入dll,如果程序B中沒有消息,就不會調用Hook函數,無法注入。我們在MyDll.dll中export了GetMsgProc函數,該函數将被作為Hook函數。注入工作在我們自己編寫的程式中完成,我們自己變成的程式為程序A。需要涉及到:程序A、程序B、MyDll.dll、GetMsgProc。

由于程序A是我們自己編寫的,是以程序A可以載入MyDll.dll,假設載入後的子產品句柄為hInstDll。于是在程序A中可以使用SetWindowsHookEx函數了,

HHook hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hInstDll, 0);
           

WH_GETMESSAGE是Hook類型,csdn解釋如下:Installs a hook procedure that monitors messages posted to a message queue,即隻要有消息被post到消息隊列,Hook函數就會被調用。

最後一個參數是0,我們不知道B程序中的線程,是以幹脆設定為所有線程(這樣做會損失系統其他程式的一些性能,其他不需要改dll的程式,也會加載)。

現在來看看B程序的執行情況:

  1. 程序B中的一個線程準備向一個視窗post一條消息。
  2. 系統檢查該線程是否已經安裝了WH_GETMESSAGE Hook,檢查結果為确實安裝了這種Hook。
  3. 程序B準備調用Hook函數,即GetMsgProc函數。但是該函數在MyDll.dll中,而MyDll.dll并沒有加載到程序B。
  4. 程序B加載MyDll.dll。
  5. 調用GetMsgProc函數。

當然,還有很多複雜的步驟。我們關心的dll注入在第四步完成了。這就是采用Hook來注入dll的技術。dll一旦被注入程序B以後,該dll内的所有函數(不僅僅是GetMsgProc函數)都可以被程序B中的所有線程調用。

3. dll注入的作用

相信喜歡玩遊戲的都知道有個東西叫外挂,很多外挂就是采用dll注入的方法,進入到遊戲程序中,修改程序中的某些資料(比如金币、攻擊力、防禦力等)。dll注入還可以進行API攔截。

結束語:一句話,如果要進入一個程序的位址空間,可以考慮dll注入。