二元炸弹 - 第 4 阶段

Posted

技术标签:

【中文标题】二元炸弹 - 第 4 阶段【英文标题】:Binary Bomb - Phase 4 【发布时间】:2013-11-07 12:59:23 【问题描述】:

我很难追踪以下二进制炸弹的汇编代码(来自学校的一个必须拆除炸弹的作业,该炸弹包含 6 个阶段,所有阶段都有 1 个正确输入以进行下一阶段) .我目前在 phase_4 上,它有一个名为 func4 的递归函数。我已经确定输入是“%d %d”,它是两个整数。但是,即使在每一步都获取了所有寄存器的信息之后,我也无法完全弄清楚 func4 在做什么。

阶段_4:

    (gdb) disas
Dump of assembler code for function phase_4:
=> 0x08048e24 <+0>: sub    $0x2c,%esp
   0x08048e27 <+3>: lea    0x1c(%esp),%eax
   0x08048e2b <+7>: mov    %eax,0xc(%esp)
   0x08048e2f <+11>:    lea    0x18(%esp),%eax
   0x08048e33 <+15>:    mov    %eax,0x8(%esp)
   0x08048e37 <+19>:    movl   $0x804a7f1,0x4(%esp)
   0x08048e3f <+27>:    mov    0x30(%esp),%eax
   0x08048e43 <+31>:    mov    %eax,(%esp)
   0x08048e46 <+34>:    call   0x80488d0 <__isoc99_sscanf@plt>
   0x08048e4b <+39>:    cmp    $0x2,%eax
   0x08048e4e <+42>:    jne    0x8048e5d <phase_4+57>
   0x08048e50 <+44>:    mov    0x18(%esp),%eax
   0x08048e54 <+48>:    test   %eax,%eax
   0x08048e56 <+50>:    js     0x8048e5d <phase_4+57>
   0x08048e58 <+52>:    cmp    $0xe,%eax
   0x08048e5b <+55>:    jle    0x8048e62 <phase_4+62>
   0x08048e5d <+57>:    call   0x8049470 <explode_bomb>
   0x08048e62 <+62>:    movl   $0xe,0x8(%esp)
   0x08048e6a <+70>:    movl   $0x0,0x4(%esp)
   0x08048e72 <+78>:    mov    0x18(%esp),%eax
   0x08048e76 <+82>:    mov    %eax,(%esp)
   0x08048e79 <+85>:    call   0x8048dbb <func4>
   0x08048e7e <+90>:    cmp    $0x25,%eax
   0x08048e81 <+93>:    jne    0x8048e8a <phase_4+102>
   0x08048e83 <+95>:    cmpl   $0x25,0x1c(%esp)
   0x08048e88 <+100>:   je     0x8048e8f <phase_4+107>
   0x08048e8a <+102>:   call   0x8049470 <explode_bomb>
   0x08048e8f <+107>:   add    $0x2c,%esp
   0x08048e92 <+110>:   ret    
    End of assembler dump.

func4:

Breakpoint 2, 0x08048dbb in func4 ()
(gdb) disas
Dump of assembler code for function func4:
=> 0x08048dbb <+0>: sub    $0x1c,%esp
   0x08048dbe <+3>: mov    %ebx,0x14(%esp)
   0x08048dc2 <+7>: mov    %esi,0x18(%esp)
   0x08048dc6 <+11>:    mov    0x20(%esp),%eax
   0x08048dca <+15>:    mov    0x24(%esp),%edx
   0x08048dce <+19>:    mov    0x28(%esp),%esi
   0x08048dd2 <+23>:    mov    %esi,%ecx
   0x08048dd4 <+25>:    sub    %edx,%ecx
   0x08048dd6 <+27>:    mov    %ecx,%ebx
   0x08048dd8 <+29>:    shr    $0x1f,%ebx
   0x08048ddb <+32>:    add    %ebx,%ecx
   0x08048ddd <+34>:    sar    %ecx
   0x08048ddf <+36>:    lea    (%ecx,%edx,1),%ebx
   0x08048de2 <+39>:    cmp    %eax,%ebx
   0x08048de4 <+41>:    jle    0x8048dfd <func4+66>
   0x08048de6 <+43>:    lea    -0x1(%ebx),%ecx
   0x08048de9 <+46>:    mov    %ecx,0x8(%esp)
   0x08048ded <+50>:    mov    %edx,0x4(%esp)
   0x08048df1 <+54>:    mov    %eax,(%esp)
   0x08048df4 <+57>:    call   0x8048dbb <func4>
   0x08048df9 <+62>:    add    %eax,%ebx
   0x08048dfb <+64>:    jmp    0x8048e16 <func4+91>
   0x08048dfd <+66>:    cmp    %eax,%ebx
   0x08048dff <+68>:    jge    0x8048e16 <func4+91>
   0x08048e01 <+70>:    mov    %esi,0x8(%esp)
   0x08048e05 <+74>:    lea    0x1(%ebx),%edx
   0x08048e08 <+77>:    mov    %edx,0x4(%esp)
   0x08048e0c <+81>:    mov    %eax,(%esp)
   0x08048e0f <+84>:    call   0x8048dbb <func4>
   0x08048e14 <+89>:    add    %eax,%ebx
   0x08048e16 <+91>:    mov    %ebx,%eax
   0x08048e18 <+93>:    mov    0x14(%esp),%ebx
   0x08048e1c <+97>:    mov    0x18(%esp),%esi
   0x08048e20 <+101>:   add    $0x1c,%esp
   0x08048e23 <+104>:   ret    
End of assembler dump.

【问题讨论】:

我还能够确定 int 必须大于 0,但除此之外我迷路了。 这有帮助吗? ***.com/q/18961406/56778。在这里搜索“二元炸弹”,或者只看右边的相关问题。 ------------> 如果我能在搜索中找到它,我不会问这个问题。 【参考方案1】:

我希望很明显phase4 正在检查第一个数字是否在0..14 范围内(请参阅行+44..+57) 然后它使用三个参数调用func4:输入的第一个数字014(行+62..+85)。接下来,它检查+90 行上的返回值是0x25(十进制37)并且输入的第二个数字也是37+95 行)

让我们继续func4。我将调用这三个参数xlowhigh。最初你当然不知道它们是什么。行+23..+34 计算(high - low) / 2。丑陋的混乱是因为编译器生成代码来处理截断为零的负数。不过,我们不会看到任何负数。行+36 只是一个花哨的加法,所以在ebx 中我们现在有low + (high - low) / 2,它也被称为两个数字的平均值。然后代码将该平均值与作为第一个参数提供的数字x 进行比较。 +43..+62 行在 x &lt; average 时执行,它们调用 func4(x, low, average - 1) 并将返回值添加到平均值中。同样,+70..+89 行在 x &gt; average 时执行并计算 average + func4(x, average + 1, high)。如果x == average 则只返回平均值本身。

它基本上是在进行二进制搜索并总结猜测。鉴于区间有 15 个元素,它最多需要 4 次猜测。第一个猜测是7,所以要得到37 的所需结果,我们需要更多30。我们最多还有 3 次尝试,所有的猜测都将小于 7 或大于 7。由于7 * 3 = 21 不能给我们30,这意味着数字必须大于 7。第二个猜测是因此将是(8 + 14) / 2 = 11,使我们的总和1819 更多。如果数字高于 11,则意味着我们超出了目标,因此该数字必须大于 7 且小于 11。因此,第三个猜测是 (8 + 10) / 2 = 9,这使总和为 27,而 10 更多只是一个猜测,所以这意味着数字是10

TL;DR:正确的输入应该是 1037

【讨论】:

哇,太棒了。你的解释让一切变得如此清楚。我看到了 0-14 的范围,但我不知道 func4 本身在做什么。我自己看到了 37,但我没有意识到这将是第二个输入。非常感谢您的好先生! @petrov 你能解释一下你是怎么得到 0-14 的吗?我糊涂了。第 52 行,%eax

以上是关于二元炸弹 - 第 4 阶段的主要内容,如果未能解决你的问题,请参考以下文章

二元炸弹(第 4 阶段)%d %d

如何解决二元炸弹实验阶段 6?

我在处理这个二元炸弹任务时遇到了麻烦

炸弹实验室作业第 5 阶段 - 编写其 C 等效项

炸弹实验室第 6 阶段:卡在最后一步

标记阶段的标记类