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

0x04 尋找函數地址示意圖

Tags: