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

标签 c gcc assembly x86-64 reverse-engineering

我正在尝试对这个神秘函数进行逆向工程。 该函数返回一个整数并以一个结构节点作为参数

#include "mystery.h"
int mystery(struct e4_struct *s){}

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

struct my_struct {
    int a;
    int b; 
};

我要逆向工程的程序集是

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  

到目前为止我认为函数是这样的:

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

但这是不正确的。我不明白 mov %eax,(%rdi) 到底做了什么以及函数最终返回了什么,因为它应该返回整数。

最佳答案

鉴于 RDI 是指向结构开头的指针(函数的第一个参数),下面一行获取 s->a 的值并将其放置在临时寄存器 EAX 中。

mov    (%rdi),%eax

按理说这可能是 int x = s->a。这一行:

lea    (%rax,%rax,2),%eax

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

int x = s->a * 3;

mov %eax,(%rdi) 将采用临时值 x 并将其存储回 s->a 以便可以表示为:

s->a = x;

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;    
}

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

mystery:
        movl    (%rdi), %eax
        leal    (%rax,%rax,2), %eax
        movl    %eax, (%rdi)
        addl    $7, 4(%rdi)
        ret

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


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

关于c - 从给定的 x86 程序集编写 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49350723/

相关文章:

android - Linux ptrace() 读取整个内存页

c++ - gcc 奇怪的转换警告(从 ‘A<B>::count_type {aka short unsigned int}’ 转换到 ‘int’ 可能会改变它的值)

linux - x64 NASM 汇编程序在程序开始时显示段错误

assembly - 他们如何如此快地将十进制转换为十六进制(记住)?

winapi - 我们如何在组装中清除控制台?

c - bind()-ing UDP套接字到不同的地址

c++ - 如何包装std::vector以在纯C中使用

创建一个使用 2 个不同 ISA 的程序

c++ - 在不同的 C++ 编译器中有通用的解决方案来捕获异常类型被零除,段错误?

c++ - 在 Windows 的 MinGW 中打印堆栈跟踪