了解二进制炸弹的汇编代码

时间:2014-03-14 18:27:08

标签: assembly x86

我一直在努力了解一些我在课堂上必须做的实验室的汇编代码,并且希望由那些能指出我正确方向的人来解释。 代码如下:

   0x080488bb <+0>:     push   %esi
   0x080488bc <+1>:     push   %ebx
   0x080488bd <+2>:     sub    $0x34,%esp
   0x080488c0 <+5>:     mov    $0x0,%esi
   0x080488c5 <+10>:    mov    $0x0,%ebx
   0x080488ca <+15>:    lea    0x1c(%esp,%ebx,4),%eax
   0x080488ce <+19>:    mov    %eax,0x4(%esp)
   0x080488d2 <+23>:    movl   $0x8048c8d,(%esp)
   0x080488d9 <+30>:    call   0x80484e0 <__isoc99_scanf@plt>
   0x080488de <+35>:    test   %eax,%eax
   0x080488e0 <+37>:    jns    0x80488ee <phase_3_of_5+51>
   0x080488e2 <+39>:    movl   $0x3,(%esp)
   0x080488e9 <+46>:    call   0x80487c2 <explode>
   0x080488ee <+51>:    mov    0x1c(%esp,%ebx,4),%eax
   0x080488f2 <+55>:    add    %eax,%esi
   0x080488f4 <+57>:    add    $0x1,%ebx
   0x080488f7 <+60>:    cmp    $0x5,%ebx
   0x080488fa <+63>:    jne    0x80488ca <phase_3_of_5+15>
   0x080488fc <+65>:    cmp    $0x64,%esi
   0x080488ff <+68>:    je     0x804890d <phase_3_of_5+82>
   0x08048901 <+70>:    movl   $0x3,(%esp)
   0x08048908 <+77>:    call   0x80487c2 <explode>
   0x0804890d <+82>:    add    $0x34,%esp
   0x08048910 <+85>:    pop    %ebx
   0x08048911 <+86>:    pop    %esi
   0x08048912 <+87>:    ret

根据我收集的内容,此功能将接受两个输入(来自两个推送)。 __isoc99_scanf @ plt将一系列输入保存为字符串。

第一部分我很困惑的是&#34;测试%eax,%eax&#34;这本质上是比较eax的价值吗?我查看了堆栈溢出中的另一个线程,其中有一个有类似问题的人,其中一个解决方案说%eax必须为零才能使该语句为真。

如果上述陈述为真,我们继续前进至+51。 +51表示存储在0x1c中的eax = esp + ebx * 4。然后我们添加eax + esi并将其存储在esi中。然后我们将1添加到ebx。然后我们将5与ebx进行比较。如果不相等则返回+15。如果它相等则移动到+65,将64与esi进行比较。如果它们相等则功能结束。

如果我的解释错误,或者您认为可以澄清的部分,请告诉我。

编辑:我的主要目标是弄清楚我应该输入什么,以便程序在不调用爆炸函数的情况下完成。

我已将其缩小为两个输入,ebx必须为5才能继续通过一个部分。 esi必须是64才能继续下一部分。我唯一的问题是esi依赖于eax的价值,我不知道。

4和48不是正确的答案,有什么建议吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

test %eax,%eaxand注册eax。此操作的唯一实际效果是设置CPU标志。下一条指令是jns 0x80488ee <phase_3_of_5+51>。如果由于前一个test指令而未设置符号位,则跳转到+51

基本上,如果eax的高位为0,则它​​采用分支。如果高位为1,则它会通过。

答案 1 :(得分:0)

From what I gathered this function will take two inputs(from both the pushes)

如果你的意思是前两行,那些只是将寄存器esiebx保存在堆栈上,因为调用约定说它们必须保留。最后的代码将恢复它们。这与此函数占用的参数数量或scanf将处理的数量无关。

scanf获得2个参数,第一个是格式字符串,位于内存中的地址0x8048c8d。我想如果你查看它的价值,你会发现它只是一个"%d"。第二个参数是堆栈上的局部变量的地址,这将接收输入数字。 (它实际上是数组的一个元素,但这并不重要。)

然后检查scanf的返回值以查看是否EOF或发生了错误。

+51然后加载已转换的输入数字并将其添加到esi,然后递增ebx并循环回读取另一个数字(如果它小于5)。这意味着,代码一个接一个地读取五个数字,并总结它们。

最后,将总和与0x64进行比较,其中十进制为100。

TL; DR:您需要输入总和为100的任意5个数字。