尝试对功能进行逆向工程 [英] Trying to reverse engineer a function

查看:73
本文介绍了尝试对功能进行逆向工程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图更多地了解x86中的汇编.我在这里有一个神秘函数,我知道它返回一个int并接受一个int参数. 因此它看起来像int mystery(int n){}.我无法弄清楚C中的功能.程序集是:

I'm trying to understand assembly in x86 more. I have a mystery function here that I know returns an int and takes an int argument. So it looks like int mystery(int n){}. I can't figure out the function in C however. The assembly is:

mov  %edi, %eax
lea  0x0(,%rdi, 8), %edi
sub  %eax, %edi
add  $0x4, %edi
callq < mystery _util >
repz retq

< mystery _util >
mov  %edi, %eax
shr  %eax
and  $0x1, %edi
and  %edi, %eax
retq

我不明白地方政府在这里的作用以及它可能具有的功能.

I don't understand what the lea does here and what kind of function it could be.

推荐答案

汇编代码似乎是计算机生成的,可能是由GCC编译的,因为无条件分支(call)之后有repz retq .还有一种迹象表明,由于在转到mystery_util时没有尾部调用(jmp)而不是call,因此代码是用-O1编译的(较高的优化级别可能会内联该函数,在这里没有发生).缺少帧指针和额外的加载/存储空间表明它没有使用-O0

The assembly code appeared to be computer generated, and something that was probably compiled by GCC since there is a repz retq after an unconditional branch (call). There is also an indication that because there isn't a tail call (jmp) instead of a call when going to mystery_util that the code was compiled with -O1 (higher optimization levels would likely inline the function which didn't happen here). The lack of frame pointers and extra load/stores indicated that it isn't compiled with -O0

x乘以7等于将x乘以8并减去x.那就是下面的代码正在做的事情:

Multiplying x by 7 is the same as multiplying x by 8 and subtracting x. That is what the following code is doing:

lea  0x0(,%rdi, 8), %edi
sub  %eax, %edi

LEA 可以计算地址,但也可以用于简单的算术运算.内存操作数的语法为置换(基数,索引,小数位数).比例可以是1、2、4、8.计算是位移+基准+索引*比例.在您的情况下,lea 0x0(,%rdi, 8), %edi实际上是EDI = 0x0 + RDI * 8或EDI = RDI *8.完整的计算为n * 7 -4;

LEA can compute addresses but it can be used for simple arithmetic as well. The syntax for a memory operand is displacement(base, index, scale). Scale can be 1, 2, 4, 8. The computation is displacement + base + index * scale. In your case lea 0x0(,%rdi, 8), %edi is effectively EDI = 0x0 + RDI * 8 or EDI = RDI * 8. The full calculation is n * 7 - 4;

mystery_util的计算似乎只是

n &= (n>>1) & 1;

如果将所有这些因素综合考虑,我们会得到一个函数mystery,该函数将n * 7-4传递给一个名为mystery_util的函数,该函数返回n &= (n>>1) & 1.

If I take all these factors together we have a function mystery that passes n * 7 - 4 to a function called mystery_util that returns n &= (n>>1) & 1.

由于mystery_util返回单个位值(0或1),因此bool是返回类型是合理的.

Since mystery_util returns a single bit value (0 or 1) it is reasonable that bool is the return type.

我很好奇能否获取优化级别为1(-O1)的 GCC 的特定版本来重现此汇编代码.我发现,对于给定的 C 程序,GCC 4.9.x将产生此确切的汇编代码:

I was curious if I could get a particular version of GCC with optimization level 1 (-O1) to reproduce this assembly code. I discovered that GCC 4.9.x will yield this exact assembly code for this given C program:

#include<stdbool.h>

bool mystery_util(unsigned int n)
{
    n &= (n>>1) & 1;
    return n;
}

bool mystery(unsigned int n)
{
    return mystery_util (7*n+4);
}

程序集输出为:

mystery_util:
        movl    %edi, %eax
        shrl    %eax
        andl    $1, %edi
        andl    %edi, %eax
        ret
mystery:
        movl    %edi, %eax
        leal    0(,%rdi,8), %edi
        subl    %eax, %edi
        addl    $4, %edi
        call    mystery_util
        rep ret

您可以在我在解释这个问题时显然犯了错误.我假设问这个问题的人自己确定mystery的原型是int mystery(int n).我以为我可以改变这一点.根据每天在Stackoverflow上问到的相关问题稍后,似乎int mystery(int n)作为原型被分配给您.这很重要,因为这意味着必须进行修改.

I apparently erred in interpreting the question. I assumed the person asking this question determined by themselves that the prototype for mystery was int mystery(int n). I thought I could change that. According to a related question asked on Stackoverflow a day later, it seems int mystery(int n) is given to you as the prototype as part of the assignment. This is important because it means that a modification has to be made.

需要进行的更改与mystery_util有关.这些行在反向工程代码中是:

The change that needs to be made is related to mystery_util. In the code to be reverse engineered are these lines:

mov  %edi, %eax
shr  %eax

EDI 是第一个参数. SHR 是逻辑右移.仅当 EDI unsigned int(或等效值)时,编译器才会生成此代码. int是带符号的类型,会生成 SAR (算术右移).这意味着mystery_util的参数必须为unsigned int(随之而来的是返回值很可能是unsigned int.这意味着代码将如下所示:

EDI is the first parameter. SHR is logical shift right. Compilers would only generate this if EDI was an unsigned int (or equivalent). int is a signed type an would generate SAR (arithmetic shift right). This means that the parameter for mystery_util has to be unsigned int (and it follows that the return value is likely unsigned int. That means the code would look like this:

unsigned int mystery_util(unsigned int n)
{
    n &= (n>>1) & 1;
    return n;
}

int mystery(int n)
{
    return mystery_util (7*n+4);
}

mystery现在具有您的教授给出的原型(已删除bool),我们将unsigned int用作mystery_util的参数和返回类型.为了使用GCC 4.9.x生成此代码,我发现您需要使用-O1 -fno-inline.可以在

mystery now has the prototype given by your professor (bool is removed) and we use unsigned int for the parameter and return type of mystery_util. In order to generate this code with GCC 4.9.x I found you need to use -O1 -fno-inline. This code can be found on godbolt. The assembly output is the same as the version using bool.

如果使用unsigned int mystery_util(int n),您会发现它并没有完全输出我们想要的:

If you use unsigned int mystery_util(int n) you would discover that it doesn't quite output what we want:

mystery_util:
        movl    %edi, %eax
        sarl    %eax          ; <------- SAR (arithmetic shift right) is not SHR
        andl    $1, %edi
        andl    %edi, %eax
        ret

这篇关于尝试对功能进行逆向工程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆