二进制炸弹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\n", 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

 

posted @ 2015-09-27 16:18  whu.yt  阅读(7483)  评论(0编辑  收藏  举报