炸弹实验室第4阶段

时间:2014-10-11 13:54:55

标签: assembly reverse-engineering x86-64

Dump of assembler code for function func4
    <+0>: mov %rbx,-0x18(%rsp)
    <+5>: mov %rbp, -0x10(%rsp)
    <+10>: mov %r12,-0x8(%rsp)
    <+15>: sub $0x18,%rsp
    <+19>: mov %edi,%ebx
    <+21>: mov %esi,%ebp
    <+23>: test %edi, %edi
    <+25>: jg 0x400fb2<func4+34>
    <+27>: mov $0x0,%ebp
    <+32>: jmp 0x400fd2<func4+66>
    <+34> cmp $0x1, %edi
    <+37>: je 0x400fd2<func4+66>
    <+39>: lea -0x1(%rbx),%edi
    <+42>: callq 0x400f90 <func4>
    <+47>: mov %eax,%r12d
    <+50>: lea -0x2(%rbx),%edi
    <+53>: mov %ebp,%esi
    <+55>: callq 0x400f90 <func4>
    <+60>: lea (%r12,%rax,1),%eax
    <+64>: add %eax,ebp
    <+66>: mov %ebp, %eax
    <+68>: mov (%rsp),%rbx
    <+72>: mov 0x8(%rsp), %rbp
    <+77>: mov 0x10(%rsp),%r12
    <+82>: add $0x18,%rsp
    <+86>: retq

这是func4的反汇编代码。 而且我不确定我是否正确理解这个功能。

我在这里没有编写phase_4的反汇编代码, 但它需要&#34;%d%d&#34;输入,并且第一整数应该在范围1 <= x <4中。 所以它应该是1,2或3。 寄存器%edi的值最初为7。 在调用func4之后,代码比较0x10(%rsp)和%eax的值 所以我应该知道调用func4后的%eax值。

我想,func4的反汇编代码意味着

put the stack
ebx = edi
ebp = esi
if edi is not zero
    if edi is one: then eax=ebp.
                   rearrange the stack
                   return.
    else: edi = -0x1(rbx)
          func4
          r12d = eax
          edi = -0x2(rbx)
          esi = ebp
          func4
          eax = rax+r12+ebp
          rearrange the stack and return.
else
    ebp=0
    eax=ebp
    return

但凭据我的理解,我无法解决它。 例如,如果%rsp的原始地址是0x7fffffffd5a8 那么地址会更小,直到edi的值变为0。 我发现0x7fffffffd56f的值为0 - 并且第一个func4调用结束 - 但是在0x7fffffffd56e的值也为0之后 - 所以第二个func4调用结束 - 并且所有寄存器都变为0,包括eax。

所以我认为第二个数字的答案是零, 但是(1,0),(2,0),(3,0)总是爆炸炸弹。

你猜到我错在哪里并帮忙?

1 个答案:

答案 0 :(得分:2)

ediesifunc4的两个参数。这是根据标准调用约定,但也可以从这些寄存器未经初始化使用的事实推断出来,因此它们的值必须来自外部。因此,原型是int func4(int a, int b)

+23检查是否a > 0,如果是,则跳开。因此,如果条件为假,我们可以轻松跟踪发生的情况:

if (a <= 0) return 0;

+34正在检查是否为a == 1,如果是,则返回ebp的当前值,但已从esi初始化,这是第二个参数,b

if (a == 1) return b;

否则,行+39 .. +55以递归方式调用func4。行+60将两个调用的结果一起添加,行+64添加b。所以我们有:

return func4(a - 1, b) + func4(a - 2, b) + b;

由此可以计算任何输入的返回值。

当然,如果您被允许使用调试器,您可以让代码运行并查看eax的值是什么;)