二进制炸弹(binary bomb)——计算机体系与组成结构作业

这是来自于CS:APP的一个著名实验“拆解二进制炸弹”,也是我们的计算机组成与体系结构课程的家庭作业
这个实验也让我学会了怎么进行反汇编和使用GDB调试程序
解决问题的过程如下:

Phase_1
代码如下:

   0x0000000000400f2d <+0>:     sub    $0x8,%rsp
   0x0000000000400f31 <+4>:     mov    $0x402660,%esi

   0x0000000000400f36 <+9>:     callq  0x4013d6 <strings_not_equal>

   0x0000000000400f3b <+14>:    test   %eax,%eax
   0x0000000000400f3d <+16>:    je     0x400f44 <phase_1+23>
   0x0000000000400f3f <+18>:    callq  0x4016aa <explode_bomb>
   0x0000000000400f44 <+23>:    add    $0x8,%rsp
   0x0000000000400f48 <+27>:    retq 

可以看到第一个炸弹的触发条件在于%eax(函数返回值)是否为0.而由函数名字strings_not_equal可以看出当字符串不相等时返回1.我们只需让输入的第一个字符串和某个字符串内容相等即可。
观察程序可以发现,这个用来和我们输入的字符串作比较的字符串应该储存在0x402660这个地址。
打开GDB 输入

(gdb)disassemble x/s 0x402660
"And they have no disregard for human life."

因此第一道题的答案便是上面的字符串。

Phase_2

代码如下:

   0x0000000000400f67 <+30>:    cmpl   $0x0,(%rsp) # %rsp>0 which is the the top of the stack.
   0x0000000000400f6b <+34>:    jns    0x400f72 <phase_2+41>
   0x0000000000400f6d <+36>:    callq  0x4016aa <explode_bomb>

   0x0000000000400f72 <+41>:    mov    %rsp,%rbp #save the first parameter's address
   0x0000000000400f75 <+44>:    mov    $0x1,%ebx #save 1 in %ebx
   0x0000000000400f7a <+49>:    mov    %ebx,%eax #save %ebx in %eax 
   0x0000000000400f7c <+51>:    add    0x0(%rbp),%eax #add the first,second... parameter to %eax(1+bomb?if first is 1)
   0x0000000000400f7f <+54>:    cmp    %eax,0x4(%rbp) #compare %eax with second parameter
   0x0000000000400f82 <+57>:    je     0x400f89 <phase_2+64> #jump the bomb if it is equal
   0x0000000000400f84 <+59>:    callq  0x4016aa <explode_bomb>
   0x0000000000400f89 <+64>:    add    $0x1,%ebx # %ebx=%edx+1. I am defusing bomb(%ebx)
   0x0000000000400f8c <+67>:    add    $0x4,%rbp #next parameter
   0x0000000000400f90 <+71>:    cmp    $0x6,%ebx
   0x0000000000400f93 <+74>:    jne    0x400f7a <phase_2+49> #This is a circle until cmp $0x6,ebx is equal. Which means we need defuse 5 bombs.

这是一个有坑的程序,首先炸弹的触发条件很明确,一旦%eax和参数不相等,那么炸弹便会爆炸。在第一个循环时,%eaxparameter(i+1)做比较,以此类推。而%eax=%ebx+parameter(i),同时我们可以很惊奇的发现%ebx=i,所以整个问题便迎刃而解了。只要满足parameter(i+1)=parameter(i)+i即可,同时由开头的代码处的炸弹有,parameter1必须大于等于0.
而从最后的代码可以看出这个循环会进行5次,也就是对输入的前6个参数进行比较。所以答案可以是
1 2 4 7 11 16

Phase_3
代码如下:

   0x0000000000400fc5 <+20>:    lea    0x4(%rsp),%rcx # %rcx=%rsp+4 store the second parameter
   0x0000000000400fca <+25>:    mov    %rsp,%rdx # store the first parameter
   0x0000000000400fcd <+28>:    mov    $0x40295d,%esi # store address"0x40295d" it's"%d %d"
   0x0000000000400fd2 <+33>:    callq  0x400c40 <__isoc99_sscanf@plt>
   0x0000000000400fd7 <+38>:    cmp    $0x1,%eax # %eax = the number of parameters sscanf read
   0x0000000000400fda <+41>:    jg     0x400fe1 <phase_3+48> # %eax>1

   0x0000000000400fdc <+43>:    callq  0x4016aa <explode_bomb>

   0x0000000000400fe1 <+48>:    cmpl   $0x7,(%rsp) 
   0x0000000000400fe5 <+52>:    ja     0x40104c <phase_3+155> #bomb! if para1 >7
   0x0000000000400fe7 <+54>:    mov    (%rsp),%eax # %eax=para1
   0x0000000000400fea <+57>:    jmpq   *0x4026c0(,%rax,8) #shenmegui??? jump to address (*0x4026c0)+para1*8 400ff1

   0x0000000000400ff1 <+64>:    mov    $0x298,%eax #0x298
   0x0000000000400ff6 <+69>:    jmp    0x400ffd <phase_3+76>

   0x0000000000400ff8 <+71>:    mov    $0x0,%eax

   0x0000000000400ffd <+76>:    sub    $0x160,%eax #0x298-0x160=0x138
   0x0000000000401002 <+81>:    jmp    0x401009 <phase_3+88>

   0x0000000000401004 <+83>:    mov    $0x0,%eax

   0x0000000000401009 <+88>:    add    $0x33b,%eax #0x138+0x33b=0x473
   0x000000000040100e <+93>:    jmp    0x401015 <phase_3+100>

   0x0000000000401010 <+95>:    mov    $0x0,%eax 

   0x0000000000401015 <+100>:   sub    $0x3de,%eax #0x473-990
   0x000000000040101a <+105>:   jmp    0x401021 <phase_3+112>

   0x000000000040101c <+107>:   mov    $0x0,%eax

   0x0000000000401021 <+112>:   add    $0x3de,%eax #0x473
   0x0000000000401026 <+117>:   jmp    0x40102d <phase_3+124>

   0x0000000000401028 <+119>:   mov    $0x0,%eax

   0x000000000040102d <+124>:   sub    $0x3de,%eax #0x473-990
   0x0000000000401032 <+129>:   jmp    0x401039 <phase_3+136>

   0x0000000000401034 <+131>:   mov    $0x0,%eax

   0x0000000000401039 <+136>:   add    $0x3de,%eax #0x473
   0x000000000040103e <+141>:   jmp    0x401045 <phase_3+148>

   0x0000000000401040 <+143>:   mov    $0x0,%eax

   0x0000000000401045 <+148>:   sub    $0x3de,%eax #0x473-990
   0x000000000040104a <+153>:   jmp    0x401056 <phase_3+165>

   0x000000000040104c <+155>:   callq  0x4016aa <explode_bomb>

   0x0000000000401051 <+160>:   mov    $0x0,%eax

   0x0000000000401056 <+165>:   cmpl   $0x5,(%rsp) # <=5
   0x000000000040105a <+169>:   jg     0x401062 <phase_3+177>

   0x000000000040105c <+171>:   cmp    0x4(%rsp),%eax # ==
   0x0000000000401060 <+175>:   je     0x401067 <phase_3+182>

   0x0000000000401062 <+177>:   callq  0x4016aa <explode_bomb>

这是一个看似很长,实则很简单的程序。
首先我们要确定自己应当输入什么,阅读代码后有两个提示

  • 在地址0x40295d隐藏着一个字符串,打开后发现是“%d %d”,也就是说我们要以这样的方式输入
  • 整块代码只用到了%rsp%rsp+4。而且,没有移动过%rsp,所以可以断定,我们需要输入两个数。
    接着便是对代码分析
    第一个炸弹要求输入参数个数大于1
    第二个炸弹要求para1<=7
    第三个炸弹有两个要求:
  • para1<=5
  • para2==%eax
    而%eax是原有的%eax经过一系列计算后的结果,我们发现对%eax的操作只有movaddsub三种。而jmpq *0x4026c0(,%rax,8)表明了随着para1的值的不同,进行的运算也不同.有个问题是当para1!=0时,该语句跳转到的位置并不符合规范,这个需要进一步的调试探究。由代码中的注释可以看到,当para1=0时,para2=0x95,也就是149。在探索过程中我还发现当para14para0.这一结果更加表示了jmpq命令跳转到的位置有必要进行研究,感兴趣的可以探究一下。

    Phase_4 5 6
    剩下的三个虽然做出来了但写起来好麻烦,两场考试还都没复习,我要去复习了。老师还是对程序进行了很大的修改的,网上的参考只能借鉴一部分,真正的答案还是要自己去研究才能做出来。大家加油!等考完期中考试再继续写。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值