use*_*612 2 c x86 assembly reverse-engineering att
我试图更多地了解x86中的汇编.我在这里有一个神秘的功能,我知道它会返回int
并接受一个int
参数.所以它看起来像int mystery(int n){}
.但我无法弄清楚C中的功能.大会是:
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
Run Code Online (Sandbox Code Playgroud)
我不明白lea在这里做了什么,它可能是什么样的功能.
汇编代码似乎是由计算机生成的,并且可能由GCC编译,因为有repz retq
一个无条件分支(call
).还有一个迹象表明,因为没有一个尾调用(jmp
),而不是call
去当mystery_util
代码被编译-O1
(较高的优化级别可能会内嵌其中并没有发生在这里的功能).缺少框架指针和额外的加载/存储表明它没有编译-O0
乘以x
7与乘以x
8并减去相同x
.这就是以下代码正在做的事情:
lea 0x0(,%rdi, 8), %edi
sub %eax, %edi
Run Code Online (Sandbox Code Playgroud)
LEA可以计算地址,但也可以用于简单算术.内存操作数的语法是位移(base,index,scale).比例可以是1,2,4,8.计算是位移+基数+指数*比例.在你的情况下lea 0x0(,%rdi, 8), %edi
,有效EDI = 0x0 + RDI*8或EDI = RDI*8.完整的计算是n*7 - 4;
计算mystery_util
似乎只是
n &= (n>>1) & 1;
Run Code Online (Sandbox Code Playgroud)
如果我把所有这些因素放在一起,我们就有一个函数mystery
将n*7 - 4传递给一个名为mystery_util
return 的函数n &= (n>>1) & 1
.
由于mystery_util
返回单个位值(0或1),因此bool
返回类型是合理的.
我很好奇是否可以获得具有优化级别1()的特定版本的GCC-O1
来重现此汇编代码.我发现GCC 4.9.x将为这个给定的C程序生成这个精确的汇编代码:
#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);
}
Run Code Online (Sandbox Code Playgroud)
程序集输出是:
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
Run Code Online (Sandbox Code Playgroud)
你可以在godbolt上玩这个代码.
我在解释这个问题时显然错了.我以为问自己确定原型这个问题的人mystery
是int mystery(int n)
.我以为我可以改变它.根据一天后在Stackoverflow上提出的相关问题,似乎int mystery(int n)
是作为作业的一部分给你作为原型.这很重要,因为这意味着必须进行修改.
需要做出的改变与mystery_util
.在要反向工程的代码中有以下几行:
mov %edi, %eax
shr %eax
Run Code Online (Sandbox Code Playgroud)
EDI是第一个参数.SHR是合乎逻辑的右移.如果EDI是unsigned int
(或等效的),编译器只会生成这个.int
是一个有符号的类型,它会生成SAR(算术右移).这意味着参数mystery_util
必须是unsigned int
(并且它可能是返回值unsigned int
.这意味着代码看起来像这样:
unsigned int mystery_util(unsigned int n)
{
n &= (n>>1) & 1;
return n;
}
int mystery(int n)
{
return mystery_util (7*n+4);
}
Run Code Online (Sandbox Code Playgroud)
mystery
现在有你的教授给出的原型(bool
被删除),我们unsigned int
用于参数和返回类型mystery_util
.为了使用GCC 4.9.x生成此代码,我发现您需要使用-O1 -fno-inline
.这个代码可以在godbolt上找到.程序集输出与使用的版本相同bool
.
如果你使用,unsigned int mystery_util(int n)
你会发现它不能完全输出我们想要的东西:
mystery_util:
movl %edi, %eax
sarl %eax ; <------- SAR (arithmetic shift right) is not SHR
andl $1, %edi
andl %edi, %eax
ret
Run Code Online (Sandbox Code Playgroud)