如何手动读写.exe机器码?

16

我对编译器的魔法不是很熟悉。将人类可读的代码(或者几乎不可读的汇编指令)转换成机器码,对我来说就像是融合了火箭科学和巫术。

我将问题范围缩小到Win32可执行文件(.exe)。当我在专用的查看器中打开这些文件时,我可以在各个地方找到散落的字符串(通常每个字符16位),但其余部分都是垃圾。我想未读取的部分(大部分)是机器码(或者可能是资源,如图像等等)。

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

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

我如何理解EXE文件内部发生了什么?


1
ACDSee技巧将使用预编译程序,并编辑其资源。请参见http://www.silurian.com/win32/peformat.htm并尝试使用Process Explorer(http://live.sysinternals.com/procexp.exe)。 - Mark
谢谢,看起来很不错。而且Process Explorer真是太棒了。几个月前开始使用它,简直太神奇了。每次运行它,我都忍不住想知道他们是如何做到的...??? - Peter Perháč
这里只是一个延迟的评论;你最终是如何处理它的?你成功走得很远吗? - dreamlax
13个回答

16

OllyDbg 是一个很棒的工具,它可以将可执行文件反汇编成易读的指令,并允许你逐条执行这些指令。它还可以告诉你程序使用了哪些 API 函数以及可能提供的参数(只要这些参数在堆栈中被找到)。

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

你可以阅读 Paul Carter 博士的PC Assembly Language Tutorial,这是一本入门级别的免费书籍,介绍了汇编语言和英特尔 386 CPU 的工作原理。其中大部分知识即使在现代的消费级英特尔 CPU 中也适用。

EXE 格式是特定于 Windows 的。入口点(即第一条可执行指令)通常在 EXE 文件中相同的位置上找到。这些内容一下子讲解可能有些困难,但我提供的资源应该能够满足你的一部分好奇心! :)


2
这是非常好的回答。你说得对,我很好奇。并不是因为我需要去反汇编可执行文件,而是我非常感兴趣,并想稍微玩弄一下可执行文件。当我理解了当前超出我的视野的东西时,会有一种“哇”的感觉 :) - Peter Perháč

6
你需要一个反汇编器,将机器代码转换为汇编语言。这个维基百科链接描述了这个过程,并提供了免费的反汇编器链接。当然,正如你所说,你不理解汇编语言,这可能并不是很有用——那么你到底想做什么呢?

无法链接到Windbg http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx - Mark

5

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

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

今天学到了新东西。希望我不会很快破坏我的操作系统。当我对调整注册表条目感到过度兴奋时,曾经发生过一次...再也没有看到我的桌面了。 - Peter Perháč
您也可以编写新代码并将其保存回文件。只有疯子[或黑客]才会使用Debug。 - Dead account
把我算作那些仍在使用debug的少数人之一。顺便提一下:微软的DEBUG只能反汇编16位实模式。如果你需要一个32位DPMI兼容的debug,可以试试japheth的版本:http://www.japheth.de/debxxf.html - Coding With Style

5
您看到的可执行文件是Microsoft的PE(Portable Executable)格式。它本质上是一个容器,其中包含有关程序的操作系统特定数据以及程序数据本身分成几个部分存储,例如代码、资源和静态数据都存储在单独的部分中。
部分的格式取决于其中的内容。代码部分保存着根据可执行目标架构的机器代码。在最常见的情况下,Microsoft PE二进制文件的架构是Intel x86或AMD-64(与EM64T相同)。机器代码的格式是CISC,起源可以追溯到8086及更早的时期。 CISC的重要方面是其指令大小不是固定的,您必须从正确的位置开始阅读才能获得有价值的东西。 Intel在x86 / x64指令集上发布了良好的手册。
您可以使用反汇编器直接查看机器代码。结合手册,您大多数时间都可以猜测源代码。
然后还有MSIL EXE:.NET可执行文件保存着Microsoft的中间语言,其中不包含机器特定代码,而是.NET CIL代码。该规范可在ECMA网站上在线获取。
这些可以使用诸如Reflector之类的工具查看。

5
EXE文件的内容在可移植可执行文件中有描述。它包含代码、数据和指令,告诉操作系统如何加载文件。
机器码和汇编语言之间存在1:1的映射关系。反汇编程序将执行相反的操作。
在i386上,每个指令的字节数没有固定的数量。有些指令只有一个字节,而有些指令则要长得多。

3

关于这个问题,还有人会读CD 21之类的东西吗?

我记得桑德拉·布洛克在一部节目中,实际上读了一屏十六进制数,并弄清了程序的作用。有点像现在阅读Matrix代码的版本。

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


同样的,不懂英语的程序员也可以学习使用英语语法的编程语言。我认为任何在DOS中进行过低级编程的人都会记得CD 21。 - Coding With Style

2

MSDN上的Win32 exe格式

我建议您拿一些Windows C源代码,在Visual Studio中构建并开始调试。切换到反汇编视图并逐个步骤地执行命令。您可以看到C代码已编译为机器码 - 并逐步观察其运行。


2
如果这对你来说像外语一样陌生,我认为调试器或反汇编器是无法帮助你的 - 你需要先学习汇编语言编程;研究处理器的架构(英特尔提供了大量可下载的文档)。因为大部分机器码是由编译器生成的,所以你需要了解编译器如何生成代码 - 最简单的方法是编写许多小程序,然后将它们反汇编以查看你的C/C++被转换成了什么。
有几本书可以帮助你理解:
- 逆向工程 - 黑客攻防:渗透测试实战指南

2

想要了解情况,可以在一些有趣的代码上设置断点,然后转到CPU窗口。

如果您想了解更多信息,可以使用-al参数编译Free Pascal的短片段更容易。

FPC允许使用-A参数以多种汇编格式(TASM、MASM、GAS)输出生成的汇编程序,并且您可以将原始Pascal代码交错在注释中(等等),以便进行轻松的交叉引用。

因为它是编译器生成的汇编程序,而不是从反汇编的.exe获得的汇编程序,所以它更具象征意义,更易于跟踪。


+1,我偶尔使用Delphi,并对CPU、FPU等窗口感到好奇,可以从一条指令跳转到另一条指令并查看正在发生的事情。我想知道这些指令是如何制成EXE文件的,以及如何生成EXE文件(参见ACD See示例)。我特别喜欢BCS介绍的想法 :) - Peter Perháč
http://www.stack.nl/~marcov/compiler.pdf 是 Crenshaw 教程几乎不可或缺的 PDF 版本。不幸的是,它面向不同的 CPU(m68k),但它漂亮地阐述了编译器的基础知识。 - Marco van de Voort

2
熟悉低级汇编语言(我指的是真正的低级汇编语言,而不是“宏”之类的东西)可能是必需的。如果你真的想直接阅读原始机器代码本身,通常会使用十六进制编辑器。但是,为了理解指令的作用,大多数人会使用反汇编器将其转换为适当的汇编指令。如果你是想要理解机器语言本身的少数人之一,我认为你需要查看Intel® 64和IA-32体系结构软件开发人员手册。其中第2卷专门介绍了指令集,与您关于如何阅读机器代码本身以及汇编语言如何与之相关的问题有关。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接