第13章:PE文件格式(3) -- EAT
EAT
是一种核心机制,使不同的应用程序可以调用库文件中提供的函数.PE中的结构体Image_Export_Directory保存着导出信息,且只有一个结构体.
DataDirectory[0]结构体中的第一个元素是地址,第二个是大小.
有下面几个重要的成员:
1#.NumberOfFunctions
实际Export函数的个数.
2#.NumberOfNames
Export函数中具名的函数个数.
3#.AddressOfNames
函数名称地址数组.
4.AddressOfFunctions
Export函数地址数组.
5#.AddressOfNameOrdinals
Ordinal地址数组.
注意这个结构体在notepad.exe中显示是NULL.
下面展示在kernel.dll中的Image_Export_Directory结构体:
RVA 地址转换为 FileOffset,262C 转化为 1A2C.
如图所示:实际Export函数的个数:3b9,函数地址数组的起始地址:2654,函数名称数组的起始地址:3538,Ordinal地址数组:441C.(全是RVA)
从这里可以知道GetProcAddress()到底是如何工作的了:
1.在库文件的DataDirectory[0]中找到ExportDirectory,然后找到结构体中的AddressOfNames成员.每一个地址都对应一个函数名(连续的).
2.通过strcmp()函数对比查找指定的函数名称.
3.从AddressOfNameOrdinals找到ordinal数组.2字节表示一个ordinal值.将在找名称中拿到的索引值(x)用来查找相应的ordinal值(ordinal[x]).
4.利用AddressOfFunctions成员转到EAT.4字节为一个地址.用ordinal值用作数组索引查找指定函数的地址.
注意:若函数没有名称,则ordinal 无法匹配函数名称中的索引值.此时:
MSDN中写到: " GetProcAddress 采用 DLL 模块句柄(由 LoadLibrary 、AfxLoadLibrary
或 GetModuleHandle 返回)作为参数,并采用要调用的函数的名称或函数的导出序号。" 因此ordinal是可以直接作为参数传递进去的.就可以找到函数地址.
书上的一点补充: