.exe文件是Windows操作系统可执行的文件,但它究竟包含了什么内容呢?是特定处理器的汇编语言吗?还是某种中间语句,被Windows识别后转换为特定处理器的汇编语言?当Windows“执行”该文件时,它具体做了什么呢?
.exe文件是Windows操作系统可执行的文件,但它究竟包含了什么内容呢?是特定处理器的汇编语言吗?还是某种中间语句,被Windows识别后转换为特定处理器的汇编语言?当Windows“执行”该文件时,它具体做了什么呢?
MSDN上有一篇文章 "深入探讨Win32可执行文件格式" ,其中描述了可执行文件的结构。
基本上,一个 .exe 文件包含多个数据块和有关这些块如何加载到内存中的指令。其中一些块包含可以执行的机器代码(其他块包含程序数据、资源、重定位信息、导入信息等)。
我建议您获取一份《Windows 内核原理》,以便全面了解运行 exe 时发生的情况。
对于本机可执行文件,其机器代码是特定于平台的。.exe 的头部指示了 .exe 所针对的平台。
当运行本机 .exe 时,会发生以下操作(大致说明):
托管可执行文件包含 MSIL (Microsoft Intermediate Language),可以编译它们以针对 CLR 支持的任何 CPU。我不太熟悉 CLR 加载器的内部工作方式(最初运行哪些本机代码来引导 CLR 并启动解释 MSIL),也许其他人可以详细说明。
我可以告诉你,.exe文件的前两个字节包含'MZ'字符。
实际上,这代表着Mark Zbikowski。他是设计exe文件格式的人。
1和0!
这个维基百科链接会为你提供有关Windows应用程序使用的可移植可执行文件格式的所有信息。
EXE文件实际上是一种名为可移植可执行文件(Portable Executable)的文件类型。它包含二进制数据,处理器可以读取并执行(基本上是x86指令)。还有很多头部数据和其他杂项内容。实际的可执行代码位于名为.text
的部分中,并以机器指令(特定于处理器)的形式存储。这些代码(以及.EXE的其他部分)被放入内存中,并将CPU发送到它,从而开始执行。(请注意,实际上还发生了更多接口;这是一个简化的解释)。
在一个实际程序的示例中,002b个条目(或00ac字节)的重定位表位于EXE文件的001e-00ca位置。程序图像的大小为548e字节,段被展开并放置在0200-548d文件中。堆栈应初始化为SS:SP = 06c1:0800,并且入口点应位于CS:IP = 0000:05d0位置。数据请求范围为2190-ffff0字节,校验和为e3d8。
因此,强制的16位字的布局如下:
W00 = 5a4d
(W02, W04) = (008e, 002b)
W06 = 002b
W08 = 0020
(W0a, W0c) = (0219, ffff)
(W0e, W10) = (06c1, 0800)
W12 = e3d8
(W14, W16) = (05d0, 0000)
W18 = 001e
W1a = 0000
作为一个字节序列,它的读取结果是: 4d, 5a, 8e, 00, 2b, 00, 2b, 00, 20, 00, 19, 02, ff, ff, c1, 06, 00, 08, d8, e3, d0, 05, 00, 00, 1e, 00, 00, 00在重定位中列出了几个部分,包括 0000、0135、04d0、04fe、0500,这是一种获取代码镜像如何分割成片段的方法之一 - EXE 文件没有明确列出各个片段,因为它们已经被扁平化。
从文件位置 00ca 到 01ff 还有另一个覆盖范围缺失,代码镜像从文件位置 0200 开始,直到文件末尾的 548d。
刚才提到的实际片段在文件中映射如下:
0000 片段在 0200-154f
0135 片段在 1550-4eff
04d0 片段在 4f00-51df
04fe 片段在 51e0-51ff
0500 片段在 5200-548d
假设这些是程序中唯一的片段。当程序叠加到内存中时,在重新定位完成后,它将放置在物理内存中第一个可用地址的 0000-528d 区间。
所以,例如,如果它被加载器重新定位到段落077a(我的DosBox版本是如此),那么加载器首先必须进行调整。例如,代码图像中列出的单词在0000:0022处(并且在文件中位于0222-0223)包含了0135这个词(表示段落0135),必须将其增加到0135+077a=08af。段落本身也会在重定位过程中相应地增加,从0000、0135、04d0、04fe、0500(堆栈为06c1)分别增加到077a、08af、0c4a、0c78、0c7a(堆栈为0e3b)。