尝试对功能进行逆向工程 [英] Trying to reverse engineer a function
问题描述
我试图更多地了解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屋!