PE结构延迟加载导入表
PE體系
PE結(jié)構(gòu)&整體敘述
PE結(jié)構(gòu)&導(dǎo)入表
PE結(jié)構(gòu)&導(dǎo)出表
PE結(jié)構(gòu)&基址重定位表
PE結(jié)構(gòu)&綁定導(dǎo)入實(shí)現(xiàn)
PE結(jié)構(gòu)&延遲加載導(dǎo)入表
簡介
延遲加載導(dǎo)入表是PE中引入的專門用來描述與動(dòng)態(tài)鏈接庫延遲加載相關(guān)的數(shù)據(jù),因?yàn)檫@些數(shù)據(jù)所起的作用和導(dǎo)入表數(shù)據(jù)基本一致,所以稱為延遲加載導(dǎo)入表。
延遲加載導(dǎo)入表和導(dǎo)入表是相互分離的,一個(gè)PE文件中可以同時(shí)存在這兩種數(shù)據(jù),也可以單獨(dú)存在一種。延遲加載導(dǎo)入表是一種特殊類型的導(dǎo)入表,同導(dǎo)入表一樣,它記錄了應(yīng)用程序要導(dǎo)入的部分或全部動(dòng)態(tài)鏈接庫及相關(guān)的函數(shù)信息。與導(dǎo)入表不同的是,它所記錄的這些動(dòng)態(tài)鏈接庫并不會(huì)被操作系統(tǒng)的PE加載器加載,只有等到由其登記的相關(guān)函數(shù)被應(yīng)用程序調(diào)用時(shí),PE中注冊(cè)的延遲加載函數(shù)才會(huì)根據(jù)延遲加載導(dǎo)入表中對(duì)該函數(shù)的描述,動(dòng)態(tài)加載鏈接庫并修正函數(shù)的VA地址,實(shí)現(xiàn)對(duì)函數(shù)的調(diào)用。
延遲加載導(dǎo)入表的概念及作用
延遲加載導(dǎo)入是一種合理利用進(jìn)程加載機(jī)制提高進(jìn)程加載效率的技術(shù),使用延遲加載導(dǎo)入表能跳過加載前對(duì)引入函數(shù)的檢測(cè)及加載后對(duì)IAT的修正(只有等到由其登記的相關(guān)函數(shù)被應(yīng)用程序調(diào)用時(shí),PE中注冊(cè)的延遲加載函數(shù)才會(huì)根據(jù)延遲加載導(dǎo)入表中對(duì)該函數(shù)的描述,動(dòng)態(tài)加載鏈接庫并修正函數(shù)的VA地址)。
延遲加載導(dǎo)入的概念:系統(tǒng)開始運(yùn)行程序時(shí)指定的延遲加載的DLL是不被載入的,只有等到程序調(diào)用了該動(dòng)態(tài)鏈接庫的函數(shù)時(shí),系統(tǒng)才將該鏈接庫載入內(nèi)存空間,并執(zhí)行相關(guān)函數(shù)代碼。
作用:
提高應(yīng)用程序加載速度
如果一個(gè)應(yīng)用程序使用了很多的DLL,PE加載器在將程序映像加載的虛擬地址空間的時(shí)候,同時(shí)也會(huì)把所有的DLL一起提前加載到進(jìn)程空間,而且在加載每個(gè)DLL時(shí)還會(huì)調(diào)用DLL 的入口函數(shù),對(duì)DLL進(jìn)行初始化,盡管這時(shí)候程序并沒有開始調(diào)用這些引入的動(dòng)態(tài)鏈接庫的函數(shù)。這些操作的存在使得進(jìn)程加載時(shí)會(huì)耗費(fèi)一些時(shí)間,可能會(huì)使程序加載速度收到影響,而延遲加載則可以完全避開這點(diǎn)。這就好像安排一項(xiàng)多人要完成的工作,只有當(dāng)需要某人的時(shí)候才正式通知他
提高應(yīng)用程序兼容性
同一個(gè)DLL在不同時(shí)期會(huì)有不同的版本,一般情況下,新的DLL除了對(duì)原有函數(shù)的繼承和優(yōu)化外,通常還會(huì)增加一些新的函數(shù)。如果我們?cè)賾?yīng)用程序中調(diào)用了一個(gè)DLL的新函數(shù),運(yùn)行時(shí)所在環(huán)境提供的卻是老的DLL,那么加載時(shí)系統(tǒng)就會(huì)提示錯(cuò)誤,然后拒絕指向應(yīng)用程序。如果我們?cè)俅a中先對(duì)運(yùn)行的環(huán)境進(jìn)行檢測(cè),發(fā)現(xiàn)存在老的DLL,則不再調(diào)用這個(gè)不存在的函數(shù),要么友好提示,要么通過其它方式實(shí)現(xiàn)該函數(shù)的功能。這樣就可以保證在沒有新DLL的環(huán)境中,程序依舊可以被PE加載器加載并運(yùn)行。
假設(shè)現(xiàn)在有DLL的兩個(gè)不同版本,舊的MyDLL.dll和新的MyDll.dll,其中在新的MyDll.dll中又增加了一個(gè)函數(shù)_getImportDescriptor()
應(yīng)用程序代碼如下:
把這段代碼按照正常的編碼方式放到一個(gè)源文件,然后編譯,鏈接,鏈接的時(shí)候一定會(huì)出現(xiàn)錯(cuò)誤。即使讓你鏈接通過了,運(yùn)行時(shí)也會(huì)出現(xiàn)錯(cuò)誤。如果我們?cè)冁溄訒r(shí)告訴鏈接器新的MyDll.dll使用了加載延遲加載導(dǎo)入的方法,鏈接器就會(huì)為我們單獨(dú)處理這個(gè)函數(shù)的調(diào)用,從而避免錯(cuò)誤的出現(xiàn)。這種提高應(yīng)用程序適應(yīng)不同環(huán)境的能力。
提高應(yīng)用程序可整合性
受早期MS_DOS下應(yīng)用程序的習(xí)慣影響,有的程序員并不太喜歡目前Windows下應(yīng)用程序的安裝方式。在Windows系統(tǒng)下,程序運(yùn)行需要安裝,不需要的時(shí)候還要通過控制面板卸載,與程序有關(guān)的 數(shù)據(jù)并不是僅僅存儲(chǔ)在一個(gè)獨(dú)立的目錄下,而是遍及整個(gè)磁盤,如運(yùn)行是庫所在目錄,注冊(cè)表,系統(tǒng)目錄,系統(tǒng)的配置管理器目錄等。這把一個(gè)完整的程序變得四分五裂,在程序的后期管理維護(hù)和移植上制造了很多麻煩。為了使軟件易于安裝,于是軟件就有了綠色的概念,將所有的東西全部存儲(chǔ)在一個(gè)文件里。想拷走的時(shí)候僅僅復(fù)制一個(gè)文件,與文件有關(guān)的配置信息,數(shù)據(jù)庫,鏈接庫都在一個(gè)文件里。這里指的可整合就是這種情況。
PE中的延遲加載導(dǎo)入表
在Windows XP SP3的大部分系統(tǒng)PE文件中,都存在延遲加載導(dǎo)入表數(shù)據(jù),延遲加載導(dǎo)入表數(shù)據(jù)的整體組織與導(dǎo)入表類似,也存在INT和IAT雙橋結(jié)構(gòu)
延遲加載導(dǎo)入表數(shù)據(jù)定位
延遲加載導(dǎo)入數(shù)據(jù)為數(shù)據(jù)目錄注冊(cè)的數(shù)據(jù)類型之一,其描述數(shù)據(jù)處于數(shù)據(jù)目錄的第14個(gè)目錄項(xiàng)中。
延遲加載導(dǎo)入數(shù)據(jù)所造的地址RVA=0x00000203c
延遲加載導(dǎo)入數(shù)據(jù)大小=0x00000040h
轉(zhuǎn)換成文件偏移后,0x83C
延遲加載導(dǎo)入描述符 IMAGE_DELAY_IMPORT_DESCRIPTOR
IMAGE_DELAY_IMPORT_DESCRIPTOR STRUCTAttributes dword ? ;0000h -屬性,必須為0Name dword ? ;0004h -指向DLL名稱的RVAModuleHandle dword ? ;0008h -DLL模塊句柄的RVADelayIAT dword ? ;000ch -延遲加載導(dǎo)入IAT的RVADelayINT dword ? ;0010h -延遲加載導(dǎo)入INT的RVABoundDelayIT dword ? ;0014h -綁定延遲加載導(dǎo)入表的RVAUnloadDelayIT dword ? ;0018h -卸載延遲加載導(dǎo)入地址表的RVATimeStamp dword ? ;001ch -此映像綁定到DLL的時(shí)間戳 IMAGE_DELAY_IMPORT_DESCRIPTOR ENDSIMAGE_DELAY_IMPORT_DESCRIPTOR.Attributes
+0000h,雙字,屬性,暫時(shí)未用,鏈接器在生成映像文件時(shí)將此字段設(shè)置為0.用戶可以在將來擴(kuò)展這個(gè)結(jié)構(gòu)時(shí)用它來指明添加了新字段,或者用它來指明延遲加載導(dǎo)入或卸載輔助函數(shù)的行為
IMAGE_DELAY_IMPORT_DESCRIPTOR.Name
+0004h,雙字,指向延遲加載導(dǎo)入的動(dòng)態(tài)鏈接庫的名字字符串的地址,該地址是一個(gè)RVA。
IMAGE_DELAY_IMPORT_DESCRIPTOR.ModuleHandle
+0008h,雙字。被延遲加載導(dǎo)入的DLL模塊句柄的RVA。該RVA位于PE映像的數(shù)據(jù)節(jié)中,延遲加載輔助函數(shù)使用這個(gè)位置存儲(chǔ)要被延遲加載的DLL的模塊句柄
IMAGE_DELAY_IMPORT_DESCRIPTOR.DelayIAT
+000Ch,雙字。延遲加載導(dǎo)入地址表的RVA。延遲加載輔助函數(shù)用導(dǎo)入符號(hào)的實(shí)際地址來更新這些指針,以便起轉(zhuǎn)換作用的這部分代碼不會(huì)陷入循環(huán)調(diào)用之中
IMAGE_DELAY_IMPORT_DESCRIPTOR.DelayINT
+0010h,雙字。延遲加載導(dǎo)入名稱表(INT)包含了可能需要被加載的導(dǎo)入符號(hào)的名稱。它們的排列方式與IAT的函數(shù)指針一樣,它們的結(jié)構(gòu)與標(biāo)準(zhǔn)的INT一樣。結(jié)構(gòu)的詳細(xì)信息可以參照導(dǎo)入表部分。
IMAGE_DELAY_IMPORT_DESCRIPTOR.BoundDelayIT
+0014h,雙字。延遲綁定導(dǎo)入地址表(BIAT)是由IMAGE_THUNK_DATA結(jié)構(gòu)組成的數(shù)組,它是可選的。它與延遲加載目錄表中的TimeStamp字段一起被用于后處理綁定階段。
IMAGE_DELAY_IMPORT_DESCRIPTOR.UnloadDelayIT
+0018h,雙字。延遲加載導(dǎo)入地址表(UIAT)是由IMAGE_THUNK_DATA結(jié)構(gòu)組成的數(shù)組,它是可選的。卸載代碼用它來處理明確的卸載請(qǐng)求。它由只讀節(jié)中已初始化的數(shù)據(jù)組成,這些數(shù)據(jù)是原始IAT 的精確副本。在處理卸載請(qǐng)求時(shí),可以釋放這個(gè)DLL,同時(shí)將IMAGE_DELAY_IMPORT_DESCRIPTOR.ModuleHandle清零,并用UIAT覆蓋IAT,以便將一切還原到預(yù)加載時(shí)的狀態(tài)。
IMAGE_DELAY_IMPORT_DESCRIPTOR.TimeStamp
+001Ch,雙字。表示應(yīng)用程序綁定到DLL的時(shí)間戳
延遲加載導(dǎo)入表實(shí)例分析
0x83C
IMAGE_DELAY_IMPORT_DESCRIPTOR.Attributes,屬性值為0
30 20 40 00IMAGE_DELAY_IMPORT_DESCRIPTOR.Name,0x402030轉(zhuǎn)換為文件偏移后0x830開始的字符串“MyDll.dll”
IMAGE_DELAY_IMPORT_DESCRIPTOR.ModuleHandle。指向.data段,文件偏移0x0000a1C處,此處用來存放MyDll.dll的模塊句柄
IMAGE_DELAY_IMPORT_DESCRIPTOR.DelayIAT。指向了延遲加載導(dǎo)入的IAT,位于文件偏移的0x00000a14位置處。該位置位于.data段,
IMAGE_DELAY_IMPORT_DESCRIPTOR.DelayINT.指向了延遲加載導(dǎo)入的INT,位于文件偏移的0x0000087C位置處,該位置位于.rdata段。從該位置取出的值為0x00402084,它指向了函數(shù)sayHello的hint/name描述:00 00/ 73 61 79 48 65 6c 6c 6F 00 00
IMAGE_DELAY_IMPORT_DESCRIPTOR.BoundDelayIT。指向了綁定延遲加載導(dǎo)入表,位于文件偏移0x00000890位置處,該位置位于.rdata段,從該位置取出的值為0x00000000,表示該映像文件無綁定延遲加載導(dǎo)入定義
總結(jié)
以上是生活随笔為你收集整理的PE结构延迟加载导入表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PE结构绑定导入实现
- 下一篇: 内核和用户模式下进程与线程创建