14

我不太熟悉编译器的魔法。对我来说,将人类可读的代码(或不可读的汇编指令)转换为机器代码的行为是火箭科学与巫术的结合。

我将把这个问题的主题缩小到 Win32 可执行文件 (.exe)。当我在专门的查看器中打开这些文件时,我可以发现分散在各个地方的字符串(通常每个字符 16b),但其余的只是垃圾。我想不可读的部分(大部分)是机器代码(或者可能是资源,例如图像等......)。

是否有任何直接读取机器代码的方法?将 exe 作为文件流打开并逐字节读取,如何将这些单独的字节转换为汇编?这些指令字节和汇编指令之间是否有直接的映射?

.exe是怎么写的?每条指令四个字节?更多的?较少的?我注意到一些应用程序可以像这样创建可执行文件:例如,在 ACD See 中,您可以将一系列图像导出到幻灯片中。但这不一定是 SWF 幻灯片,ACD See 也能够生成可执行的演示文稿。这是怎么做的?

我如何理解 EXE 文件中发生的事情?

4

13 回答 13

15

OllyDbg是一个很棒的工具,它可以将 EXE 反汇编成可读的指令,并允许您一个接一个地执行指令。它还告诉您程序使用了哪些 API 函数,如果可能,它提供的参数(只要在堆栈上找到参数)。

一般来说,CPU指令的长度是可变的,有些是一个字节,有些是两个,有些是三个,有些是四个等。这主要取决于指令期望的数据类型。有些指令是通用的,例如“mov”,它告诉 CPU 将数据从 CPU 寄存器移动到内存中的某个位置,反之亦然。实际上,有许多不同的“mov”指令,用于处理 8 位、16 位、32 位数据的指令,用于从不同寄存器移动数据的指令等等。

您可以阅读 Paul Carter 博士的PC 汇编语言教程,这是一本免费的入门级书籍,介绍了汇编以及 Intel 386 CPU 如何运行。其中大部分甚至适用于现代消费级英特尔 CPU。

EXE 格式特定于 Windows。入口点(即第一条可执行指令)通常位于 EXE 文件中的相同位置。一下子解释起来有点困难,但是我提供的资源应该至少可以帮助治愈您的一些好奇心!:)

于 2009-04-16T14:33:34.937 回答
6

您需要一个反汇编程序,它将机器代码转换为汇编语言。此Wikipedia 链接描述了该过程并提供了免费反汇编程序的链接。当然,正如你所说的你不懂汇编语言,这可能不是很丰富 - 你到底想在这里做什么?

于 2009-04-16T14:30:57.890 回答
5

你看到的可执行文件是微软的PE(Portable Executable)格式。它本质上是一个容器,它包含一些有关程序的操作系统特定数据,并且程序数据本身分为几个部分。例如代码、资源、静态数据存储在单独的部分中。

该部分的格式取决于其中的内容。代码部分根据可执行目标体系结构保存机器代码。在最常见的情况下,这是用于 Microsoft PE 二进制文件的 Intel x86 或 AMD-64(与 EM64T 相同)。机器代码的格式是 CISC,起源于 8086 和更早版本。CISC的重要方面是它的指令大小不是恒定的,您必须从正确的位置开始阅读才能从中获得有价值的东西。英特尔发布了关于 x86/x64 指令集的优秀手册。

您可以使用反汇编程序直接查看机器代码。结合手册,您大部分时间都可以猜出源代码。

然后是 MSIL EXE:包含 Microsoft 中间语言的 .NET 可执行文件,它们不包含特定于机器的代码,而是 .NET CIL 代码。ECMA 上提供了相关规范。

这些可以使用反射器等工具进行查看。

于 2009-04-16T14:36:02.153 回答
5

EXE 文件的内容在Portable Executable中描述。它包含有关如何加载文件的代码、数据和 OS 指令。

机器代码和程序集之间存在 1:1 映射。反汇编程序将执行相反的操作。

i386 上的每条指令没有固定的字节数。有些是单个字节,有些更长。

于 2009-04-16T14:38:33.037 回答
4

您可以从命令行使用调试,但这很难。

C:\WINDOWS>debug taskman.exe
-u
0D69:0000 0E            PUSH    CS
0D69:0001 1F            POP     DS
0D69:0002 BA0E00        MOV     DX,000E
0D69:0005 B409          MOV     AH,09
0D69:0007 CD21          INT     21
0D69:0009 B8014C        MOV     AX,4C01
0D69:000C CD21          INT     21
0D69:000E 54            PUSH    SP
0D69:000F 68            DB      68
0D69:0010 69            DB      69
0D69:0011 7320          JNB     0033
0D69:0013 7072          JO      0087
0D69:0015 6F            DB      6F
0D69:0016 67            DB      67
0D69:0017 7261          JB      007A
0D69:0019 6D            DB      6D
0D69:001A 206361        AND     [BP+DI+61],AH
0D69:001D 6E            DB      6E
0D69:001E 6E            DB      6E
0D69:001F 6F            DB      6F
于 2009-04-16T14:29:23.137 回答
2

MSDN上的win32 exe格式

我建议使用一些 Windows C 源代码并在 Visual Studio 中构建并开始调试它。切换到反汇编视图并单步执行命令。您可以看到 C 代码是如何被编译成机器代码的 - 并观看它一步一步地运行。

于 2009-04-16T14:35:59.360 回答
2

如果它看起来对你来说很陌生,我认为调试器或反汇编器不会有帮助——你需要先学习汇编程序;研究处理器的架构(可从 Intel 下载大量文档)。然后由于大多数机器代码是由编译器生成的,因此您需要了解编译器如何生成代码 - 编写大量小程序然后反汇编它们以查看您的 C/C++ 变成了什么的最简单方法。

几本书可以帮助您理解:-

于 2009-04-16T14:50:56.533 回答
2

就这个问题而言,还有人读过CD 21之类的东西吗?

我记得 Sandra Bullock 在一个节目中,实际上是在阅读一屏十六进制数字并弄清楚程序的作用。有点像当前版本的阅读矩阵代码。

如果你确实读过 CD 21 之类的东西,你如何记住不同的组合?

于 2009-04-16T16:53:56.257 回答
2

为了得到一个想法,在一些有趣的代码上设置一个断点,然后转到 CPU 窗口。

如果您对更多内容感兴趣,使用 -al 参数使用 Free Pascal 编译短片段会更容易。

FPC 允许使用 -A 参数以多种汇编器格式(TASM、MASM、GAS)输出生成的汇编器,并且您可以在注释(和更多)中交错显示原始帕斯卡代码,以便于交叉引用。

因为它是编译器生成的汇编程序,而不是从反汇编的 .exe 汇编程序,所以它更具符号性且更易于理解。

于 2009-05-08T13:58:32.807 回答
2

熟悉低级组装(我的意思是低级组装,而不是“宏”和那头公牛)可能是必须的。如果您真的想直接阅读原始机器代码本身,通常您会使用十六进制编辑器。然而,为了理解指令的作用,大多数人会使用反汇编程序将其转换为适当的汇编指令。如果您是少数想要了解机器语言本身的人之一,我认为您会想要英特尔® 64 和 IA-32 架构软件开发人员手册第 2 卷专门介绍了指令集,它与您关于如何阅读机器代码本身以及汇编与它的关系的查询有关。

于 2009-09-25T05:15:38.370 回答
1

你的好奇心和你的理解水平正是我曾经的位置。我强烈推荐Code: The Hidden Language of Computer Hardware and Software。这不会回答你在这里提出的所有问题,但它会揭示计算机的一些完全黑魔法的方面。这是一本厚厚的书,但可读性很高。

于 2009-04-16T17:59:37.613 回答
1

ACD See 可能利用了 .EXE 文件不对文件长度或超出文件预期部分长度的任何内容进行错误检查这一事实。因此,您可以制作一个 .EXE 文件,该文件将打开其自身并将超出给定点的所有内容作为数据加载。这很有用,因为您可以制作一个适用于给定数据集的 .EXE,只需在适当编写的 .EXE 末尾添加该数据即可

(我不知道 ACD See 到底是什么,所以请多加注意,但我知道有些程序是这样生成的。)

于 2009-04-17T18:55:34.083 回答
-2

每条指令都以机器代码形式保存在 cpu 内的特殊内存区域中。EARLY INTEL 书籍中给出了指令的机器码,因此应该尝试获取此类书籍以便理解这一点。显然,今天机器代码不容易获得。一个可以将十六进制反转为机器代码的程序会很好。或者手动做_!! 乏味

于 2019-01-19T19:26:27.333 回答