在PE文件头之前
理论
Windows的PE(Portable Executable)文件有两个头,一个是是Windows头,一个是DOS头。在文件的最开始会有一段DOS的EXE文件头,来说明这个程序不可以在DOS环境下运行。我们需要在DOS头+3Ch处,会有一个4字节的指针指向windows头。
根据+3Ch处的值,定位到Windows文件头可以看到"PE"两个字节,Windows头就从此处开始。这也就是Windows EXE文件经常被称为PE文件的原因。
实践
- 在xp环境下,用QuickView打开一个EXE文件,观察其头部。
- 在00h处有两个字节
4D 5A
表示这是一个DOS头。 - 在4Eh处,有一个字符串
This program cannot be run in DOS mode.
表明这不是一个DOS文件 - 在3C处,有一个四字节指针,其值为000000D0h,颜色标黄,指向windows头
- 在00h处有两个字节
-
查看文件地址D0处的值
可以看到此处的两个字节为
50 45
即“PE”,表示这个EXE文件是一个PE文件,从这两个字节开始才是PE的文件头。
PE文件头
背景知识
要了解PE文件头的具体内容,我们需要对Windows的内存管理,文件存储有一定的了解。接下来做简要的说明,想要了解更详细的内容可以去学习操作系统的相关知识。
Windows通过分段以及分页两种机制管理内存和实现进程的隔离及保护。以下说明会涉及到一些寄存器和比较抽象的概念,不懂也没有关系。只需要知道结论,*一个进程的虚拟地址会经过一些转换成为真正的物理地址. *进程之间的虚拟地址可以相同,但相同的虚拟地址会转化成不同的物理地址。
- 在Windows系统中,为了向下兼容,保留了分段(section)的的机制,但是CS,DS,SS这些段地址在GDT表中的值全部为0,所以经过分段后的逻辑地址(logical address)与线性地址(linear address)是完全一致的,在此处不用过多理会。
- 对于分页(paging)机制,每一个进程都有一个属于他们自己的页目录表,每一个页目录表是不一样的,线性地址需要经过页表项的查询,转换成的真正的物理地址。所以对于不同进程而言,相同的线性地址会转化成为不同的物理地址。
有了分页的机制后,windows的exe在运行时统一被载入内存的基地址=400000h处
在PE文件头中出现的内存地址都是以RVA(relative virtual address)相对虚拟地址的形式表示的,即
程序真正的虚拟地址 = 相对虚拟地址+载入内存的基地址=RVA+400000h
PE文件头的具体内容
有了上述的了解后,接下来我们来看PE文件头的具体内容。以下的描述涉及到的偏移地址均为16进制,且均相对于PE文件头。
以一个EXE文件的PE头为例,我们来说明,PE文件头一些重要的项的具体含义。
000000d0: 5045 0000 4c01 0300 2fe6 a25d 0000 0000 PE..L.../..]....
|
+------------------------------- +06 用两个字节来保存段的数量,此时为0003个段
000000e0: 0000 0000 e000 0f01 0b01 0600 0050 0000 .............P..
000000f0: 0050 0000 0000 0000 4510 0000 0010 0000 .P......E.......
|
+------------------------- +28 程序的32位入口地址,即当前EXE在运行时, 第一条指令执行的相对虚拟地址
00000100: 0060 0000 0000 4000 0010 0000 0010 0000 .`....@.........
| | |
| | +------------- +3C 文件对齐,两个字节,此处为1000h
| +------------------------- +38 内存对齐,两个字节,此处为1000h
|
+----------------------------------- +34 程序载入内存的基地址,4个字节EXE一般上都为400000h
00000110: 0400 0000 0000 0000 0400 0000 0000 0000 ................
00000120: 00b0 0000 0010 0000 0000 0000 0300 0000 ................
| |
| |
| +---------------------------------- +54 EXE文件头的文件长度(经过文件对齐之后),载入内存后会进行内存对齐(包括DOS头和Windows头)
|
+-------------------------------------------- +50 EXE文件载入内存后的总长度=文件头+各个section载入内存后的总长度(经过内存对齐后)
- 在PE+F8处定义了各个section的描述,每一个节的描述的大小为28h字节,在QV中查看具体的值如下:
- PE+F8+0: 节名,8字节,以00作为结束标记
- PE+F8+8:节的内存长度 4980h
- PE+F8+C:节的内存偏移 1000h
- PE+F8+10: 节的文件长度 5000h
- PE+F8+14: 节的文件偏移 1000h
- PE+F8+24: 节的属性,read,write,execute
关于PE文件头中的输出表、输入表、资源表、重定位表的描述比较复杂,会另写文档讲述。
输出表:To do...
输入表:Windows PE文件的输入表
重定位表:To do...
随笔是个人学习的总结,如有错误欢迎指出!