PE结构绑定导入实现
PE體系
PE結構&整體敘述
PE結構&導入表
PE結構&導出表
PE結構&基址重定位表
PE結構&綁定導入實現
PE結構&延遲加載導入表
簡介
作用
綁定導入是一種提高PE加載速度的技術。它只能起輔助性作用,它的存在與否只影響加載過程,并不影響PE的最終加載結果和運行結果。
為什么說是輔助性呢?
因為不同的操作系統中,動態鏈接庫的基地址是不一樣的。舉個例子,kernel32.dll,在Windows 2000中其加載到進程空間的基地址為0x77e60000,而在Windows XP SP3中其加載地址則是0x7c800000。同一動態鏈接庫加載后處于不同的基地址,直接導致了同一個導入函數在不同操作系統中其導入地址VA是不一樣的。
因此經過綁定的PE程序可以能在Windows 2000里運行得很好,但是到了Windows XP SP3中卻因地址出現錯誤而造成無法運行。
解決辦法
在為PE加入綁定導入機制的時候,微軟就已經考慮了這個問題,所以假定PE加載前對IAT的修正都是正確的。那么PE的加載速度是加快的,即使綁定以后的EXE程序在其他兼容系統中運行時,其地址出現錯誤,PE加載也有檢測錯誤的基址。如果地址檢測出錯誤,PE加載器會重新接管這項工作,加載時對IAT進行修正。
原因
雙橋結構導入表中,橋2是指向IAT的,Windows加載程序負責IAT中地址的修正工作。如果導入函數比較多的話,那么就會占用比較長的時間,從而加載速度就會變慢。因此有了綁定導入,它的目的就是把Windows加載程序負責的IAT地址修正工作提到加載前進行,要么由用戶手工完成,要么由專門的程序完成;然后再PE文件中聲明導入數據,以便告訴操作系統加載器說這部分工作不需要你做了。
操作
微軟提供了一個綁定工具bind.exe程序,它把導入表IAT表項IMAGE_THUNK_DATA32的內容都靜態替換成虛擬內存地址(如下圖)
,然后在數據目錄表的第12項指定的位置聲明這些更改。Windows在加載目標PE相關的動態鏈接庫時,會檢查這些地址時候合法(檢查操作包括:當前的DLL版本是否符合綁定導入結構中描述的版本號,如果不符合或者DLL需要被重新定位,加載器也就會去遍歷INT(如下圖),計算新的地址。)
這就是為什么雙橋可以綁定, 單橋不能綁定了,因為單橋的話,進行遍歷INT這里是無效的(沒有橋1,只有橋2),所以單橋結構無法實施靜態綁定
綁定導入數據定位
綁定導入數據結構
IMAGE_BOUND_IMPORT_DESCRIPTOR STRUCTTimeDataStamp dword ? ; 0000h -時間戳OffserModuleName word ? ; 0004h -指向DLL名稱NumberOfModuleForwarderRefs word ? ; 0006h -ModuleForwarderRef 數目 IMAGE_BOUND_IMPORT_DESCRIPTOR ENDSIMAGE_BOUND_IMPORT_DESCRIPTOR.TimeDataStamp
+0000h,雙字。該字段的值必須要與要引用的DLL文件頭IMAGE_FILE_HEADER.TimeDataStamp字段值相吻合,否則就會促使加載器去重新計算新IAT,這種情況一般發生在DLL版本不同時或者DLL映像被重定位時
IMAGE_BOUND_IMPORT_DESCRIPTOR.OffserModuleName
+0004h,單字。該字段包含了以第一個IMAGE_BOUND_INPORT_DESCRIPTOR作為基址,DLL名稱字符串(ASCII且以“\0”結束)的偏移
注意:
該偏移地址是一個特殊的地址,它即不是RVA,也不是FOA
IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs
+0006h,單字。該字段描述了緊接在IMAGE_BOUND_IMPORT_DESCRIPTOR結構后的另一個結構IMAGE_BOUND_FORWARDER_REF的定義:
IMAGE_BOUND_FORWARDER_REF STRUCTTimeDataStamp dword ?; 0000h - 時間戳OffsetModuleName word ?; 0004h - 指向DLL名稱Reserved word ?; 0006h - 預留 IMAGE_BOUND_FORWARDER_REF ENDS為什么會存在該結構呢?處于不同的目的(如代碼更新,結構調整或實施補丁等),動態鏈接庫中的某些函數的實現代碼會被轉移到別的動態鏈接庫中。但為了提供向前的兼容,這些動態鏈接庫中還保留該函數的定義。
換種說法,一個導入函數將涉及對多個動態鏈接庫函數的調用,數據結構IMAGE_BOUND_FORWARDER_REF就是在這樣一個背景下產生的,它將引入函數涉及的所有動態鏈接庫都列舉出來。
該結構的字段定義和IMAGE_BOUND_IMPORT_DESCRIPTOR是基本一致的,所以前面的描述“綁定導入數據由一系列的綁定導入描述符IMAGE_BOUND_IMPORT_DESCRIPTOR的結構組成”也是成立。
導入數據組織方式如下圖:
實際操作
用的是dump后的文件:
注意:
系統文件的綁定導入表數據在文件中的存放位置:大部分情況下,該數據被存在PE文件頭部,緊跟在節表后。
看一個特殊的具有IMAGE_BOUND_FORWARDER_REF的結構,如上圖數據進行分析,分析結果如下:
IMAGE_BOUND_IMPORT_DESCRIPTOR。
綁定時操作系統中動態鏈接庫kernel32.dll 的時間戳
A3 00指向動態鏈接庫名稱字符串的偏移為0x00A3,注意該偏移是基于第一個IMAGE_BOUND_IMPORT_DESCRIPTOR結構的,即基于文件偏移地址0x00000250開始的偏移。
01 00表示該動態鏈接庫中的函數實現字節碼存儲在另一個動態鏈接庫中
B0 00指向動態鏈接庫名稱字符串的偏移
00 00預留值,為0
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的PE结构绑定导入实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TLS回调函数(2)
- 下一篇: PE结构延迟加载导入表