[PE結構分析] 9.導出表 IMAGE_EXPORT_DIRECTORY


typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;    // 未使用,總為0 
    DWORD   TimeDateStamp;      // 文件創建時間戳
    WORD    MajorVersion;       // 未使用,總為0 
    WORD    MinorVersion;       // 未使用,總為0
    DWORD   Name;               // 指向一個代表此 DLL名字的 ASCII字符串的 RVA
    DWORD   Base;               // 函數的起始序號
    DWORD   NumberOfFunctions;  // 導出函數的總數
    DWORD   NumberOfNames;      // 以名稱方式導出的函數的總數
    DWORD   AddressOfFunctions;     // 指向輸出函數地址的RVA
    DWORD   AddressOfNames;         // 指向輸出函數名字的RVA
    DWORD   AddressOfNameOrdinals;  // 指向輸出函數序號的RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

AddressOfFunctions 所指向內容是以 4 字節為一個單位的數組元素,每個元素代表函數入口

AddressOfNames 所指向內容是以 4 字節為一個單位的數組元素,每個元素代表一個指向字符串的 RVA

AddressOfNamesOrdinals 所指向內容是以 2 字節為一個單位的數組元素,每個元素代表對應名字在 AddressOfFunctions 中的序號數。

AddressOfNames 和 AddressOfNamesOrdinals 的數目肯定是一樣的,不是一樣那么就出錯了。

主要要掌握兩種尋找函數入口地址的方法:

A. 從序號查找函數入口地址

1. 定位到PE 文件頭
2. 從PE 文件頭中的 IMAGE_OPTIONAL_HEADER32 結構中取出數據目錄表,並從第一個數據目錄中得到導出表的RVA
3. 從導出表的 Base 字段得到起始序號
4. 將需要查找的導出序號減去起始序號Base,得到函數在入口地址表中的索引,檢測索引值是否大於導出表的 NumberOfFunctions 字段的值,如果大於后者的話,說明輸入的序號是無效的
5. 用這個索引值在 AddressOfFunctions 字段指向的導出函數入口地址表中取出相應的項目,這就是函數入口地址的RVA 值,當函數被裝入內存的時候,這個RVA 值加上模塊實際裝入的基地址,就得到了函數真正的入口地址

B. 從函數名稱查找入口地址

我想通的地方,記錄下來:用函數名來查找的話,Base 的值現在沒有任何意義

1. 首先得到導出表的地址
2. 從導出表的 NumberOfNames 字段得到已命名函數的總數,並以這個數字作為循環的次數來構造一個循環,從 AddressOfNames 字段指向得到的函數名稱地址表的第一項開始,在循環中將每一項定義的函數名與要查找的函數名相比較,如果沒有任何一個函數名是符合的,表示文件中沒有指定名稱的函數。
3. 如果某一項定義的函數名與要查找的函數名符合,那么記下這個函數名在字符串地址表中的索引值,然后在AddressOfNamesOrdinals 指向的數組中以同樣的索引值取出數組項的值,我們這里假設這個值是 x
4. 最后,以 x 的值作為索引值在 AddressOfFunctions  字段指向的函數入口地址表中獲取 RVA 。此 RVA 就是函數的入口地址。

附上圖片:

PE-Export-table


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM