CMU bomb lab

这个题的本质是让通过gdb和objdump的工具的使用,以及对汇编代码的理解找到程序在栈中已存在的数据或者汇编代码本身的代码逻辑。从而根据固有信息确定输入,使得炸弹得以解除。这个实验有6道关卡和一道隐藏关卡。由于时间原因,我并没有想方法找出隐藏关,只是把固有的6道关卡做完了。下面说一下解题步骤。

  由于炸弹爆炸是要扣分的,所以最开始需要做的任务是在炸弹爆炸函数的入口设置一个断点。这样一来当发现运行到这个断点之后就可以重新开始gdb的运行,使得爆炸函数得不到运行。由于是只有通过前一关后才能做后一关所以当做到后面几关的时候,要把前几关的答案放在一个文档里,然后运行gdb时指定这个文件,就会自动通过前几关。

  关于gdb的使用可以看我的另一篇文章。

第一道关卡:phase1

  上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
08048b90 <phase_1>:
  8048b90:       55                      push   %ebp
  8048b91:       89 e5                   mov    %esp,%ebp
  8048b93:       83 ec 18                sub    $0x18,%esp
  8048b96:       c7 44 24 04 e4 a2 04    movl   $0x804a2e4,0x4(%esp)
  8048b9d:       08
  8048b9e:       8b 45 08                mov    0x8(%ebp),%eax
  8048ba1:       89 04 24                mov    %eax,(%esp)
  8048ba4:       e8 a2 04 00 00          call   804904b <strings_not_equal>
  8048ba9:       85 c0                   test   %eax,%eax
  8048bab:       74 05                   je     8048bb2 <phase_1+0x22>
  8048bad:       e8 86 07 00 00          call   8049338 <explode_bomb>
  8048bb2:       c9                      leave
  8048bb3:       c3                      ret

  以上是通过用objdump工具反汇编bomb可执行程序后得到的汇编代码文件中第一关的代码。这个代码的意义非常简单。通读下来发现首先确定栈的大小。然后为函数strings_not_equal准备参数。参数总共有两个一个是用户自己输入的字符串。由于是字符串,肯定不是直接把字符串本身放在运行占空间里的,所以通过ebp寄存器可以找到存放字符串的内存地址。同理,很自然的可以知道0x804a2e4即是程序本身的一段字符串。通过匹配字符串,便可以把炸弹解开。因此此题的目的便是把字符串找出来,因此便用到了gdb工具。

  首先,用p/x *(int *)0x804a2e4便可以得到一个地址。假设地址为ooxx,那么要想查看这段地址存放的字符串内容便可以通过x/s ooxx既可以得到字符串的内容。我的答案是:There are rumors on the internets.每个人的答案都不一样。哈哈。下面来看第二题。

第二道关卡:phase2

  上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
08048bb4 <phase_2>:
  8048bb4:       55                      push   %ebp
  8048bb5:       89 e5                   mov    %esp,%ebp
  8048bb7:       56                      push   %esi
  8048bb8:       53                      push   %ebx
  8048bb9:       83 ec 30                sub    $0x30,%esp
  8048bbc:       8d 45 e0                lea    -0x20(%ebp),%eax
  8048bbf:       89 44 24 04             mov    %eax,0x4(%esp)
  8048bc3:       8b 45 08                mov    0x8(%ebp),%eax
  8048bc6:       89 04 24                mov    %eax,(%esp)
  8048bc9:       e8 d2 08 00 00          call   80494a0 <read_six_numbers>
  8048bce:       83 7d e0 01             cmpl   $0x1,-0x20(%ebp)
  8048bd2:       74 05                   je     8048bd9 <phase_2+0x25>
  8048bd4:       e8 5f 07 00 00          call   8049338 <explode_bomb>
  8048bd9:       8d 5d e4                lea    -0x1c(%ebp),%ebx
  8048bdc:       8d 75 f8                lea    -0x8(%ebp),%esi
  8048bdf:       8b 43 fc                mov    -0x4(%ebx),%eax
  8048be2:       01 c0                   add    %eax,%eax
  8048be4:       39 03                   cmp    %eax,(%ebx)
  8048be6:       74 05                   je     8048bed <phase_2+0x39>
  8048be8:       e8 4b 07 00 00          call   8049338 <explode_bomb>
  8048bed:       83 c3 04                add    $0x4,%ebx
  8048bf0:       39 f3                   cmp    %esi,%ebx
  8048bf2:       75 eb                   jne    8048bdf <phase_2+0x2b>
  8048bf4:       83 c4 30                add    $0x30,%esp
  8048bf7:       5b                      pop    %ebx
  8048bf8:       5e                      pop    %esi
  8048bf9:       5d                      pop    %ebp
  8048bfa:       c3                      ret

  首先可以看到这道题调用一个函数。函数名叫输入6个数。很明显,这六个书会以次放在ebp-0x20到ebp-0x8的空间内。然后再从以下的代码逻辑可以看出这6个数得满足一种关系:等比为2的等比数列。并且首元素为1.因此答案就明了了为:1 2 4 8 16 32.下面来看第三关。

第三道关卡:phase3

上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
08048bfb <phase_3>:
  8048bfb:       55                      push   %ebp
  8048bfc:       89 e5                   mov    %esp,%ebp
  8048bfe:       83 ec 28                sub    $0x28,%esp
  8048c01:       8d 45 f0                lea    -0x10(%ebp),%eax
  8048c04:       89 44 24 0c             mov    %eax,0xc(%esp)
  8048c08:       8d 45 f4                lea    -0xc(%ebp),%eax
  8048c0b:       89 44 24 08             mov    %eax,0x8(%esp)
  8048c0f:       c7 44 24 04 25 a6 04    movl   $0x804a625,0x4(%esp)
  8048c16:       08
  8048c17:       8b 45 08                mov    0x8(%ebp),%eax
  8048c1a:       89 04 24                mov    %eax,(%esp)
  8048c1d:       e8 be fb ff ff          call   80487e0 <__isoc99_sscanf@plt>
  8048c22:       83 f8 01                cmp    $0x1,%eax
  8048c25:       7f 05                   jg     8048c2c <phase_3+0x31>
  8048c27:       e8 0c 07 00 00          call   8049338 <explode_bomb>
  8048c2c:       83 7d f4 07             cmpl   $0x7,-0xc(%ebp)
  8048c30:       77 65                   ja     8048c97 <phase_3+0x9c>
  8048c32:       8b 45 f4                mov    -0xc(%ebp),%eax
  8048c35:       ff 24 85 40 a3 04 08    jmp    *0x804a340(,%eax,4)
  8048c3c:       b8 00 00 00 00          mov    $0x0,%eax
  8048c41:       eb 05                   jmp    8048c48 <phase_3+0x4d>
  8048c43:       b8 56 00 00 00          mov    $0x56,%eax
  8048c48:       2d 0f 02 00 00          sub    $0x20f,%eax
  8048c4d:       eb 05                   jmp    8048c54 <phase_3+0x59>
  8048c4f:       b8 00 00 00 00          mov    $0x0,%eax
  8048c54:       05 a9 03 00 00          add    $0x3a9,%eax
  8048c59:       eb 05                   jmp    8048c60 <phase_3+0x65>
  8048c5b:       b8 00 00 00 00          mov    $0x0,%eax
  8048c60:       2d e5 00 00 00          sub    $0xe5,%eax
  8048c65:       eb 05                   jmp    8048c6c <phase_3+0x71>
  8048c67:       b8 00 00 00 00          mov    $0x0,%eax
  8048c6c:       05 e5 00 00 00          add    $0xe5,%eax
  8048c71:       eb 05                   jmp    8048c78 <phase_3+0x7d>
  8048c73:       b8 00 00 00 00          mov    $0x0,%eax
  8048c78:       2d e5 00 00 00          sub    $0xe5,%eax
  8048c7d:       eb 05                   jmp    8048c84 <phase_3+0x89>
  8048c7f:       b8 00 00 00 00          mov    $0x0,%eax
  8048c84:       05 e5 00 00 00          add    $0xe5,%eax
  8048c89:       eb 05                   jmp    8048c90 <phase_3+0x95>
  8048c8b:       b8 00 00 00 00          mov    $0x0,%eax
  8048c90:       2d e5 00 00 00          sub    $0xe5,%eax
  8048c95:       eb 0a                   jmp    8048ca1 <phase_3+0xa6>
  8048c97:       e8 9c 06 00 00          call   8049338 <explode_bomb>
  8048c9c:       b8 00 00 00 00          mov    $0x0,%eax
  8048ca1:       83 7d f4 05             cmpl   $0x5,-0xc(%ebp)
  8048ca5:       7f 05                   jg     8048cac <phase_3+0xb1>
  8048ca7:       3b 45 f0                cmp    -0x10(%ebp),%eax
  8048caa:       74 05                   je     8048cb1 <phase_3+0xb6>
  8048cac:       e8 87 06 00 00          call   8049338 <explode_bomb>
  8048cb1:       c9                      leave
  8048cb2:       c3                      ret

  有没有被这段代码吓到?确实有点长。依然可以看到这个题会调用一个函数,这个函数是sscanf,如果对这个函数有所了解的话,可以从它下面的一个比较看出这个函数要求输入两个变量,那么这两个变量是什么类型的呢?可以从movl   $0x804a625,0x4(%esp)这句里找到信息。很明显这是个非常突兀的地址,那么这个地址是干嘛的,首先可以肯定它是sscanf函数的参数,联想到sscanf的参数,可以这段地址的内容便是变量的类型。通过x/s 0x804a625便可以得到"%d %d"这个字符串。同样从开始代码的调动,仍然可以清晰的确定这是有接受两个参数。从后面的代码逻辑可以看出,要根据第一个参数的具体值跳到不同的地址,来执行命令。而且第一个参数要小于7.可以分别假设第一个参数等于0到6,然后可以看出根据这个分支选择可以确定eax的大小,然后第二个参数等eax的值即可。而且又可以从后面的代码看出第一个参数要小于5所以只有0到4可以选择,然后假设第一个参数为4那么eax在运算后为0,因此第二个参数为0便是一个解。(可以看出这题没有唯一解)

第四道关卡:phase_4

  上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
08048d19 <phase_4>:
  8048d19:       55                      push   %ebp
  8048d1a:       89 e5                   mov    %esp,%ebp
  8048d1c:       83 ec 28                sub    $0x28,%esp
  8048d1f:       8d 45 f0                lea    -0x10(%ebp),%eax
  8048d22:       89 44 24 0c             mov    %eax,0xc(%esp)
  8048d26:       8d 45 f4                lea    -0xc(%ebp),%eax
  8048d29:       89 44 24 08             mov    %eax,0x8(%esp)
  8048d2d:       c7 44 24 04 25 a6 04    movl   $0x804a625,0x4(%esp)
  8048d34:       08
  8048d35:       8b 45 08                mov    0x8(%ebp),%eax
  8048d38:       89 04 24                mov    %eax,(%esp)
  8048d3b:       e8 a0 fa ff ff          call   80487e0 <__isoc99_sscanf@plt>
  8048d40:       83 f8 02                cmp    $0x2,%eax
  8048d43:       75 0c                   jne    8048d51 <phase_4+0x38>
  8048d45:       8b 45 f4                mov    -0xc(%ebp),%eax
  8048d48:       85 c0                   test   %eax,%eax
  8048d4a:       78 05                   js     8048d51 <phase_4+0x38>
  8048d4c:       83 f8 0e                cmp    $0xe,%eax
  8048d4f:       7e 05                   jle    8048d56 <phase_4+0x3d>
  8048d51:       e8 e2 05 00 00          call   8049338 <explode_bomb>
  8048d56:       c7 44 24 08 0e 00 00    movl   $0xe,0x8(%esp)
  8048d5d:       00
  8048d5e:       c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
  8048d65:       00
  8048d66:       8b 45 f4                mov    -0xc(%ebp),%eax
  8048d69:       89 04 24                mov    %eax,(%esp)
  8048d6c:       e8 42 ff ff ff          call   8048cb3 <func4>
  8048d71:       83 f8 25                cmp    $0x25,%eax
  8048d74:       75 06                   jne    8048d7c <phase_4+0x63>
  8048d76:       83 7d f0 25             cmpl   $0x25,-0x10(%ebp)
  8048d7a:       74 05                   je     8048d81 <phase_4+0x68>
  8048d7c:       e8 b7 05 00 00          call   8049338 <explode_bomb>
  8048d81:       c9                      leave
  8048d82:       c3                      ret

 看到代码里的 

?
1
2
call   80487e0 __isoc99_sscanf@plt
cmp    $0x2,%eax

 就明白了要输入两个数,然后拿出输入的第一个数(mov    -0xc(%ebp),%eax)首先看看其是不是负数,如果是负数,bomb!!然后将其与14进行比较,如果它比14大,则bomb!!然后将第一个参数,0,和14分别作为第1,2,3个参数传递给func4,然后调用func4.这个函数的返回值是37.因此我们要做的就是,使得输入的值传递给func4,然后让其返回37即可。下面来看看func4函数。依然上代码:

?
08048cb3 <func4>:
  8048cb3:       55                      push   %ebp
  8048cb4:       89 e5                   mov    %esp,%ebp
  8048cb6:       83 ec 18                sub    $0x18,%esp
  8048cb9:       89 5d f8                mov    %ebx,-0x8(%ebp)
  8048cbc:       89 75 fc                mov    %esi,-0x4(%ebp)
  8048cbf:       8b 45 08                mov    0x8(%ebp),%eax
  8048cc2:       8b 55 0c                mov    0xc(%ebp),%edx
  8048cc5:       8b 75 10                mov    0x10(%ebp),%esi
  8048cc8:       89 f1                   mov    %esi,%ecx
  8048cca:       29 d1                   sub    %edx,%ecx
  8048ccc:       89 cb                   mov    %ecx,%ebx
  8048cce:       c1 eb 1f                shr    $0x1f,%ebx
  8048cd1:       8d 0c 0b                lea    (%ebx,%ecx,1),%ecx
  8048cd4:       d1 f9                   sar    %ecx
  8048cd6:       8d 1c 11                lea    (%ecx,%edx,1),%ebx
  8048cd9:       39 c3                   cmp    %eax,%ebx
  8048cdb:       7e 17                   jle    8048cf4 <func4+0x41>
  8048cdd:       8d 4b ff                lea    -0x1(%ebx),%ecx
  8048ce0:       89 4c 24 08             mov    %ecx,0x8(%esp)
  8048ce4:       89 54 24 04             mov    %edx,0x4(%esp)
  8048ce8:       89 04 24                mov    %eax,(%esp)
  8048ceb:       e8 c3 ff ff ff          call   8048cb3 <func4>
  8048cf0:       01 c3                   add    %eax,%ebx
  8048cf2:       eb 19                   jmp    8048d0d <func4+0x5a>
  8048cf4:       39 c3                   cmp    %eax,%ebx
  8048cf6:       7d 15                   jge    8048d0d <func4+0x5a>
  8048cf8:       89 74 24 08             mov    %esi,0x8(%esp)
  8048cfc:       8d 53 01                lea    0x1(%ebx),%edx
  8048cff:       89 54 24 04             mov    %edx,0x4(%esp)
  8048d03:       89 04 24                mov    %eax,(%esp)
  8048d06:       e8 a8 ff ff ff          call   8048cb3 <func4>
  8048d0b:       01 c3                   add    %eax,%ebx
  8048d0d:       89 d8                   mov    %ebx,%eax
  8048d0f:       8b 5d f8                mov    -0x8(%ebp),%ebx
  8048d12:       8b 75 fc                mov    -0x4(%ebp),%esi
  8048d15:       89 ec                   mov    %ebp,%esp
  8048d17:       5d                      pop    %ebp
  8048d18:       c3                      ret

  一看到这个函数里面有func4,心理就紧张了,这是要递归啊。对于这部分,有的同学是用c写了一段代码,模拟这个逻辑,把题给结出来的,我是拿笔算加推理得出的。对于此,不管你认为怎么样,我反正认为是没有必要,这个递归逻辑不复杂。

  下面就来剖析func4,这个函数在确定栈之后,首先取出来传递给它的参数,依次放在eax,edx,esi.中,从一个jle和一个jge可以看出,这个递归函数跳出的条件根据func4的第二个参数和第二个参数进过种种运算的结果等于第一个参数即可。注意在递归过程中第一个参数是不变的,最后返回值是经过运算后的ebx加上第一个参数。其中根据传进参数的大小,可以大致算出如果第一个参数如果等于7,则结果明显小于37,所以选比7大的数。所以第一递归会走jge这条路,因此新的参数为输入的第一个数,8,14.然后重新调用函数。可以自己画出每次递归传进的参数图。稍微对比下可以发现传入的数为10即可满足题意.

 然后继续看phase_4函数,最后有这句话 cmpl   $0x25,-0x10(%ebp)可以看出只要第二个参数为37即可满足。第二个参数的要求就这么简单。是不是很无语?

因此这道题的答案为4 37.

第五道关卡:phase_5

  上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
08048d83 <phase_5>:
  8048d83:       55                      push   %ebp
  8048d84:       89 e5                   mov    %esp,%ebp
  8048d86:       83 ec 28                sub    $0x28,%esp
  8048d89:       8d 45 f0                lea    -0x10(%ebp),%eax
  8048d8c:       89 44 24 0c             mov    %eax,0xc(%esp)
  8048d90:       8d 45 f4                lea    -0xc(%ebp),%eax
  8048d93:       89 44 24 08             mov    %eax,0x8(%esp)
  8048d97:       c7 44 24 04 25 a6 04    movl   $0x804a625,0x4(%esp)
  8048d9e:       08
  8048d9f:       8b 45 08                mov    0x8(%ebp),%eax
  8048da2:       89 04 24                mov    %eax,(%esp)
  8048da5:       e8 36 fa ff ff          call   80487e0 <__isoc99_sscanf@plt>
  8048daa:       83 f8 01                cmp    $0x1,%eax
  8048dad:       7f 05                   jg     8048db4 <phase_5+0x31>
  8048daf:       e8 84 05 00 00          call   8049338 <explode_bomb>
  8048db4:       8b 45 f4                mov    -0xc(%ebp),%eax
  8048db7:       83 e0 0f                and    $0xf,%eax
  8048dba:       89 45 f4                mov    %eax,-0xc(%ebp)
  8048dbd:       83 f8 0f                cmp    $0xf,%eax
  8048dc0:       74 28                   je     8048dea <phase_5+0x67>
  8048dc2:       b9 00 00 00 00          mov    $0x0,%ecx
  8048dc7:       ba 00 00 00 00          mov    $0x0,%edx
  8048dcc:       83 c2 01                add    $0x1,%edx
  8048dcf:       8b 04 85 60 a3 04 08    mov    0x804a360(,%eax,4),%eax
  8048dd6:       01 c1                   add    %eax,%ecx
  8048dd8:       83 f8 0f                cmp    $0xf,%eax
  8048ddb:       75 ef                   jne    8048dcc <phase_5+0x49>
  8048ddd:       89 45 f4                mov    %eax,-0xc(%ebp)
  8048de0:       83 fa 0f                cmp    $0xf,%edx
  8048de3:       75 05                   jne    8048dea <phase_5+0x67>
  8048de5:       3b 4d f0                cmp    -0x10(%ebp),%ecx
  8048de8:       74 05                   je     8048def <phase_5+0x6c>
  8048dea:       e8 49 05 00 00          call   8049338 <explode_bomb>
  8048def:       c9                      leave
  8048df0:       c3                      ret

 首先,看到这题不是递归,代码又这么短,心理就有种蔑视这道题的感觉。首先可以看到需要输入两个数,否则bomb。然后就对第一个数进行操作了,首先取其后四位,如果其后四位全为1则爆炸。然后看到mov    $0x0,%ecx    mov    $0x0,%edx就可以知道下面是个循环,edx为循环变量。这个循环里会根据eax,以其为索引找以地址0x804a360开头的数组中的值。然后求和。最后和等于输入的第二个参数即可。可以通过p/x *(int *)(0x804a360)@16得到这个数组,然后拼凑即可。我选则的值为4 115.

第六道关卡:phase_6

  上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

你可能感兴趣的:(c,汇编,360,工具,fun,Numbers)