关于汇编的 3 个问题 - 高级代码(例如 C++)中的语法、含义和等价物

逆向工程 部件 反编译 二进制
2021-07-10 09:57:35

对于以下示例,使用 AT&T 格式的 x86 代码:

xor $0x20, (%eax) 
and $0x20, %ah 
or $0x20, %dh 
dec (%edi) 
dec %si
dec %sp
dec %bp

我的理解:

Line 1: takes value in %eax and does an XOR operation with 0x20

Line 2: takes value in %ah and dies an AND operation with 0x20

Line 3:  takes value in %dh and does an OR operation with 0x20.

Line 4: decrements value in %edi by 1

Line 5: decrements value in %si by 1

Line 6: decrements value in %sp by 1

Line 7: decrements value in %bp by 1

问题:

  1. 运行每一步代码后,结果会发生什么变化?

  2. 操作数的顺序重要吗?如果是,为什么?

  3. 你如何从这个汇编代码构造一些等效的代码(例如反编译成 c++)?

这不是作业问题 - 我是组装新手。示例代码不是来自实际代码 - 它是为了帮助我更好地理解和说明我的问题。

2个回答

注意:此答案对应于原始问题

我也是组装新手,所以我可以看到你来自哪里。话虽如此,您发布的人为代码似乎存在不少问题。

操作数的顺序重要吗?如果是,为什么?

有两种不同风格的人类可读助记符用于表示 CPU 指令代码:AT&T 和 Intel。虽然 Intel 和 AT&T 语法中操作数的显示顺序不同,但内存中指令代码字节的顺序是恒定的。

英特尔语法:

08048074 <main>:
 8048074:       55                      push   ebp
 8048075:       89 e5                   mov    ebp,esp
 8048077:       b8 00 00 00 00          mov    eax,0x0
 804807c:       5d                      pop    ebp
 804807d:       c3                      ret    

AT&T 语法:

08048074 <main>:
 8048074:       55                      push   %ebp
 8048075:       89 e5                   mov    %esp,%ebp
 8048077:       b8 00 00 00 00          mov    $0x0,%eax
 804807c:       5d                      pop    %ebp
 804807d:       c3                      ret  

的(小端)字节序列89 e5表示为mov ebp,esp在Intel语法和mov %esp,%ebp在AT&T的语法。尽管操作数的助记表示彼此相反,但它们表示相同的字节序列。操作码助记符的顺序很重要,因为它由用于表示指令代码的语法决定。

代码

运行每一步代码后,结果会发生什么变化?

除了最后一行之外,问题中发布的每一行代码都至少包含一个非法操作数,因此只有该行可以运行。

假设使用 AT&T 语法。

0x2000: cs cs cs

  • %cs段寄存器,作为寄存器,必须以%符号为前缀这里有3个操作数,都是同一个寄存器,没有指令。这是非法的。我不确定你预想的会发生在这里。

0x2001: xor x20,(eax)

  • x20是非法操作数。常量是立即数操作数,必须以$符号为前缀,所以这个操作数应该是$0x20%eax是一个寄存器,因此%需要前缀。(eax)应该是(%eax).

0x2002: and x20,%ah

  • x20 应该 $0x20

0x2003: or x20, %dh

  • x20 应该 $0x20

0x2004: dec (ebi)

  • ebi看起来它应该是一个寄存器。你是说%edi还是%ebx无论哪种方式,它都缺少%前缀

0x2005: dec %si

  • dec指令将其操作数的内容减一。所以存储的值%si会递减。

修复了,代码看起来像这样:

xor $0x20, (%eax)
and $0x20, %ah
or  $0x20, %dh
dec (%edi)
dec %si

你如何从这个汇编代码构造一些等效的代码(例如 c++)?

假设更正后的代码实际上是正确的,具有足够理解力的人可以简单地查看这个片段并用高级语言创建一个大致等效的语句或语句序列。对于凡人来说,有称为反编译器的工具。

资源

Jonathan Bartlett 的“从头开始编程”和 Richard Blum 的“专业汇编语言”是非常好的 IMO。更具技术性的资源是System V Application Binary Interface Intel386 Architecture Processor Supplement,它揭示了处理器和虚拟内存的一些奥秘。SO 的 x86 wiki列出了许多资源。当然,还有英特尔手册

回答你的第三个问题,从计算机科学方面 c++ 或任何其他不是机器操作码的一对一助记符映射的高级语言;灵魂的目的是减轻复杂性。也就是说,我们可以推断出的 C++ 不是或不应该是与汇编的 1 对 1 映射。某些 c 语法无法完全映射。

例如,跳转语句将代码推进到任何其他字节。所以跳转可以像条件分支或函数调用等一样。C++ 中所有非常不同的语句都使用关键部分,跳转指令。

我认为更好的方法是询问 c++ 基本语句如何编译为汇编。如果您理解并知道,那么在汇编中找到这些块是一件简单的事情。

注意在现代设置中,大多数高级语言不会编译为 x86 汇编,而是编译为字节码或某些特定于操作的格式,通常与汇编相距不远,但又足够不同以至于它需要操作系统才能运行。这是为了抽象底层硬件,因此软件不必重新编译。