从给定的x86程序集编写C函数

min*_*tle 4 c assembly gcc reverse-engineering x86-64

我正试图逆向设计这个神秘功能.此函数返回一个整数,并将struct节点作为参数

#include "mystery.h"
int mystery(struct e4_struct *s){}
Run Code Online (Sandbox Code Playgroud)

头文件是一个简单的结构声明

struct my_struct {
    int a;
    int b; 
};
Run Code Online (Sandbox Code Playgroud)

我试图逆向工程的组件是

400596:    8b 07                    mov    (%rdi),%eax
400598:    8d 04 40                 lea    (%rax,%rax,2),%eax
40059b:    89 07                    mov    %eax,(%rdi)
40059d:    83 47 04 07              addl   $0x7,0x4(%rdi)
4005a1:    c3                       retq  
Run Code Online (Sandbox Code Playgroud)

到目前为止,我认为功能如下:

int mystery(struct m_struct *s){
    int i = s->a;
    i = 3*i;
    int j = s->b;
    j += 7;
    return i;
}
Run Code Online (Sandbox Code Playgroud)

但这不正确.我不明白究竟mov %eax,(%rdi)是什么以及函数最终返回的是什么因为它应该返回和整数.

Mic*_*tch 7

假定RDI是指向结构开头的指针(函数的第一个参数),则以下行获取值s->a并将其放入临时寄存器EAX中.

mov    (%rdi),%eax
Run Code Online (Sandbox Code Playgroud)

合理的可能是int x = s->a.这一行:

lea    (%rax,%rax,2),%eax
Run Code Online (Sandbox Code Playgroud)

与将温度值乘以3相同,因为RAX + RAX*2 = 3*RAX(因此s-> a*3).所以前两行的装配可以表示为:

int x = s->a * 3;
Run Code Online (Sandbox Code Playgroud)

该行将mov %eax,(%rdi)获取临时值x并将其存储回s-> a,以便表示为:

s->a = x;
Run Code Online (Sandbox Code Playgroud)

该行在addl $0x7,0x4(%rdi)4(RDI)处将值加7.4(RDI)是s-> b的地址.这条线可以表示为s->b += 7;.

那么什么是作为价值返回?由于没有其他与完成EAX上面分析的代码之后,EAX是仍是年初的时候我们做了它的价值x = s->a * 3;.这意味着该函数正在返回临时值x.

然后代码看起来像这样:

int mystery(struct my_struct *s)
{
    int x = s->a * 3;
    s->a = x;
    s->b += 7;
    return x;    
}
Run Code Online (Sandbox Code Playgroud)

如果您编译此代码与GCC 4.9.x上godbolt-O1优化级别,我们得到这个生成的程序集:

mystery:
        movl    (%rdi), %eax
        leal    (%rax,%rax,2), %eax
        movl    %eax, (%rdi)
        addl    $7, 4(%rdi)
        ret
Run Code Online (Sandbox Code Playgroud)

具有不同优化级别的不同编译器将生成不同的程序集,这些程序集都将执行相同的操作.GCC 4.9.x恰好产生了我们最初逆向工程的精确汇编代码.


注意:我猜测了编译器和优化级别的版本,因为最近的SO问题具有不同的mystery功能,我发现GCC 4.9.x的优化级别-O1生成了我正在寻找的确切代码.似乎为这些神秘练习生成组装文件的人使用了这样的设置和类似的编译器.