EAT表
0X0 EAT表
在windows系統中,「庫」是為了方便其他程序調用而集中包含相關的函數的文件(dll,sys).win32 API是最具有代表性的庫。
EAT是一種核心機制,它使不同的應用程序可以調用庫文件中提供的函數。也就是說,只有通過EAT表才能準確的求得從相應的庫中導出函數的起始地址。
PE文件內的結構體(IMAGE_EXPORT_DIRECTORY)保存着導出信息,且PE文件中僅有一個用來說明庫EAT的IMAGE_EXPORT_DIRECTORY結構體
0X01 IMAGE_EXPORT_DIRECTORY結構體
我們可以在PE文件頭 IMAGE_EXPORT_DIRECTORY的位置,IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress就是該結構體數組的起始地址。
IMAGE_EXPORT_DIRECTORY 結構體代碼如下
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; //保留 總是定義為0
DWORD TimeDateStamp; //文件生成時間
WORD MajorVersion; //主版本號 一般不賦值
WORD MinorVersion; //次版本號 一般不賦值
DWORD Name; //模塊的真實名稱
DWORD Base; //索引基數 加上序數就是函數地址數組的索引值
DWORD NumberOfFunctions; //地址表中個數
DWORD NumberOfNames; //名稱表的個數
DWORD AddressOfFunctions; //輸出函數地址的RVA
DWORD AddressOfNames; //輸出函數名字的RVA
DWORD AddressOfNameOrdinals; //輸出函數序號的RVA
} IMAGE_EXPORT_DIRECTORYM, *pIMAGE_EXPORT_DIRECTORY;
IMAGE_EXPORT_DIRECTORY 結構體的重要成員
項目 | 含義 |
---|---|
NumberOfFunctions | 實際Export函數的個數 |
NumberOfNames | Export函數中具名函數的個數 |
AddressOfFunctions | Export函數地址數組(數組元素個數=NumberOfFunctions) |
AddressOfNames | 函數名稱地址數組(數組元素個數=NumberOfNames) |
AddressOfNameOrdinals | Ordinal地址數組(數組元素個數=NumberOfNames) |
下圖是描述kernel32.dll文件的IMAGE_EXPORT_DIRECTORY 結構體與整個EAT結構
0x02 獲取庫函數的操作原理
從庫中獲取函數的API為GetProAddress()函數。該API引用EAT來獲取指定API的地址,下面說明GetProAddress()函數的流程。
GetProAddress()操作原理
(1) 首先我們有一個要查找的函數名字fun_name
(2) 通過IMAGE_EXPORT_DIRECTORYM 獲得AddressOfNames成員獲取函數名稱數組。通過比較(strcmp)字符串,查找出指定的函數名稱,獲取數組的索引值
(3) 通過IMAGE_EXPORT_DIRECTORYM 獲得AddressOfNameOrdinals成員獲取函數名稱數組,將獲取的數組索引值作為AddressOfNameOrdinals數組的下標獲取相應的值ordinal
(4) 通過IMAGE_EXPORT_DIRECTORYM 獲得AddressOfFunctions成員獲取函數名稱數組。並把ordinal作為AddressOfFunctions數組的下標,獲取指定函數的地址
提示
對於沒有函數名稱的導出函數,可以通過Ordinal查找它們地址。從Ordinal值減去IMAGE_EXPORT_DIRECTORY.Base成員最後一個值,使用該值作為”函數地址數組”(AddressOfFunctions)的索引,即可查找到相應的函數地址。
0x03 使用user32.dll練習
1 查找EAT表的地址
通過PEview查看user32.dll RVA 3900 => RAW 2D00
2 查出來EAT表的RAW為 2D00
EAT結構體中的含義
名稱 | 數據(RVA) | RAW |
---|---|---|
Characteristics | 0 | 0 |
TimeDateStamp | 48025D7A | 0 |
MajorVersion | 0000 | 0 |
MinorVersion | 0000 | 0 |
Name | 000055C0 | 49C0 |
Base | 00000001 | 0 |
NumberOfFunctions | 000002DC | 0 |
NumberOfNames | 000002DC | 0 |
AddressOfFunctions | 00003928 | 2D28 |
AddressOfNames | 00004498 | 3898 |
AddressOfNameOrdinals | 00005008 | 4408 |
3 查看函數名稱組
AddressOfNames是一個 4個位元組RVA組成的數組,AddressOfNameOrdinals是一個2個位元組組成的數組,AddressOfFunctions 是由4個位元組 函數地址組成的數組
我們查找第一個函數名的地址來演示整個流程 首先找到AddressOfNames 在文件中的首地址RAW 3898
RVA 55CB => RAW 49CB 轉換成文件偏移
這個為一個函數,序號為0,下一步需要查找AddressOfNameOrdinals中索引為0中的數據
從數組中取出數據為零,則在AddressOfFunctions 數組查找下標為0的數組
RVA 00018673
用OllDbg查看user32.dll 看到 ImageBase=77D10000
所以該ActivateKeyboardLayout函數的實際地址為 77D10000+18673=77D28673