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