第38章: PE32+
PE32+ 是 Windows OS 使用的可执行文件格式.
64位 Windows OS 中进程的虚拟内存为16TB,其中低位的8TB供用户模式使用.高位的8TB供内核模式使用.
IMAGE_NT_HEADERS
IMAGE_FILE_HEADER
x86 PE32 固定为 014C. x64 PE32+ 中则为 8664 ( IA-64 中为0200 ).
IMAGE_OPTIONAL_HEADER
1#. Magic
PE32 中为 010B , PE32+ 中为 20B
2#. BaseOfData
PE32 中用作指示数据节的起始地址( RVA ), 而PE32+ 中删除了.
3#. ImageBase
有双字( Dword ) 变为 ULONGLONG (8字节).
4#. 堆&栈
与 堆(heah) 和 栈(stack) 有关的数据类型都变为 ULONGLONG 类型.
IMAGE_THUNK_DATA
先以32位为例:
这个结构体其实就是 INT 和 IAT 所指向的结构体.
网上有:
第一种说法: Ordinal 的值用作判断 union 中哪个域发挥作用.若 Ordinal 值为0,则此时只有 AddressOfData (指向 Import_by_name )有效, 即为 INT .若 Ordinal 最高位为1,则为 IAT.
这种说法纯属离谱,Ordinal 和 AddressOfData 都占四字节,不可能出现上述情况。
第二种说法是: 按照 IMAGE_THUNK_DATA 的最高位来判断. 如果最高位为1 ,则低 31/63 位是 ordinal,否则为地址 .
在 xp sp3 中的 notepad.exe 中看一下(因为使用的是服务包sp3,系统文件会被重建,会硬编入准确地址):
再看一下 INT :
目前来看,INT 中最高位都是 0 ; 而 IAT 中,最高位都不是1 (最高位为1,则值最小为: 0x80000000 ),并且 IAT 中是硬编码函数地址.
因为:该程序是系统程序,我们找到的函数都是系统DLL函数,系统DLL都固定了位置。
在 Win 7 32位下,看一下 notepad.exe 的 IAT 信息:
INT 信息:
如图,最高字节的值有 77, 6F , 73 , 72 , 75 , 3F ,以及 80.
普通 Dll 的 ImageBase 为 0x10000000,即最高字节值为1. 当最高位为1时,此时为 0x80000000 , 而 00000000 - 7FFFFFFF 是用户空间,其它则是系统空间.因此最高位为1时,在用户模式下是不能表示函数地址的.
通过以上这些,并结合前面的知识,可以做如下总结(程序未载入内存时):
1#. 在 IAT 中, 有两种值, ①表示函数地址 ②与 INT 相同,即指向 Import_by_name 结构体.
2#. 在 INT 中, 在两种值, ①指向 Import_by_name 结构体 ② 最高位为1,表示这个函数是由导出序号导入的函数.
因此当 IMAGE_THUNK_DATA 的最高位为1时,此时一定表示函数的导入序号.其它情况则分情况判定.