一、基础知识
(1)EXE和DLL文件之间的区别完全是语义上的,因为他们使用完全相同的PE格式。而唯一的区别就是用一个字段标识出这个文件是EXE还是DLL。
(2)64位Windows只是对PE格式做了一些简单的修饰,新格式叫PE32+。并没有任何新的结构加进去,改变的只是简单的将32位字段扩展成64位。(windows NT架构的可执行文件的格式就是PE格式)
(3)PE格式定义的主要地方位于我们的头文件winnt.h,这个头文件中几乎能找到关于PE文件的所有定义
(4)PE文件中的数据结构一般都有32位和64位之分,一般在名称上会表现出来:例如IMAGE_NT_HEADERS32 或 IMAGE_NT_HEADER64
(5)PE文件框架结构图:
(6)PE 文件和内存映像的关系
二、PE的基本概念
(1)PE文件使用的是一个平面地址空间(线性的),所有代码和数据都被合并在一起,组成一个很大的结构。文件的内容被分割为不同的区块,块中包含代码或数据。各个区块按页边界来对齐,区块没有大小限制,是一个连续的结构。此外,每个块有自己在内存中的一套属性,比如说这个区块是否包含代码、是否只读或可读/写等。
(2)认识PE文件不是作为单一内存映射文件被装入内存是很重要的。
(3)Windows加载器(又称PE装载器)遍历PE文件并决定文件的哪一部分被映射(比如说调试信息是不会被映射的,我们调试的时候才会用到).这种映射方式是将文件较高的偏移位置映射到较高的内存地址中(反之低的就到低的)。
(4)当磁盘文件一旦被装入内存中,磁盘上的数据结构布局和内存中的数据结构布局是一致的。
(5)这样如果知道在磁盘的数据结构中寻找一些内容,那么几乎都能在被装入到内存映射文件中找到相同的信息。但数据之间的相对位置可能改变(只是按比例变大变小了),其某项的偏移地址可能区别于原始的偏移位置,不管怎样,所有表现出来的信息都允许从磁盘文件偏移到内存偏移的转换。
(6)PE文件磁盘与内存映像结构图:清晰的反应了映射到内存中结构布局是一致的,只是数据之间的相对位置发生了改变(按比例变大变小了)。
三、PE相关名词解释
(1)基地址(ImageBase):文件执行时将被映射到指定内存地址中(加载文件会先加载到内存中,也就是映射了)的起始地址被称为模块句柄,这个初始内存地址也称为基地址。这个值是由PE文件本身设定的。(按照默认设置,用Visual C++建立的EXE文件基地址是00400000h,DLL文件基地址是10000000h。但是,这个值可以自己在编译器设定的。)
获取基地址的函数:HMODULE GetModuleHandle(LPCTSTR lpModuleName) //HMODULE 返回值,也就是我们获取到的句柄。LPCTSTR指针指向lpModuleName(想要获取的句柄的模块)
(2)虚拟地址(Virtual Address, VA)
由于Windows程序运行在保护模式下,所以应用程序访问存储器所使用的逻辑地址称为虚拟地址(因为他不是真正的物理地址,真正的物理地址被windows老大妈的保护机制保护起来),又称为内存偏移地址(Memory Offset)。
(3)相对虚拟地址(RVA(RelativeVirtualAddress)):某一个虚拟地址相对于基地址的偏移。例如:基地址为:00400000h,虚拟地址为:00410000h,那么相对虚拟地址就是:10000h。
(4)文件偏移地址(File Offset)
当PE文件储存在磁盘上的时候,某个数据的位置相对于文件头的偏移量,叫做偏移地址。文件偏移地址从PE文件的第一个字节开始计数,起始值为0。