PE文件結構(四)
參考
書:《加密與解密》
視頻:小甲魚 解密系列 視頻
輸出表
一般來說輸出表存在於dll中。輸出表提供了 文件中函數的名字跟這些函數的地址, PE裝載器通過輸出表來修改IAT。
IMAGE_OPTIONAL_HEADER中的 DataDirectory[0] 提供了輸出表的RVA。輸出表是以一個IMAGE_EXPORT_DIRECTORY結構 開始的。
IMAGE_EXPORT_DIRECTORY結構:
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; //未使用
DWORD TimeDateStamp; //文件生成的時間
WORD MajorVersion; //主版本號,一般爲0
WORD MinorVersion; //次版本號,一般爲0
DWORD Name; //指向dll名的RVA
DWORD Base; // 基數,一般爲 1 (就是從1數起)
DWORD NumberOfFunctions; // AddressOfFunctions指向的數組的元素的個數
DWORD NumberOfNames; // AddressOfNames 指向的數組的元素的個數
DWORD AddressOfFunctions; // 函數地址數組ENT的RVA
DWORD AddressOfNames; // 函數名字數組EAT的RVA
DWORD AddressOfNameOrdinals; // 輸出序列號數組的RVA,這個數組是以WORD爲單位的,用來函數名字數組連接函數地址數組的
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
輸出表主要就是來給PE加載器修改IAT的,即查找函數的入口地址。PE加載器查找函數的地址有兩種方法,從序號查找,從函數名查找。
1. 從序號查找函數入口地址
PE加載器通過INT知道了序號,直接用這個序號 去找 函數地址數組EAT就可以了。
2. 從函數名查找函數入口地址
通過函數名,查找函數名數組ENT,找到這個函數名在數組中的序號 n(從0數起),然後取輸出序列號數組的第n個值(從0數起)。然後 以這個值爲序號的的函數地址數組EAT的值就是這個函數的入口地址。
即 ENT[ 輸出序列號數組[n] ]
實例分析:
例如找user32.dll 中AdjustWindowRect 這個函數。
先查看user32.dll的二進制文件,它的IMAGE_OPTIONAL_HEADER結構爲:
圖片1
從中可以知道:
Name: RVA 55C0h 文件偏移值:49C0h
Base: 1
NumberOfFunctions: 02DCh
NumberOfNmae:02DCh
AddressOfFunctions: RVA 3928h 文件偏移值:2D28h
AddressOfNames: RVA 4498h 文件偏移值:3898h
AddressOfNameOrdinals: RVA 5008h 文件偏移值:4408h
查看ENT數組所指向的字符串,可以知道AdjustWindowRect是第2個元素。所以,查看AddressOfNameOrdinals所指向的輸出序列號數組的第2個元素,可以發現值爲 1。
圖片2
再查看EAT中序號爲1的元素(即第2個元素)值爲021140h,這個就是AdjustWindowRect函數的RVA。
圖片3