弄清楚一段汇编代码的作用

逆向工程 拆卸 部件 反编译
2021-06-18 09:32:08

我有以下汇编代码:

0000000000400711 <foo>:
  400711:   55                      push   rbp
  400712:   48 89 e5                mov    rbp,rsp
  400715:   48 89 7d e8             mov    QWORD PTR [rbp-0x18],rdi
  400719:   48 c7 45 f8 00 00 00    mov    QWORD PTR [rbp-0x8],0x0
  400720:   00
  400721:   eb 10                   jmp    400733 <foo+0x22>
  400723:   48 8b 45 e8             mov    rax,QWORD PTR [rbp-0x18]
  400727:   48 8d 50 ff             lea    rdx,[rax-0x1]
  40072b:   48 89 55 e8             mov    QWORD PTR [rbp-0x18],rdx
  40072f:   48 01 45 f8             add    QWORD PTR [rbp-0x8],rax
  400733:   48 83 7d e8 00          cmp    QWORD PTR [rbp-0x18],0x0
  400738:   75 e9                   jne    400723 <foo+0x12>
  40073a:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  40073e:   5d                      pop    rbp
  40073f:   c3                      ret

我已经尝试了几个小时来弄清楚这段代码的作用。从 C 代码到汇编代码转换器的反复试验,我很确定 QWORD 部分来自一个字符数组,它上面的行(push rbp、mov rbp、rsp)就像一个序言。我真的不知道如何解释这之后的行。我尝试将上述代码存储为一个名为“file.S”的文件,然后我使用以下 C 代码和终端命令来尝试弄清楚它的作用:

#include <stdio.h>
int foo(int, int);

int main()
{
   // printf() displays the string inside quotation
   printf("%d", foo(2,2));
   return 0;
}

我使用的终端命令是

gcc -g -Og -no-pie -fno-pie -m32 main.c file.S

但我只是收到一大堆错误。

我已经尝试了很多小时,但在破译此代码方面没有取得任何进展。任何帮助深表感谢。另外,将来有没有一种快速的方法(例如反编译器)可以为我做到这一点?我也找不到任何一个。

1个回答

首先,这是 64 位汇编,因为rax第一行中有寄存器 ( ,..) 和内存地址。因此,使用-m32编译为 32 位可执行文件的选项,您会遇到一些问题。

你说得对,第一部分,push rbp并且mov rbp,rsp是函数序言。

mov    QWORD PTR [rbp-0x18],rdi
mov    QWORD PTR [rbp-0x8],0x0

这两个 QWORDS 不是参数而是局部变量。您可以认识到这一点,因为负偏移量(变量位于基指针上方,堆栈向低地址增长)。x64 汇编器给出寄存器中的第一个参数,所以第一行是一个函数参数。第二个是局部变量。由于它们是 QWORDS,因此数据类型的长度为 8 个字节。第一条指令将 的值赋给rdi一个局部变量(比如var_18),第二条指令将0 赋给另一个局部变量(比如var_8)。

jmp    400733 <foo+0x22>

这是到该位置的无条件跳转,这400733意味着您将始终跳转到该位置所以我们需要在这个位置继续。

cmp    QWORD PTR [rbp-0x18],0x0
jne    400723 <foo+0x12>

400733我们看到一条比较指令,然后是条件跳转。比较检查局部变量var_18是否为 0,如果是,var_8则返回 的值(将值写入rax并返回)。否则,如果不是 0,我们跳转到400723

mov    rax,QWORD PTR [rbp-0x18]
lea    rdx,[rax-0x1]
mov    QWORD PTR [rbp-0x18],rdx
add    QWORD PTR [rbp-0x8],rax

继续400723前三个指令,将 的值减var_181。但减法之前的初始值被添加到var_8这似乎有点令人困惑,但如果您熟悉 C/C++,var--就会想到一条类似的指令,即减去变量之前使用变量的值

然后我们再次与 0 进行比较。所以回顾所有这些行,很明显这是一个循环,其中参数是一个数字,然后作为一个计数器,从这个数字向下计数到零。第二个局部变量var_8只是不同计数器值的总和。例如,如果var_18有 5,那么结果将是 5+4+3+2+1=15。

相应的 C 代码将与此类似。

long foo(long nr) {
    long var_8 = 0;

    while(nr != 0) {
        var_8 += nr--;
    } 
    return var_8;
}

另外,将来有没有一种快速的方法(例如反编译器)可以为我做到这一点?我也找不到任何一个。

是的,Hex-Rays Decompiler 可以完成这项工作。