EXE和DLL文件使用完全相同的PE格式,唯一的区别就是用一个字段标示出这个文件是EXE还是DLL。
PE格式定义的主要地方位于头文件winnt.h中,这个头文件中几乎能找到关于PE文件的所有定义。
Windows的内核基本是用C写的。(Microsoft Visual Studio\VC98\Include下<小甲鱼说,Include下包含了VC所用的所有头文件。>)
winnt.h中有一个章节叫做image format,该章节定义了PE的结构。
DOS 'MZ' HEADER和Dos stub是为了兼容以前的16位的Dos系统而保留下来的。
文件的内容被分割为不同的区块,块中包含代码或数据。各个区块按页边界来对齐,区块没有大小限制,是一个连续的结构。
此外,每个块有自己在内存中的一套属性,比如说这个区块是否包含代码、是否只读或可读/写等。
认识PE文件不是作为单一内存映射文件被装入内存是很重要的。
Windows加载器(又称PE加载器)遍历PE文件并决定文件的哪一部分被映射,这种映射方式是将文件较高的偏移位置映射到较高的内存地址中。
例如调试信息这一部分是不会被映射的。
当磁盘文件一旦被装入内存中,磁盘上的数据结构布局和内存中的数据结构布局是一致的。
但数据之间的相对位置可能改变,其某项的偏移地址可能区别于原始的偏移地址,不管怎样,所有表现出来的信息都允许从磁盘文件偏移到内存偏移的转换。
基地址 --- ImageBase(内存中的头地址)
文件的偏移地址 --- 当我们的PE文件存放在磁盘中的时候,各个的区块对于它的头的相对偏移(文件头都是从0开始的)。
相对虚拟地址RVA --- 每一个区块的虚拟地址相对于基地址的偏移。(相对虚拟地址会在PE文件中显示出来)。
当磁盘的PE文件被PE加载器加载到内存中之后,内存中的这个PE文件,我们称之为一个模块(module),映射文件的起始地址被称为这个模块的一个句柄。
HMODULE GetModuleHandle(LPCTSTR lpModuleName);可以获取模块的句柄。