PE文件:延遲導入表

0x00 作用

延遲導入表從它的名字上,我們可以知道他是一種加載比較延遲的導入表,不是在一開始就被加載的,而是等到要被使用的時候,纔會被延遲加載(動態加載相關鏈接庫並修正函數的虛擬地址,實現對函數的調用)。
目的:
1.提高程序的加載速度。
2.提高兼容性:有的函數在老的Windows版本中並不存在,但是在新的Windows版本中存在,而我們想要寫一個Dll來實現一個動態的判斷,即可以根據操作系統的版本來決定動態庫是否要被加載,則可以使用延時導入技術。

延時導入的侷限性:
1.一個導出了全局變量的的Dll是無法被延時加載的。
2.Kernel32.dll是不能被延時加載的,因爲要加載好該模塊才能調用LoadLibrary和GetProcAddress。
3.不應該在DllMain的入口函數中調用一個延時載入的函數,因爲這樣可能引起程序奔潰(可能此時的Dll並沒有被加載上)。

0x01 結構

數據目錄的第十四個成員。

typedef struct ImgDelayDescr {  
    DWORD           grAttrs;           // attributes  
    RVA             rvaDLLName;     // RVA to dll name  
    RVA             rvaHmod;            // RVA of module handle  
    RVA             rvaIAT;               // RVA of the IAT  
    RVA             rvaINT;              // RVA of the INT  
    RVA             rvaBoundIAT;    // RVA of the optional bound IAT  
    RVA             rvaUnloadIAT;   // RVA of optional copy of original IAT  
    DWORD           dwTimeStamp;    // 0 if not bound,  
                                    // O.W. date/time stamp of DLL bound to (Old BIND)  
} ImgDelayDescr, * PImgDelayDescr;  
typedef const ImgDelayDescr *   PCImgDelayDescr;  

grAttrs: 用來區分版本,1是新版本,0是舊版本,舊版本中後續的rvaxxxxxx域使用的都是指針,而新版本中都用RVA,我們只討論新版本。
rvaDLLName:一個RVA,指向導入DLL的名字。
rvaHmod: 一個RVA,指向導入DLL的模塊基地址,這個基地址在DLL真正被導入前是NULL,導入後纔是實際的基地址。
rvaIAT: 一個RVA,表示導入函數表,實際上指向IAT,在DLL加載前,IAT裏存放的是一小段代碼的地址,加載後纔是真正的導入函數地址。
rvaINT: 一個RVA,指向導入函數的名字表。 rvaUnloadIAT:延遲導入函數卸載表。
dwTimeStamp:延遲導入DLL的時間戳

0x02 設置方式

延遲導入表的設置是通過VS設置來實現的,比較簡單。

【DLL的延遲加載】:
1.需要DLL,MyLib.lib導入庫及MyLib.h 進行【隱式加載】的全步驟
2.屬性->配置屬性->鏈接器->輸入->延遲加載的Dll-> 添加MyDll.dll
(注意/DelayLoad:MyDll.dll這個開關不能用#pragma comment(linker, “/DelayLoad:MyDll.dll”)來設置。
3.屬性->配置屬性->鏈接器->輸入->附加依賴項-> 添加DelayImp.lib
//也可以用#include <delayimp.h>和#pragma comment(lib, “Delayimp.lib”)
//這個開關告訴鏈接器將delayimp中的__delayLoadHelper2函數嵌入到我們的可執行文件中。
4.如果需要自動卸載Dll,則需在可選 屬性->配置屬性->鏈接器->高級->卸載延遲加載的DLL->是 (/DELAY:UNLOAD);
//此時只能調用__FUnloadDelayLoadedDll2(PCSTR szDll)函數,而不能調用FreeLibrary
//並且傳入的參數不包含路徑,且名稱與延遲加載的Dll中配置的參數必須保持一致,如果不打算卸載,就可以不指定/DELAY:UNLOAD

裝載延遲導入表:實際使用的函數是實際上使用的函數是:__delayLoadHelper2
在這裏插入圖片描述
**卸載延遲導入表:**實際使用的函數是FUnloadDelayLoadedDLL()。
在這裏插入圖片描述

注意:
延遲導入的加載只發生在函數第一次被調用的時候,之後IAT就填充爲正確函數地址,不會再走__delayLoadHelper了。
延遲導入一次只會導入一個函數,而不是一次導入整個模塊的所有函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章