• 二进制炸弹Lab


    Lab 采用的是 coursera 上华盛顿大学的The Hardware/Software Interface. 与CSAPP书上的不同,这里的lab采用的是64位机器。

    Lab2 要求拆除6个炸弹加一个secret bomb。

    phase_1

    0000000000400e70 <phase_1>:
      400e70:    48 83 ec 08              sub    $0x8,%rsp
      400e74:    be f8 1a 40 00           mov    $0x401af8,%esi
      400e79:    e8 bf 03 00 00           callq  40123d <strings_not_equal>
      400e7e:    85 c0                    test   %eax,%eax
      400e80:    74 05                    je     400e87 <phase_1+0x17>
      400e82:    e8 b6 07 00 00           callq  40163d <explode_bomb>
      400e87:    48 83 c4 08              add    $0x8,%rsp
      400e8b:    c3                       retq 
    000000000040123d <strings_not_equal>:
      40123d:    48 89 5c 24 e8           mov    %rbx,-0x18(%rsp)
      401242:    48 89 6c 24 f0           mov    %rbp,-0x10(%rsp)
      401247:    4c 89 64 24 f8           mov    %r12,-0x8(%rsp)
      40124c:    48 83 ec 18              sub    $0x18,%rsp
      401250:    48 89 fb                 mov    %rdi,%rbx
      401253:    48 89 f5                 mov    %rsi,%rbp
      401256:    e8 c6 ff ff ff           callq  401221 <string_length>
      40125b:    41 89 c4                 mov    %eax,%r12d
      40125e:    48 89 ef                 mov    %rbp,%rdi
      401261:    e8 bb ff ff ff           callq  401221 <string_length>
      401266:    ba 01 00 00 00           mov    $0x1,%edx
      40126b:    41 39 c4                 cmp    %eax,%r12d
      40126e:    75 36                    jne    4012a6 <strings_not_equal+0x69>
    0000000000401221 <string_length>:
      401221:    b8 00 00 00 00           mov    $0x0,%eax
      401226:    80 3f 00                 cmpb   $0x0,(%rdi)
      401229:    74 10                    je     40123b <string_length+0x1a>
      40122b:    48 89 fa                 mov    %rdi,%rdx
      40122e:    48 83 c2 01              add    $0x1,%rdx
      401232:    89 d0                    mov    %edx,%eax
      401234:    29 f8                    sub    %edi,%eax
      401236:    80 3a 00                 cmpb   $0x0,(%rdx)
      401239:    75 f3                    jne    40122e <string_length+0xd>
      40123b:    f3 c3                    repz retq 

    string_length 中的代码比较好懂,是以%rdi中的内容为地址,然后与0比较(0即是字符串的终结符号)。所以字符串起始地址应该藏在%rdi中!再看 strings_not_equal,分别有两次 string_length 调用,再结合函数名 strings_not_equal,可以想见是我们输入的字符串与藏在程序中的字符串进行比较!所以只要在 401256,401261两处设置断点,打印出以%rdi中内容为起始地址的字符串。其中一个是我们输入的字符串,而另一个就是我们寻找的字符串。

    phase_2

    0000000000400e8c <phase_2>:
      400e8c:    48 89 5c 24 e0           mov    %rbx,-0x20(%rsp)
      400e91:    48 89 6c 24 e8           mov    %rbp,-0x18(%rsp)
      400e96:    4c 89 64 24 f0           mov    %r12,-0x10(%rsp)
      400e9b:    4c 89 6c 24 f8           mov    %r13,-0x8(%rsp)
      400ea0:    48 83 ec 48              sub    $0x48,%rsp
      400ea4:    48 89 e6                 mov    %rsp,%rsi
      400ea7:    e8 97 08 00 00           callq  401743 <read_six_numbers>
      400eac:    48 89 e5                 mov    %rsp,%rbp
      400eaf:    4c 8d 6c 24 0c           lea    0xc(%rsp),%r13
      400eb4:    41 bc 00 00 00 00        mov    $0x0,%r12d
      400eba:    48 89 eb                 mov    %rbp,%rbx
      400ebd:    8b 45 0c                 mov    0xc(%rbp),%eax
      400ec0:    39 45 00                 cmp    %eax,0x0(%rbp)
      400ec3:    74 05                    je     400eca <phase_2+0x3e>
      400ec5:    e8 73 07 00 00           callq  40163d <explode_bomb>
      400eca:    44 03 23                 add    (%rbx),%r12d
      400ecd:    48 83 c5 04              add    $0x4,%rbp
      400ed1:    4c 39 ed                 cmp    %r13,%rbp
      400ed4:    75 e4                    jne    400eba <phase_2+0x2e>
      400ed6:    45 85 e4                 test   %r12d,%r12d
      400ed9:    75 05                    jne    400ee0 <phase_2+0x54>
      400edb:    e8 5d 07 00 00           callq  40163d <explode_bomb>
      400ee0:    48 8b 5c 24 28           mov    0x28(%rsp),%rbx
      400ee5:    48 8b 6c 24 30           mov    0x30(%rsp),%rbp
      400eea:    4c 8b 64 24 38           mov    0x38(%rsp),%r12
      400eef:    4c 8b 6c 24 40           mov    0x40(%rsp),%r13
      400ef4:    48 83 c4 48              add    $0x48,%rsp
      400ef8:    c3                       retq   

    phase_2 会调用 read_six_numbers,所以我们要输入的应该是6个数字。

    这段汇编代码比较好懂,是让我们比较 0x0(%rbp) 与 0xc(%rbp) ,0x4(%rbp) 与 0x10(%rbp),0x8(%rbp) 与 0x14(%rbp)的内容,一旦有一个不符就引爆炸弹,同时还会检测 0x0(%rbp) + 0x4(%rbp) + 0x8(%rbp) 的和是否为0,为0则引爆炸弹。

    那么上面这些与我们输入的数字又有什么关系呢?只要在gdb中打印出来看看就行了。

    啊哈,表示的就是我们输入进去的数字嘛。所以我们只要保证后三位与前三位相同同时前三位之和不为0就ok了。 比如 1 2 3 1 2 3

    phase_3

    0000000000400ef9 <phase_3>:
      400ef9:    48 83 ec 18              sub    $0x18,%rsp
      400efd:    48 8d 4c 24 08           lea    0x8(%rsp),%rcx
      400f02:    48 8d 54 24 0c           lea    0xc(%rsp),%rdx
      400f07:    be be 1e 40 00           mov    $0x401ebe,%esi
      400f0c:    b8 00 00 00 00           mov    $0x0,%eax
      400f11:    e8 9a fb ff ff           callq  400ab0 <__isoc99_sscanf@plt>
      400f16:    83 f8 01                 cmp    $0x1,%eax
      400f19:    7f 05                    jg     400f20 <phase_3+0x27>
      400f1b:    e8 1d 07 00 00           callq  40163d <explode_bomb>
      400f20:    83 7c 24 0c 07           cmpl   $0x7,0xc(%rsp)
      400f25:    77 3c                    ja     400f63 <phase_3+0x6a>
      400f27:    8b 44 24 0c              mov    0xc(%rsp),%eax
      400f2b:    ff 24 c5 60 1b 40 00     jmpq   *0x401b60(,%rax,8)
      400f32:    b8 17 02 00 00           mov    $0x217,%eax
      400f37:    eb 3b                    jmp    400f74 <phase_3+0x7b>
      400f39:    b8 d6 00 00 00           mov    $0xd6,%eax
      400f3e:    eb 34                    jmp    400f74 <phase_3+0x7b>
      400f40:    b8 53 01 00 00           mov    $0x153,%eax
      400f45:    eb 2d                    jmp    400f74 <phase_3+0x7b>
      400f47:    b8 77 00 00 00           mov    $0x77,%eax
      400f4c:    eb 26                    jmp    400f74 <phase_3+0x7b>
      400f4e:    b8 60 01 00 00           mov    $0x160,%eax
      400f53:    eb 1f                    jmp    400f74 <phase_3+0x7b>
      400f55:    b8 97 03 00 00           mov    $0x397,%eax
      400f5a:    eb 18                    jmp    400f74 <phase_3+0x7b>
      400f5c:    b8 9c 01 00 00           mov    $0x19c,%eax
      400f61:    eb 11                    jmp    400f74 <phase_3+0x7b>
      400f63:    e8 d5 06 00 00           callq  40163d <explode_bomb>
      400f68:    b8 00 00 00 00           mov    $0x0,%eax
      400f6d:    eb 05                    jmp    400f74 <phase_3+0x7b>
      400f6f:    b8 9e 03 00 00           mov    $0x39e,%eax
      400f74:    3b 44 24 08              cmp    0x8(%rsp),%eax
      400f78:    74 05                    je     400f7f <phase_3+0x86>
      400f7a:    e8 be 06 00 00           callq  40163d <explode_bomb>
      400f7f:    48 83 c4 18              add    $0x18,%rsp
      400f83:    c3                       retq 

     400ab0 <__isoc99_sscanf@plt> 指明了 sscanf 是标准库函数,经查文档,得到该函数的 signature 为 int sscanf(const char *buffer,const char *format,[argument ]...);

    与gets函数一样都要有buffer,结合前面将 0x8(%rsp),0xc(%rsp) 的地址压入寄存器,以及后面会取出0x8(%rsp),0xc(%rsp)进行其他操作,所以猜测应该是输入的内容放入栈中这两个位置(作为buffer)。而且该函数的返回值(返回值为参数数目)要求大于1才不会爆炸,所以结合buffer的大小为2输入的应该是两个字符。%esi 对应的是参数 const char *forma,经打印为

    更加确定输入的是两个字符,而且是两个数字。

    后面部分就很简单,要求输入的第一个数字小于等于7,且跳转到 *(0x401b60 + 8 * args[1] ) 处。

    这是一个switch结构,分别对eax赋值,然后与我们输入的第二个数字比较,相等才过关。

    所以相应的这里的答案也有8组。其中一组为 0 535 。

    phase_4

    0000000000400fc1 <phase_4>:
      400fc1:    48 83 ec 18              sub    $0x18,%rsp
      400fc5:    48 8d 54 24 0c           lea    0xc(%rsp),%rdx
      400fca:    be c1 1e 40 00           mov    $0x401ec1,%esi
      400fcf:    b8 00 00 00 00           mov    $0x0,%eax
      400fd4:    e8 d7 fa ff ff           callq  400ab0 <__isoc99_sscanf@plt>
      400fd9:    83 f8 01                 cmp    $0x1,%eax
      400fdc:    75 07                    jne    400fe5 <phase_4+0x24>
      400fde:    83 7c 24 0c 00           cmpl   $0x0,0xc(%rsp)
      400fe3:    7f 05                    jg     400fea <phase_4+0x29>
      400fe5:    e8 53 06 00 00           callq  40163d <explode_bomb>
      400fea:    8b 7c 24 0c              mov    0xc(%rsp),%edi
      400fee:    e8 91 ff ff ff           callq  400f84 <func4>
      400ff3:    83 f8 37                 cmp    $0x37,%eax
      400ff6:    74 05                    je     400ffd <phase_4+0x3c>
      400ff8:    e8 40 06 00 00           callq  40163d <explode_bomb>
      400ffd:    48 83 c4 18              add    $0x18,%rsp
      401001:    c3                       retq  
    0000000000400f84 <func4>:
      400f84:    48 89 5c 24 f0           mov    %rbx,-0x10(%rsp)
      400f89:    48 89 6c 24 f8           mov    %rbp,-0x8(%rsp)
      400f8e:    48 83 ec 18              sub    $0x18,%rsp
      400f92:    89 fb                    mov    %edi,%ebx
      400f94:    b8 01 00 00 00           mov    $0x1,%eax
      400f99:    83 ff 01                 cmp    $0x1,%edi
      400f9c:    7e 14                    jle    400fb2 <func4+0x2e>
      400f9e:    8d 7b ff                 lea    -0x1(%rbx),%edi
      400fa1:    e8 de ff ff ff           callq  400f84 <func4>
      400fa6:    89 c5                    mov    %eax,%ebp
      400fa8:    8d 7b fe                 lea    -0x2(%rbx),%edi
      400fab:    e8 d4 ff ff ff           callq  400f84 <func4>
      400fb0:    01 e8                    add    %ebp,%eax
      400fb2:    48 8b 5c 24 08           mov    0x8(%rsp),%rbx
      400fb7:    48 8b 6c 24 10           mov    0x10(%rsp),%rbp
      400fbc:    48 83 c4 18              add    $0x18,%rsp
      400fc0:    c3  

    要求是输入一个数(只能有一个数),要求这个数比0大,而且将这个数作为 func4 的参数。然后要求func4函数的返回值为55(0x37).而func4这个函数是个递归函数,所以这题的关键是func4函数。我们只要写出该函数的 C 形式,然后不同的数去试就ok了。

    int func4(int n) {
        if (n <= 1)
            return 1;
        return func4(n-1) + func4(n-2);
    } 
    
    int main(void) {
        int i;
        for (i = 2; 1; i++) {
            if (func4(i) == 55)
                break;
        }
        printf("%d
    ", i);
    } 

    输出为 9,所以答案即为9.

    phase_5

    0000000000401002 <phase_5>:
      401002:    48 83 ec 18              sub    $0x18,%rsp
      401006:    48 8d 4c 24 08           lea    0x8(%rsp),%rcx
      40100b:    48 8d 54 24 0c           lea    0xc(%rsp),%rdx
      401010:    be be 1e 40 00           mov    $0x401ebe,%esi
      401015:    b8 00 00 00 00           mov    $0x0,%eax
      40101a:    e8 91 fa ff ff           callq  400ab0 <__isoc99_sscanf@plt>
      40101f:    83 f8 01                 cmp    $0x1,%eax
      401022:    7f 05                    jg     401029 <phase_5+0x27>
      401024:    e8 14 06 00 00           callq  40163d <explode_bomb>
      401029:    8b 44 24 0c              mov    0xc(%rsp),%eax
      40102d:    83 e0 0f                 and    $0xf,%eax
      401030:    89 44 24 0c              mov    %eax,0xc(%rsp)
      401034:    83 f8 0f                 cmp    $0xf,%eax
      401037:    74 2c                    je     401065 <phase_5+0x63>
      401039:    b9 00 00 00 00           mov    $0x0,%ecx
      40103e:    ba 00 00 00 00           mov    $0x0,%edx
      401043:    83 c2 01                 add    $0x1,%edx
      401046:    48 98                    cltq   
      401048:    8b 04 85 a0 1b 40 00     mov    0x401ba0(,%rax,4),%eax
      40104f:    01 c1                    add    %eax,%ecx
      401051:    83 f8 0f                 cmp    $0xf,%eax
      401054:    75 ed                    jne    401043 <phase_5+0x41>
      401056:    89 44 24 0c              mov    %eax,0xc(%rsp)
      40105a:    83 fa 0c                 cmp    $0xc,%edx
      40105d:    75 06                    jne    401065 <phase_5+0x63>
      40105f:    3b 4c 24 08              cmp    0x8(%rsp),%ecx
      401063:    74 05                    je     40106a <phase_5+0x68>
      401065:    e8 d3 05 00 00           callq  40163d <explode_bomb>
      40106a:    48 83 c4 18              add    $0x18,%rsp
      40106e:    c3                       retq   

    这题也是要求你输入两个数字, 然后第一个数字只保留后四位,其他位置0(and $0xf,%eax)。且第一个输入的数字作为int数组的索引从数组中取数,然后将得到的数字作为索引继续从数组取数(每经过一次取数:edx+1,ecx不断将取出的数加到自身)。。。直到取出15。此时要求edx为12,ecx等于第二个输入的数。

    在 0x401048 处设置断点,不断尝试各种数字,看看这个数组中的内容到底是什么。

    可以发现输入7时,可以满足取出15时要edx为12。此时ecx为93.

    所以答案为 7 93

    phase_6

    00000000004010d9 <phase_6>:
      4010d9:    48 83 ec 08              sub    $0x8,%rsp
      4010dd:    ba 0a 00 00 00           mov    $0xa,%edx
      4010e2:    be 00 00 00 00           mov    $0x0,%esi
      4010e7:    e8 94 fa ff ff           callq  400b80 <strtol@plt>
      4010ec:    89 05 8e 16 20 00        mov    %eax,0x20168e(%rip)        # 602780 <node0>
      4010f2:    bf 80 27 60 00           mov    $0x602780,%edi
      4010f7:    e8 73 ff ff ff           callq  40106f <fun6>
      4010fc:    48 8b 40 08              mov    0x8(%rax),%rax
      401100:    48 8b 40 08              mov    0x8(%rax),%rax
      401104:    48 8b 40 08              mov    0x8(%rax),%rax
      401108:    8b 15 72 16 20 00        mov    0x201672(%rip),%edx        # 602780 <node0>
      40110e:    39 10                    cmp    %edx,(%rax)
      401110:    74 05                    je     401117 <phase_6+0x3e>
      401112:    e8 26 05 00 00           callq  40163d <explode_bomb>
      401117:    48 83 c4 08              add    $0x8,%rsp
      40111b:    c3                       retq   

    查手册得,strtol是将字符串中的数字转化为特定进制,这里的参数edx为0xa,因此转化为10进制。我们随便输入一个数字 100,在 4010ec 处设置断点,发现eax中的数字就是100.

    然后发现fun6的参数edi(0x602780)固定,那么输出也应该是固定的,所以没必要去看fun6。

    引不引爆的关键在40110e处,我们在此处设置断电,将edx,(rax)的内容都打印一下,

    发现edx的数据是我们输入的值100,而(rax)为600,如图,因此我们只要开始输入600应该就通过了(在 4010ec 中我们将100存入0x20168e(%rip)中,在 401108 中我们从 0x201672(%rip) 取出了100)。

    因此答案为600.

    secret_phase

  • 相关阅读:
    delphi内存管理
    Dbgrid导出为word
    indy传输文件
    TMethod
    http状态码详解
    如何严格设置php中session过期时间
    http和https的优缺点,区别与工作原理
    session的生命周期
    Mysql分库分表方案,如何分,怎样分?
    【观点】程序员应知——循序渐进 狼人:
  • 原文地址:https://www.cnblogs.com/whuyt/p/4842368.html
Copyright © 2020-2023  润新知