CSAPP: Bomb Lab(2)


Bomb 3

Bomb 3相关字符串的获取也是需要通过对于里面重要的phase_3(input)进行反汇编才能分析出来的。

下面代码段是phase_3函数的反汇编的前几行,可以分析得到,字符串的输入格式为%d %d,且输入个数大于等于1。

%d %d格式的获取需要通过p/s (char*)0x4025cf命令读取相应内存地址的内容获取得到的。
输入大于1个数字的信息的是通过400f60处的cmp $0x1,%eax代码来判断。%eax是sscanf函数的返回值,代表读入的个数。

    0000000000400f43 <phase_3>:
      400f43:   48 83 ec 18             sub    $0x18,%rsp
      400f47:   48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
      400f4c:   48 8d 54 24 08          lea    0x8(%rsp),%rdx
      400f51:   be cf 25 40 00          mov    $0x4025cf,%esi   //获取字符串格式
      400f56:   b8 00 00 00 00          mov    $0x0,%eax
      400f5b:   e8 90 fc ff ff          callq  400bf0 <__isoc99_sscanf@plt>
      400f60:   83 f8 01                cmp    $0x1,%eax   // 获取数字的个数
      400f63:   7f 05                   jg     400f6a <phase_3+0x27>  //小于两个就爆炸 
      400f65:   e8 d0 04 00 00          callq  40143a <explode_bomb

下面代码块紧接着上面这段。可以在40f6a附近看到程序在判断第一个输入数字是否大于7,如果大于7则会跳转到400fad处触发炸弹。所以得到第一个输入数字<=7
通过观察400f75400fb9的代码可以看到,全部是执行num赋值给%eax,再跳转到400fbe处,相当于一个switch函数。在400fbe会比较第二个输入数字与%eax的值是否相等,不相等则爆炸。

400f6a: 83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)
400f6f: 77 3c         ja     400fad <phase_3+0x6a>
400f71: 8b 44 24 08             mov    0x8(%rsp),%eax 
400f75: ff 24 c5 70 24 40 00    jmpq   *0x402470(,%rax,8)  //存储目的地址的内存地址0x402470+8*i   (i<=7)

400f7c: b8 cf 00 00 00          mov    $0xcf,%eax
400f81: eb 3b           jmp    400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00          mov    $0x2c3,%eax
400f88: eb 34           jmp    400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00          mov    $0x100,%eax
400f8f: eb 2d           jmp    400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00          mov    $0x185,%eax
400f96: eb 26           jmp    400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00          mov    $0xce,%eax
400f9d: eb 1f           jmp    400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00          mov    $0x2aa,%eax
400fa4: eb 18           jmp    400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00          mov    $0x147,%eax
400fab: eb 11           jmp    400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00  callq  40143a <explode_bomb>
400fb2: b8 00 00 00 00          mov    $0x0,%eax
400fb7: eb 05           jmp    400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00          mov    $0x137,%eax

400fbe: 3b 44 24 0c             cmp    0xc(%rsp),%eax 
400fc2: 74 05           je     400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00  callq  40143a <explode_bomb>
400fc9: 48 83 c4 18             add    $0x18,%rsp
400fcd: c3                      retq   

根据上面的分析我们得到400f75:处跳转的结果决定执行哪个case,决定%eax的值。而第一个数字决定了400f75:处代码跳转到哪里。所以第一数字的取值会直接影响到第二个数字的值。
根据对于400f75:出代码中0x402470+8*第一参数打印内存信息,可以看到相应的跳转地址,已经对应的eax值应该是多少,也就是第二数字的应该的取值。打印内存信息的命令行为x/x (int *)内存地址

根据分析可以得到以下对应输入均为正确答案。

    0 207  ===》x/x (int *)0x402470 打印得到地址400f7c
    1 311  ===》x/x (int *)0x402478 打印得到地址400fb9
    2 707  ===》x/x (int *)0x402480 打印得到地址400f83
    3 256  ===》x/x (int *)0x402488 打印得到地址400f8a
    4 389  ===》x/x (int *)0x402490 打印得到地址400f91
    5 206  ===》x/x (int *)0x402498 打印得到地址400f98
    6 682  ===》x/x (int *)0x4024a0 打印得到地址400f9f
    7 327  ===》x/x (int *)0x4024a8 打印得到地址400fa6

Bomb 4

Bomb 4的开头代码和Bomb3 相类似。首先和Bomb 3类似读取$0x4025cf内存地址中存储的字符串可以得到输入格式为%d %d
根据401029: cmp $0x2,%eax代码及下面一行可以指导需要输入2个数字。

根据40102e处代码,可以分析得到第一个数字<=14。如果

40100c: 48 83 ec 18             sub    $0x18,%rsp
401010: 48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
401015: 48 8d 54 24 08          lea    0x8(%rsp),%rdx
40101a: be cf 25 40 00     mov    $0x4025cf,%esi  //==>相关输入格式%d  %d 
40101f: b8 00 00 00 00          mov    $0x0,%eax
401024: e8 c7 fb ff ff          callq  400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02    cmp    $0x2,%eax  //==> 两个数字
40102c: 75 07                   jne    401035 <phase_4+0x29>
40102e: 83 7c 24 08 0e          cmpl   $0xe,0x8(%rsp)
401033: 76 05                   jbe    40103a <phase_4+0x2e>  //==> 第一个参数《=14
401035: e8 00 04 00 00          callq  40143a <explode_bomb>

接下去的代码分别是为调用<fun4>函数做准备,传参数。

40103a: ba 0e 00 00 00          mov    $0xe,%edx
40103f: be 00 00 00 00          mov    $0x0,%esi
401044: 8b 7c 24 08             mov    0x8(%rsp),%edi
401048: e8 81 ff ff ff          callq  400fce <func4>

先跳过<fun4>,分析返回之后怎么执行,相关代码见下面代码块。用test命令来测试返回值(test的效果是两个操作数做&操作;jne指令测试ZF位是否为0)。
根据代码可以知道,返回值为0时,炸弹才不会爆炸。而且第二个输入数字可以通过这行代码401051、401056行代码确定,应该为0.

40104d: 85 c0                   test   %eax,%eax
40104f: 75 07                   jne    401058       <phase_4+0x4c> //~zf
401051: 83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)
 401056:    74 05               je     40105d <phase_4+0x51> //zf
401058: e8 dd 03 00 00          callq  40143a <explode_bomb>
40105d: 48 83 c4 18             add    $0x18,%rsp
401061: c3                      retq   

现在分析<fun4>函数。根据代码中注释,我们可以还原出递归函数的原始模样

0000000000400fce <func4>:
400fce: 48 83 ec 08             sub    $0x8,%rsp
400fd2: 89 d0                   mov    %edx,%eax 
400fd4: 29 f0                   sub    %esi,%eax 
400fd6: 89 c1                   mov    %eax,%ecx 
400fd8: c1 e9 1f                shr    $0x1f,%ecx 
400fdb: 01 c8                   add    %ecx,%eax 
400fdd: d1 f8                   sar    %eax  //eax = ((edx-esi)>>5+(edx-esi))>>1 = (edx-esi)/2
400fdf: 8d 0c 30         lea    (%rax,%rsi,1),%ecx //ecx =  0.5*(edx-esi)+rsi

400fe2: 39 f9                   cmp    %edi,%ecx //第一个输入数字与%ecx比较
400fe4: 7e 0c                   jle    400ff2 <func4+0x24> 
400fe6: 8d 51 ff                lea    -0x1(%rcx),%edx  //如果输入第一个参数小于ecx,递归调用edx = rcx -1
400fe9: e8 e0 ff ff ff          callq  400fce <func4>
400fee: 01 c0                   add    %eax,%eax
400ff0: eb 15                   jmp    401007 <func4+0x39>
400ff2: b8 00 00 00 00          mov    $0x0,%eax
400ff7: 39 f9                   cmp    %edi,%ecx
400ff9: 7d 0c                   jge    401007 <func4+0x39>
400ffb: 8d 71 01                lea    0x1(%rcx),%esi
400ffe: e8 cb ff ff ff          callq  400fce <func4>
401003: 8d 44 00 01             lea    0x1(%rax,%rax,1),%eax  //eax = 2 * rax + 1
401007: 48 83 c4 08             add    $0x8,%rsp
40100b: c3                      retq   

========================================================================

    还原得到的fun4
    int fun4(int a , int b,int c){
        int ret = a/2;
        int tmp = a/2 + b;
        if(c < tmp){
            ret = 2* fun4(a-1,b,c);
            return ret;
        }
        ret = 0;
        if(c > 0){
            return 2*fun4(a,b+1,c)+1;
        }
        return ret;
    }

递归函数fun4的C语言版本如上代码块。其中初始调用a=14 , b = 0 , c = 输入的第一个数字。
需要递归调用结果为0,c一定不能大于0,c大于0 返回值至少为1(第二个判断处)。递归结束时c >= tmp是成立的,而tmp递归到最后一定0(因为之前推测c<=0)。所以得到如下0<=c<=0表达式。从这里可以推测得到第一个输入数字参数为0;

所以这个炸弹的密码为

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值