我有以下汇编代码:
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部分来自char数组,其上方的行(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
但是我只会遇到很多错误。
我已经尝试了许多小时,但是在解密此代码方面没有取得任何进展。任何帮助深表感谢。另外,有没有一种快速的方法(例如反编译器)可以在将来为我执行此操作?我也找不到。
答案 0 :(得分:1)
从直接翻译开始,然后从那里添加语义可能会更好。
(注意:我使用uint64_t
是因为该代码未进行任何已签名的比较。int64_t
将适用于此代码运行不到十年的所有值,但是uint64_t
更合适。)
// 0000000000400711 <foo>:
// 400711: 55 push rbp
// 400712: 48 89 e5 mov rbp,rsp
uint64_t foo(uint64_t n) {
// 400715: 48 89 7d e8 mov QWORD PTR [rbp-0x18],rdi
uint64_t i = n;
// 400719: 48 c7 45 f8 00 00 00 mov QWORD PTR [rbp-0x8],0x0
// 400720: 00
uint64_t sum = 0;
// 400721: eb 10 jmp 400733 <foo+0x22>
goto label_0x22;
label_0x12:
// 400723: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18]
uint64_t rax = i;
// 400727: 48 8d 50 ff lea rdx,[rax-0x1]
uint64_t rdx = rax - 1;
// 40072b: 48 89 55 e8 mov QWORD PTR [rbp-0x18],rdx
i = rdx;
// 40072f: 48 01 45 f8 add QWORD PTR [rbp-0x8],rax
sum += rax;
label_0x22:
// 400733: 48 83 7d e8 00 cmp QWORD PTR [rbp-0x18],0x0
// 400738: 75 e9 jne 400723 <foo+0x12>
if (i != 0) goto label_0x12;
// 40073a: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
// 40073e: 5d pop rbp
// 40073f: c3 ret
return sum;
}
去除注释:
uint64_t foo(int64_t n) {
uint64_t i = n;
uint64_t sum = 0;
goto label_0x22;
label_0x12:
uint64_t rax = i;
uint64_t rdx = rax - 1;
i = rdx;
sum += rax;
label_0x22:
if (i != 0) goto label_0x12;
return sum;
}
这应该可以工作(如果不行,则可能只需要在两个标签之间的代码周围加上大括号),但是无论哪种方式,它都是丑陋的。 goto
和标签更适合作为while
循环。
uint64_t foo(int64_t n) {
uint64_t i = n;
uint64_t sum = 0;
while (i != 0) {
uint64_t rax = i;
uint64_t rdx = rax - 1;
i = rdx;
sum += rax;
}
return sum;
}
现在,使用rax
和rdx
制作整个rigamarole的目标是获取i
的旧值,将其递减,然后将旧值添加到sum
。听起来像后缀递减可以优雅地完成工作。
uint64_t foo(uint64_t n) {
uint64_t i = n, sum = 0;
while (i != 0) { sum += i--; }
return sum;
}
(此外:这是一种执行代码看起来很慢的方法。一些数学运算会导致效率更高的uint64_t foo(uint64_t n) { return (n + 1) * n / 2; }
。)