计算机系统实验 Lab1 bomblab

Bomb实验
将自己的炸弹解压,发现只有bomb可执行文件,bomb.c源码和一个README文件, 再打开bomb.c源码:

在主体bomb部分,可以看到initialize函数,其作用为初始化炸弹bomb,接下来就进入了主体的bomb运行阶段。分析可知,炸弹通过若干个密码串行组成,在每一个密码破译之前不能向下运行下一个解密关卡,所有关卡中有一个与真实密码不匹配,相应的defused函数将无法成功运行,同时结束整个程序(引爆炸弹)。代码分析完毕,接下来开始尝试进行反汇编和调试部分。
指令:
实验开始之前,bomb和bomb.c文件都是白色的,不可执行,于是我们要输入命令 chomd +x 文件名使得文件可以运行,然后就进入gdb调试
objdump -d bomb > assemble.txt # 将反汇编代码重定向输入到assemble.txt中,便于后续查看
gdb -q bomb(开始调试bomb) # 需要使用gdb来查看源代码中查看不到的代码

phase_1
gdb bomb
b phase_1 打断点
r 运行

随意输入一个字符之后,我们要查看它的反汇编代码来找答案

寄存器中(%esp)(%esp+4)中存储的值(0xffee5290)(0xffee5294)作为地址,内存中存储的值是(0x0804c3e0)(0x804a144),再将这两个数据作为地址在内存中对应的值就是我们输入的字符串以及我们答案字符串。这两个字符串的地址会作为参数传入到strings_not_equal中做比较。
我们查看x/s 0x804a144,输出为"When a problem comes along, you must zip it ",即是答案

phase_2
以下是phase_2的反汇编代码
08048bb4 <phase_2>:
 8048bb4:	56                   	push   %esi
 8048bb5:	53                   	push   %ebx
 8048bb6:	83 ec 34             	sub    $0x34,%esp
 8048bb9:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048bbd:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048bc1:	8b 44 24 40          	mov    0x40(%esp),%eax
 8048bc5:	89 04 24             	mov    %eax,(%esp)
 8048bc8:	e8 7f 05 00 00       	call   804914c <read_six_numbers>
 8048bcd:	83 7c 24 18 00       	cmpl   $0x0,0x18(%esp) 
 8048bd2:	75 07                	jne    8048bdb <phase_2+0x27> 
 8048bd4:	83 7c 24 1c 01       	cmpl   $0x1,0x1c(%esp) 
 8048bd9:	74 1f                	je     8048bfa <phase_2+0x46> 
 8048bdb:	e8 45 05 00 00       	call   8049125 <explode_bomb>
 8048be0:	eb 18                	jmp    8048bfa <phase_2+0x46>
 8048be2:	8b 43 f8             	mov    -0x8(%ebx),%eax
 8048be5:	03 43 fc             	add    -0x4(%ebx),%eax
 8048be8:	39 03                	cmp    %eax,(%ebx)
 8048bea:	74 05                	je     8048bf1 <phase_2+0x3d>
 8048bec:	e8 34 05 00 00       	call   8049125 <explode_bomb>
 8048bf1:	83 c3 04             	add    $0x4,%ebx 
 8048bf4:	39 f3                	cmp    %esi,%ebx
 8048bf6:	75 ea                	jne    8048be2 <phase_2+0x2e>
 8048bf8:	eb 0a                	jmp    8048c04 <phase_2+0x50>
 8048bfa:	8d 5c 24 20          	lea    0x20(%esp),%ebx
 8048bfe:	8d 74 24 30          	lea    0x30(%esp),%esi
 8048c02:	eb de                	jmp    8048be2 <phase_2+0x2e> 
 8048c04:	83 c4 34             	add    $0x34,%esp
 8048c07:	5b                   	pop    %ebx
 8048c08:	5e                   	pop    %esi
 8048c09:	c3                   	ret    

je 表示等于就跳转,jne是不等于就跳转
jmp是汇编语言中的无条件跳转指令
查看了一下函数

发现是输入六个整型的数字,通过寻找炸弹爆炸的条件,来找到这六个数字
8048bcd: 83 7c 24 18 00 cmpl 0 x 0 , 0 x 18 ( 通 过 这 一 行 我 们 知 道 了 0x0,0x18(%esp) 通过这一行我们知道了 0x0,0x18(esp+0x18存放的是我们
我们猜测可知,我们输入的六个数字以空格隔开,从0x18(%esp)开始顺序存储。可以使用x/24bx $esp+0x18进行查看,假设我们输入的数字为1 1 1 1 1 1,那么输出为:

输进去的第一个值,需要与0比较,相同跳转,不相同就爆炸,所以第一个数字就是0
由于一开始调试我们输进去的值是乱写的,现在需要去改掉
命令行输入
set {int}($exp+0x18)=0
此处注意到esp+0x18的地址是0xbffff218,改完之后输入si,继续执行,发现他没有爆炸,跳过跳转指令来到了以下这一行
8048bd4: 83 7c 24 1c 01 cmpl 0 x 1 , 0 x 1 c ( 通 过 这 一 行 我 们 知 道 了 0x1,0x1c(%esp) 通过这一行我们知道了 0x1,0x1c(esp+0x1c存放的是我们输进去的第二个值,需要与1比较,相同跳转,不相同就爆炸,所以第二个数字就是1
由于一开始调试我们输进去的值是乱写的,现在需要去改掉
命令行输入

set {int}($exp+0x1c)=1
8048bd9:	74 1f                	je     8048bfa <phase_2+0x46> 
8048bfa:	8d 5c 24 20          	lea    0x20(%esp),%ebx
8048bfe:	8d 74 24 30          	lea    0x30(%esp),%esi
8048c02:	eb de                	jmp    8048be2 <phase_2+0x2e> 

由于0x1c(%esp)下一个存储的位置是0x20(%esp),所以是要把0x20(%esp)的地址给ebx,0x30(%esp)则是该数组的界限,把界限的地址给esi,然后无条件跳转

8048be2:	8b 43 f8             	mov    -0x8(%ebx),%eax
8048be5:	03 43 fc             	add    -0x4(%ebx),%eax
8048be8:	39 03                	cmp    %eax,(%ebx)

现在第三个要比较的数字在ebx存储的地址里,-0x8(%ebx)里存储的是第一个数字的地址给到eax,再将-0x4(%ebx)地址里的存储的第二个数加到eax地址里的值里面,然后与第三个数字相比,所以我们知道第三个数字应该存储前面两个之和,我们也知道前两个数之和是1
由于一开始调试我们输进去的值是乱写的,现在需要去改掉
命令行输入
set {int}$ebx=1
此时的0x20(%esp)的地址是0xbffff220,此时%ebx的地址也是0xbffff220,此时看eax与(%ebx)是否相等,则跳转是下面的指令

 8048bea:	74 05                	je     8048bf1 <phase_2+0x3d>
 8048bec:	e8 34 05 00 00       	call   8049125 <explode_bomb>
 8048bf1:	83 c3 04             	add    $0x4,%ebx 
 8048bf4:	39 f3                	cmp    %esi,%ebx
 8048bf6:	75 ea                	jne    8048be2 <phase_2+0x2e>

8048bf1这条指令执行完,%ebx的地址也是0xbffff224,里面存储的值是1
8048bf4这条指令是为了比较跳到数组的下一个值时有没有越界,esi存储的是数组的界限值0xbffff230,由于没越界所以不相等就跳转

 8048be2:	8b 43 f8             	mov    -0x8(%ebx),%eax
 8048be5:	03 43 fc             	add    -0x4(%ebx),%eax
 8048be8:	39 03                	cmp    %eax,(%ebx)

-0x8(%ebx)对应的地址是0xbffff21c,里面的值是1,-0x4(%ebx)对应的地址是0xbffff220,里面的值是1,所以现在%eax地址里对应的值是2,所以现在要将%ebx的地址0xbffff224对应的值1改成2
由于一开始调试我们输进去的值是乱写的,现在需要去改掉
命令行输入

set {int}$ebx=2
 8048bea:	74 05                	je     8048bf1 <phase_2+0x3d>
 8048bec:	e8 34 05 00 00       	call   8049125 <explode_bomb>
 8048bf1:	83 c3 04             	add    $0x4,%ebx 
 8048bf4:	39 f3                	cmp    %esi,%ebx
 8048bf6:	75 ea                	jne    8048be2 <phase_2+0x2e>

到这里我们发现跟上面的流程是一样的,就可以知道其实是循环,我们就猜是不是后面的数等于这个数字前面两个数的和,所以结果是3和5
所以最终答案是“0 1 1 2 3 5”
phase_3
以下是phase_2的反汇编代码

08048c0a <phase_3>:
 8048c0a:	83 ec 2c             	sub    $0x2c,%esp
 8048c0d:	8d 44 24 1c          	lea    0x1c(%esp),%eax
 8048c11:	89 44 24 0c          	mov    %eax,0xc(%esp)
 8048c15:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048c19:	89 44 24 08          	mov    %eax,0x8(%esp)
 8048c1d:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp)
 8048c24:	08 
 8048c25:	8b 44 24 30          	mov    0x30(%esp),%eax
 8048c29:	89 04 24             	mov    %eax,(%esp)
 8048c2c:	e8 2f fc ff ff       	call   8048860 <__isoc99_sscanf@plt 
 8048c31:	83 f8 01             	cmp    $0x1,%eax
 8048c34:	7f 05                	jg     8048c3b <phase_3+0x31>
 8048c36:	e8 ea 04 00 00       	call   8049125 <explode_bomb>
 8048c3b:	83 7c 24 18 07       	cmpl  $0x7,0x18(%esp) 
 8048c40:	77 66                	ja     8048ca8 <phase_3+0x9e>
 8048c42:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048c46:	ff 24 85 a0 a1 04 08 	jmp    *0x804a1a0(,%eax,4) 
 8048c4d:	b8 00 00 00 00       	mov    $0x0,%eax
 8048c52:	eb 05                	jmp    8048c59 <phase_3+0x4f>
 8048c54:	b8 1e 01 00 00       	mov    $0x11e,%eax
 8048c59:	2d e0 03 00 00       	sub    $0x3e0,%eax
 8048c5e:	eb 05                	jmp    8048c65 <phase_3+0x5b>
 8048c60:	b8 00 00 00 00       	mov    $0x0,%eax
 8048c65:	05 b7 01 00 00       	add    $0x1b7,%eax
 8048c6a:	eb 05                	jmp    8048c71 <phase_3+0x67>
 8048c6c:	b8 00 00 00 00       	mov    $0x0,%eax
 8048c71:	2d d7 01 00 00       	sub    $0x1d7,%eax
 8048c76:	eb 05                	jmp    8048c7d <phase_3+0x73>
 8048c78:	b8 00 00 00 00       	mov    $0x0,%eax
 8048c7d:	05 d7 01 00 00       	add    $0x1d7,%eax
 8048c82:	eb 05                	jmp    8048c89 <phase_3+0x7f>
 8048c84:	b8 00 00 00 00       	mov    $0x0,%eax
 8048c89:	2d d7 01 00 00       	sub    $0x1d7,%eax
 8048c8e:	eb 05                	jmp    8048c95 <phase_3+0x8b>
 8048c90:	b8 00 00 00 00       	mov    $0x0,%eax
 8048c95:	05 d7 01 00 00       	add    $0x1d7,%eax
 8048c9a:	eb 05                	jmp    8048ca1 <phase_3+0x97>
 8048c9c:	b8 00 00 00 00       	mov    $0x0,%eax
 8048ca1:	2d d7 01 00 00       	sub    $0x1d7,%eax
 8048ca6:	eb 0a                	jmp    8048cb2 <phase_3+0xa8>
 8048ca8:	e8 78 04 00 00       	call   8049125 <explode_bomb>
 8048cad:	b8 00 00 00 00       	mov    $0x0,%eax
 8048cb2:	83 7c 24 18 05       	cmpl   $0x5,0x18(%esp) 
 8048cb7:	7f 06                	jg     8048cbf <phase_3+0xb5> 
 8048cb9:	3b 44 24 1c          	cmp    0x1c(%esp),%eax
 8048cbd:	74 05                	je     8048cc4 <phase_3+0xba> 
 8048cbf:	e8 61 04 00 00       	call   8049125 <explode_bomb>
 8048cc4:	83 c4 2c             	add    $0x2c,%esp
 8048cc7:	c3                   	ret    
 8048c0a:	83 ec 2c             	sub    $0x2c,%esp
 8048c0d:	8d 44 24 1c          	lea    0x1c(%esp),%eax
 8048c11:	89 44 24 0c          	mov    %eax,0xc(%esp)
 8048c15:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048c19:	89 44 24 08          	mov    %eax,0x8(%esp)
 8048c1d:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp)
 8048c24:	08 
 8048c25:	8b 44 24 30          	mov    0x30(%esp),%eax
 8048c29:	89 04 24             	mov    %eax,(%esp)
 8048c2c:	e8 2f fc ff ff       	call   8048860 <__isoc99_sscanf@plt>

这一段汇编代码就是在做输入的准备工作,查看$0x804a30f,是要输入两个整型的数字,__isoc99_sscanf@plt这个函数返回到eax中输入数字的个数

8048c31:	83 f8 01             	cmp    $0x1,%eax
8048c34:	7f 05                	jg     8048c3b <phase_3+0x31>
8048c36:	e8 ea 04 00 00       	call   8049125 <explode_bomb>
要求输入的数字个数必须大于1个,否则就爆炸
8048c3b:	83 7c 24 18 07       	cmpl  $0x7,0x18(%esp)
要求输入的第一个数要小于7
8048c40:	77 66                	ja     8048ca8 <phase_3+0x9e>
8048c42:	8b 44 24 18          	mov    0x18(%esp),%eax
8048c46:	ff 24 85 a0 a1 04 08 	jmp    *0x804a1a0(,%eax,4)
跳转到8048c54+4*(第一个数输入的值)
接下来运行的代码是:
8048c54:	b8 1e 01 00 00       	mov    $0x11e,%eax
8048c59:	2d e0 03 00 00       	sub    $0x3e0,%eax
8048c5e:	eb 05                	jmp    8048c65 <phase_3+0x5b> 
8048c65:	05 b7 01 00 00       	add    $0x1b7,%eax
8048c6a:	eb 05                	jmp    8048c71 <phase_3+0x67> 
8048c71:	2d d7 01 00 00       	sub    $0x1d7,%eax
8048c76:	eb 05                	jmp    8048c7d <phase_3+0x73> 
8048c7d:	05 d7 01 00 00       	add    $0x1d7,%eax
8048c82:	eb 05                	jmp    8048c89 <phase_3+0x7f> 
8048c89:	2d d7 01 00 00       	sub    $0x1d7,%eax
8048c8e:	eb 05                	jmp    8048c95 <phase_3+0x8b> 
8048ca1:	2d d7 01 00 00       	sub    $0x1d7,%eax
8048ca6:	eb 0a                	jmp    8048cb2 <phase_3+0xa8> 
8048cb2:	83 7c 24 18 05       	cmpl   $0x5,0x18(%esp) 
8048cb7:	7f 06                	jg     8048cbf <phase_3+0xb5> 

从以上汇编代码中可以看到进行了+$0x11e,-$0x3e0,+$0x1b7,-$0x1b7,+$0x1b7,-$0x1b7,-$0x1b7,结果等于-738
得出输入的第一个数字必须小于5 ,不然就会爆炸

8048cb9:	3b 44 24 1c          	cmp    0x1c(%esp),%eax
8048cbd:	74 05                	je     8048cc4 <phase_3+0xba>//相等跳转

如果第二个输入的数字和以上的运算结果eax不相等就会爆炸,所以在比较之前将0x1c(%esp)里面的值改成-738
得到第一个答案是0 -738
第二个答案是1 -1024
第三个答案是2 -32
第四个答案是3 -471
第五个答案是4 0

phase_4
 8048d12:	83 ec 2c             	sub    $0x2c,%esp
 8048d15:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048d19:	89 44 24 0c          	mov    %eax,0xc(%esp)
 8048d1d:	8d 44 24 1c          	lea    0x1c(%esp),%eax
 8048d21:	89 44 24 08          	mov    %eax,0x8(%esp)
 8048d25:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp)
 8048d2c:	08 
 8048d2d:	8b 44 24 30          	mov    0x30(%esp),%eax
 8048d31:	89 04 24             	mov    %eax,(%esp)
 8048d34:	e8 27 fb ff ff       	call   8048860 <__isoc99_sscanf@plt>
 8048d39:	83 f8 02             	cmp    $0x2,%eax
 8048d3c:	75 0c                	jne    8048d4a <phase_4+0x38>
 8048d3e:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048d42:	83 e8 02             	sub    $0x2,%eax
 8048d45:	83 f8 02             	cmp    $0x2,%eax
 8048d48:	76 05                	jbe    8048d4f <phase_4+0x3d>
 8048d4a:	e8 d6 03 00 00       	call   8049125 <explode_bomb>
 8048d4f:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048d53:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048d57:	c7 04 24 05 00 00 00 	movl   $0x5,(%esp)
 8048d5e:	e8 65 ff ff ff       	call   8048cc8 <func4>
 8048d63:	3b 44 24 1c          	cmp    0x1c(%esp),%eax
 8048d67:	74 05                	je     8048d6e <phase_4+0x5c>
 8048d69:	e8 b7 03 00 00       	call   8049125 <explode_bomb>
 8048d6e:	83 c4 2c             	add    $0x2c,%esp
 8048d71:	c3                   	ret     

通过

8048d25:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp)
 
看到需要我们输入两个整数
 8048d39:	83 f8 02             	cmp    $0x2,%eax
 8048d3c:	75 0c                	jne    8048d4a <phase_4+0x38>
 将我们输入的第二个数字进行比较,输入的第二个数字不是2就爆炸
 8048d3e:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048d42:	83 e8 02             	sub    $0x2,%eax
 8048d45:	83 f8 02             	cmp    $0x2,%eax
 8048d48:	76 05                	jbe    8048d4f <phase_4+0x3d>
 如果我们输入的第二个数字减2并转化为无符号数不等于2也爆炸,所以规定了我们第二个数字必须输入2
 8048d4f:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048d53:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048d57:	c7 04 24 05 00 00 00 	movl   $0x5,(%esp)
 8048d5e:	e8 65 ff ff ff       	call   8048cc8 <func4>
 将输入的第二个数字2和5放到栈的最前面,以便调用func4
func4
08048cc8 <func4>:
 8048cc8:	57                   	push   %edi
 8048cc9:	56                   	push   %esi
 8048cca:	53                   	push   %ebx
 8048ccb:	83 ec 10             	sub    $0x10,%esp
 8048cce:	8b 5c 24 20          	mov    0x20(%esp),%ebx
 8048cd2:	8b 74 24 24          	mov    0x24(%esp),%esi
 8048cd6:	85 db                	test   %ebx,%ebx
 8048cd8:	7e 2c                	jle    8048d06 <func4+0x3e>
 8048cda:	89 f0                	mov    %esi,%eax
 8048cdc:	83 fb 01             	cmp    $0x1,%ebx
 8048cdf:	74 2a                	je     8048d0b <func4+0x43>
 8048ce1:	89 74 24 04          	mov    %esi,0x4(%esp)
 8048ce5:	8d 43 ff             	lea    -0x1(%ebx),%eax
 8048ce8:	89 04 24             	mov    %eax,(%esp)
 8048ceb:	e8 d8 ff ff ff       	call   8048cc8 <func4>
 8048cf0:	8d 3c 30             	lea    (%eax,%esi,1),%edi
 8048cf3:	89 74 24 04          	mov    %esi,0x4(%esp)
 8048cf7:	83 eb 02             	sub    $0x2,%ebx
 8048cfa:	89 1c 24             	mov    %ebx,(%esp)
 8048cfd:	e8 c6 ff ff ff       	call   8048cc8 <func4>
 8048d02:	01 f8                	add    %edi,%eax
 8048d04:	eb 05                	jmp    8048d0b <func4+0x43>
 8048d06:	b8 00 00 00 00       	mov    $0x0,%eax
 8048d0b:	83 c4 10             	add    $0x10,%esp
 8048d0e:	5b                   	pop    %ebx
 8048d0f:	5e                   	pop    %esi
 8048d10:	5f                   	pop    %edi
 8048d11:	c3                   	ret    
通过phase_4可以得出func4调用的两个变量,形式如下
    func4(5, 2)
 8048cd6:	85 db                	test   %ebx,%ebx
 8048cd8:	7e 2c                	jle    8048d06 <func4+0x3e>
 要求func4变量1不能为0,否则返回0
 8048cda:	89 f0                	mov    %esi,%eax
 8048cdc:	83 fb 01             	cmp    $0x1,%ebx
 8048cdf:	74 2a                	je     8048d0b <func4+0x43>
 要求func4变量1不能为1,否则返回结果
 8048ce1:	89 74 24 04          	mov    %esi,0x4(%esp)
 8048ce5:	8d 43 ff             	lea    -0x1(%ebx),%eax
 8048ce8:	89 04 24             	mov    %eax,(%esp)
 8048ceb:	e8 d8 ff ff ff       	call   8048cc8 <func4>
 对应的代码是
 v3 = func4(a1 - 1, a2) + a2;
 8048cf0:	8d 3c 30             	lea    (%eax,%esi,1),%edi
 8048cf3:	89 74 24 04          	mov    %esi,0x4(%esp)
 8048cf7:	83 eb 02             	sub    $0x2,%ebx
 8048cfa:	89 1c 24             	mov    %ebx,(%esp)
 8048cfd:	e8 c6 ff ff ff       	call   8048cc8 <func4>
 对应的代码是
 return v3 + func4(a1 - 2, a2);
 8048d02:	01 f8                	add    %edi,%eax
 8048d04:	eb 05                	jmp    8048d0b <func4+0x43>
将翻译出来的c代码进行运行,即可得到我们的答案
#include<stdio.h>
int func4(int a1,int a2)
{
  int result; 
  int v3;
  if ( a1 <= 0 )
    return 0;
  result = a2;
  if ( a1 != 1 )
  {
    v3 = func4(a1 - 1, a2) + a2;
    return v3 + func4(a1 - 2, a2);
  }
  return result;
}
int main()
{
    int y;
    scanf("%d",&y);
    int result1 =func4(5,y);
    printf("%d",result1);
    getchar();
    return 0;
}

所以这道题的答案就是24 2

phase_5
08048d72 <phase_5>:
 8048d72:	83 ec 2c             	sub    $0x2c,%esp
 8048d75:	8d 44 24 1c          	lea    0x1c(%esp),%eax
 8048d79:	89 44 24 0c          	mov    %eax,0xc(%esp)
 8048d7d:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048d81:	89 44 24 08          	mov    %eax,0x8(%esp)
 8048d85:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp)
 8048d8c:	08 
 8048d8d:	8b 44 24 30          	mov    0x30(%esp),%eax
 8048d91:	89 04 24             	mov    %eax,(%esp)
 8048d94:	e8 c7 fa ff ff       	call   8048860 <__isoc99_sscanf@plt>
 8048d99:	83 f8 01             	cmp    $0x1,%eax
 8048d9c:	7f 05                	jg     8048da3 <phase_5+0x31>
 8048d9e:	e8 82 03 00 00       	call   8049125 <explode_bomb>
 8048da3:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048da7:	83 e0 0f             	and    $0xf,%eax
 8048daa:	89 44 24 18          	mov    %eax,0x18(%esp)
 8048dae:	83 f8 0f             	cmp    $0xf,%eax
 8048db1:	74 2a                	je     8048ddd <phase_5+0x6b> 
 8048db3:	b9 00 00 00 00       	mov    $0x0,%ecx
 8048db8:	ba 00 00 00 00       	mov    $0x0,%edx
 8048dbd:	83 c2 01             	add    $0x1,%edx
 8048dc0:	8b 04 85 c0 a1 04 08 	mov    0x804a1c0(,%eax,4),%eax
 8048dc7:	01 c1                	add    %eax,%ecx
 8048dc9:	83 f8 0f             	cmp    $0xf,%eax
 8048dcc:	75 ef                	jne    8048dbd <phase_5+0x4b>
 8048dce:	89 44 24 18          	mov    %eax,0x18(%esp)
 8048dd2:	83 fa 0f             	cmp    $0xf,%edx
 8048dd5:	75 06                	jne    8048ddd <phase_5+0x6b>
 8048dd7:	3b 4c 24 1c          	cmp    0x1c(%esp),%ecx
 8048ddb:	74 05                	je     8048de2 <phase_5+0x70>
 8048ddd:	e8 43 03 00 00       	call   8049125 <explode_bomb>
 8048de2:	83 c4 2c             	add    $0x2c,%esp
 8048de5:	c3                   	ret    
8048d85:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp)
由命令 x/s 0x804a30f 可以看到是需要我们输入两个整型的数字
 
根据`8048d5f`和`8048d67`两个地址的指令可知,我们的两个整数存放在`0x18(%esp)`和`0x1c(%esp)`处,简单起见,我们输入`1 2`。
 8048d99:	83 f8 01             	cmp    $0x1,%eax
 8048d9c:	7f 05                	jg     8048da3 <phase_5+0x31>
 要求输入的第二个数字大于1
 8048da3:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048da7:	83 e0 0f             	and    $0xf,%eax
 8048daa:	89 44 24 18          	mov    %eax,0x18(%esp)
 8048dae:	83 f8 0f             	cmp    $0xf,%eax
 8048db1:	74 2a                	je     8048ddd <phase_5+0x6b> 
 要求输入的数字不等于15
 8048db3:	b9 00 00 00 00       	mov    $0x0,%ecx
 8048db8:	ba 00 00 00 00       	mov    $0x0,%edx
 8048dbd:	83 c2 01             	add    $0x1,%edx
 8048dc0:	8b 04 85 c0 a1 04 08 	mov    0x804a1c0(,%eax,4),%eax
 8048dc7:	01 c1                	add    %eax,%ecx
 8048dc9:	83 f8 0f             	cmp    $0xf,%eax
 8048dcc:	75 ef                	jne    8048dbd <phase_5+0x4b>
 ecx是将eax里面的值加起来,edx是循环的计数器,0x804a1c0指向的是一组数组
 0x804a1c0(,%eax,4),%eax 是根据输入的第一个数字当作这个数组的下标,进行数组的读取
 再把读取到的值放回eax中,如果读取到的数组的值不是0xf,继续循环
 8048dbd:	83 c2 01             	add    $0x1,%edx
 8048dc0:	8b 04 85 c0 a1 04 08 	mov    0x804a1c0(,%eax,4),%eax
 8048dc7:	01 c1                	add    %eax,%ecx
 8048dc9:	83 f8 0f             	cmp    $0xf,%eax
 8048dcc:	75 ef                	jne    8048dbd <phase_5+0x4b>
 直到读取到的数组的值是0xf才跳出循环,所以无论我们第一个数输入的是什么值,在循环中一定能从数组中找到0x15
 8048dce:	89 44 24 18          	mov    %eax,0x18(%esp)
 8048dd2:	83 fa 0f             	cmp    $0xf,%edx
 8048dd5:	75 06                	jne    8048ddd <phase_5+0x6b>
 这里还要求循环必须15次
 8048dd7:	3b 4c 24 1c          	cmp    0x1c(%esp),%ecx
 8048ddb:	74 05                	je     8048de2 <phase_5+0x70>
 ecx累加的eax的值还必须等于输入的第二个值
 8048ddd:	e8 43 03 00 00       	call   8049125 <explode_bomb>
 8048de2:	83 c4 2c             	add    $0x2c,%esp
 最后我通过第一个数字遍历了0-5,5即是我找的答案
 最后的答案就是5 115
phase_6
08048de6 <phase_6>:
 8048de6:	56                   	push   %esi
 8048de7:	53                   	push   %ebx
 8048de8:	83 ec 44             	sub    $0x44,%esp
 8048deb:	8d 44 24 10          	lea    0x10(%esp),%eax
 8048def:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048df3:	8b 44 24 50          	mov    0x50(%esp),%eax
 8048df7:	89 04 24             	mov    %eax,(%esp)
 8048dfa:	e8 4d 03 00 00       	call   804914c <read_six_numbers>
 8048dff:	be 00 00 00 00       	mov    $0x0,%esi
 8048e04:	8b 44 b4 10          	mov    0x10(%esp,%esi,4),%eax
 8048e08:	83 e8 01             	sub    $0x1,%eax
 8048e0b:	83 f8 05             	cmp    $0x5,%eax
 8048e0e:	76 05                	jbe    8048e15 <phase_6+0x2f>
 8048e10:	e8 10 03 00 00       	call   8049125 <explode_bomb>
 8048e15:	83 c6 01             	add    $0x1,%esi
 8048e18:	83 fe 06             	cmp    $0x6,%esi//v1
 8048e1b:	75 07                	jne    8048e24 <phase_6+0x3e>
 8048e1d:	bb 00 00 00 00       	mov    $0x0,%ebx
 8048e22:	eb 38                	jmp    8048e5c <phase_6+0x76>
 8048e24:	89 f3                	mov    %esi,%ebx 
 8048e26:	8b 44 9c 10          	mov    0x10(%esp,%ebx,4),%eax
 8048e2a:	39 44 b4 0c          	cmp    %eax,0xc(%esp,%esi,4) 
 8048e2e:	75 05                	jne    8048e35 <phase_6+0x4f>
 8048e30:	e8 f0 02 00 00       	call   8049125 <explode_bomb>
 8048e35:	83 c3 01             	add    $0x1,%ebx 
 8048e38:	83 fb 05             	cmp    $0x5,%ebx 
 8048e3b:	7e e9                	jle    8048e26 <phase_6+0x40> 
 8048e3d:	eb c5                	jmp    8048e04 <phase_6+0x1e
 8048e3f:	8b 52 08             	mov    0x8(%edx),%edx
     //这里跨8个字节是因为,该地址是一个结构体,第一位放的是value,第二位放的是id
 8048e42:	83 c0 01             	add    $0x1,%eax//++v5
 8048e45:	39 c8                	cmp    %ecx,%eax
 8048e47:	75 f6                	jne    8048e3f <phase_6+0x59>
 8048e49:	eb 05                	jmp    8048e50 <phase_6+0x6a>
 8048e4b:	ba 3c c1 04 08       	mov    $0x804c13c,%edx//取node1地址
 8048e50:	89 54 b4 28          	mov    %edx,0x28(%esp,%esi,4) 
 8048e54:	83 c3 01             	add    $0x1,%ebx//++i
 8048e57:	83 fb 06             	cmp    $0x6,%ebx
 8048e5a:	74 17                	je     8048e73 <phase_6+0x8d>
 8048e5c:	89 de                	mov    %ebx,%esi//esi=i
 8048e5e:	8b 4c 9c 10          	mov    0x10(%esp,%ebx,4),%ecx 
 8048e62:	83 f9 01             	cmp    $0x1,%ecx
 8048e65:	7e e4                	jle    8048e4b <phase_6+0x65>
 8048e67:	b8 01 00 00 00       	mov    $0x1,%eax//v5=eax=1
 8048e6c:	ba 3c c1 04 08       	mov    $0x804c13c,%edx//取node1地址
 8048e71:	eb cc                	jmp    8048e3f <phase_6+0x59>
       //for array[x+6]存的是id=array[x]的节点的地址;
 8048e73:	8b 5c 24 28          	mov    0x28(%esp),%ebx//ebx=int v15
 8048e77:	8d 44 24 2c          	lea    0x2c(%esp),%eax//eax=char v16
 8048e7b:	8d 74 24 40          	lea    0x40(%esp),%esi//esi=char v17
 8048e7f:	89 d9                	mov    %ebx,%ecx//ecx=j=v15
 8048e81:	8b 10                	mov    (%eax),%edx
 8048e83:	89 51 08             	mov    %edx,0x8(%ecx)
 8048e86:	83 c0 04             	add    $0x4,%eax
 8048e89:	39 f0                	cmp    %esi,%eax
 8048e8b:	74 04                	je     8048e91 <phase_6+0xab>
 8048e8d:	89 d1                	mov    %edx,%ecx
 8048e8f:	eb f0                	jmp    8048e81 <phase_6+0x9b>
          //for 借助ecx把0x804c13c结构体按顺序排列好在ebx中
 8048e91:	c7 42 08 00 00 00 00 	movl   $0x0,0x8(%edx)
 8048e98:	be 05 00 00 00       	mov    $0x5,%esi
 8048e9d:	8b 43 08             	mov    0x8(%ebx),%eax
 8048ea0:	8b 00                	mov    (%eax),%eax
 8048ea2:	39 03                	cmp    %eax,(%ebx)
 8048ea4:	7e 05                	jle    8048eab <phase_6+0xc5>
 8048ea6:	e8 7a 02 00 00       	call   8049125 <explode_bomb>
 8048eab:	8b 5b 08             	mov    0x8(%ebx),%ebx
 8048eae:	83 ee 01             	sub    $0x1,%esi
 8048eb1:	75 ea                	jne    8048e9d <phase_6+0xb7>
           //while  用ebx查看结构体中的值是否是从小到大排好顺序
 8048eb3:	83 c4 44             	add    $0x44,%esp
 8048eb6:	5b                   	pop    %ebx
 8048eb7:	5e                   	pop    %esi
 8048eb8:	c3                   	ret    

查看该地址知道是结构体,三个成员是:value、id、next
所以我们知道array[x+6]存的是id=array[x]的节点的地址;
M(array[x+6])存的是id=array[x]的节点的value;
M(array[x+6]+8)存的是id=array[x]的节点的next;

函数执行过程是:先输入array[x]并判断是否在[1,6]且各不相同;
将id=array[x]的节点地址存到array[x+6];
将id=array[x]的节点的地址的next成员改写成id=array[x+1]的节点的地址,也就是array[x+6]->next=array[x+6+1];
判断排序后的链表节点的value成员大小是否是递增的。
所以我们输入的数,其实是6个节点的id成员,函数按照输入id的顺序,将这六个节点排序,排序后的链表是递增的。
id 1 2 3 4 5 6
value 921 214 532 545 622 216

所以我们得到答案2 6 3 4 5 1

phase_defused
 08049296 <phase_defused>:
 8049296:	81 ec 8c 00 00 00    	sub    $0x8c,%esp
 804929c:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 80492a2:	89 44 24 7c          	mov    %eax,0x7c(%esp)
 80492a6:	31 c0                	xor    %eax,%eax
 80492a8:	83 3d c8 c3 04 08 06 	cmpl   $0x6,0x804c3c8
 80492af:	75 72                	jne    8049323 <phase_defused+0x8d>
 80492b1:	8d 44 24 2c          	lea    0x2c(%esp),%eax
 80492b5:	89 44 24 10          	mov    %eax,0x10(%esp)
 80492b9:	8d 44 24 28          	lea    0x28(%esp),%eax
 80492bd:	89 44 24 0c          	mov    %eax,0xc(%esp)
 80492c1:	8d 44 24 24          	lea    0x24(%esp),%eax
 80492c5:	89 44 24 08          	mov    %eax,0x8(%esp)
 80492c9:	c7 44 24 04 69 a3 04 	movl   $0x804a369,0x4(%esp)
 80492d0:	08 
 80492d1:	c7 04 24 d0 c4 04 08 	movl   $0x804c4d0,(%esp)
 80492d8:	e8 83 f5 ff ff       	call   8048860 <__isoc99_sscanf@plt>
 80492dd:	83 f8 03             	cmp    $0x3,%eax
 80492e0:	75 35                	jne    8049317 <phase_defused+0x81>
 80492e2:	c7 44 24 04 72 a3 04 	movl   $0x804a372,0x4(%esp)
 80492e9:	08 
 80492ea:	8d 44 24 2c          	lea    0x2c(%esp),%eax
 80492ee:	89 04 24             	mov    %eax,(%esp)
 80492f1:	e8 24 fd ff ff       	call   804901a <strings_not_equal>
 80492f6:	85 c0                	test   %eax,%eax
 80492f8:	75 1d                	jne    8049317 <phase_defused+0x81>
 80492fa:	c7 04 24 38 a2 04 08 	movl   $0x804a238,(%esp)
 80 49301:	e8 ea f4 ff ff       	call   80487f0 <puts@plt>
 8049306:	c7 04 24 60 a2 04 08 	movl   $0x804a260,(%esp)
 804930d:	e8 de f4 ff ff       	call   80487f0 <puts@plt>
 8049312:	e8 f3 fb ff ff       	call   8048f0a <secret_phase>
 8049317:	c7 04 24 98 a2 04 08 	movl   $0x804a298,(%esp)
 804931e:	e8 cd f4 ff ff       	call   80487f0 <puts@plt>
 8049323:	8b 44 24 7c          	mov    0x7c(%esp),%eax
 8049327:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 804932e:	74 05                	je     8049335 <phase_defused+0x9f>
 8049330:	e8 8b f4 ff ff       	call   80487c0 <__stack_chk_fail@plt>
 8049335:	81 c4 8c 00 00 00    	add    $0x8c,%esp
 804933b:	c3                   	ret    
 804933c:	66 90                	xchg   %ax,%ax
 804933e:	66 90                	xchg   %ax,%ax

寻找隐藏关卡入口:
• 首先,使用了一个 0x804c3c8 的值,这个值从汇编代码自带的提示中可以猜想得到,是一个当前已经输入的关卡数,即字符串数。而该比较语句的含义是,只有在已完成关卡6的情况下才能进入到secret_phase。否则,将会直接跳到<+123>语句,失去进入<+108>秘密关卡函数的机会。

80492c9:	c7 44 24 04 69 a3 04 	movl   $0x804a369,0x4(%esp)
80492d0:	08 
80492d1:	c7 04 24 d0 c4 04 08 	movl   $0x804c4d0,(%esp)
80492d8:	e8 83 f5 ff ff       	call   8048860 <__isoc99_sscanf@plt>

• 其次,是一个sscanf语句。然而,sscanf语言的参数相比于前面的参数要多了一个。通过x/s 0x804a369语句查看,输入格式为"%d %d %s"
• 于是,我们想到sscanf语句与scanf语句的不同之处。sscanf语句可以有一个字符串参数,用于指定sscanf所需输入的字符串的源。(默认源是标准输入)
• 而这个字符串应当由我们输入触发隐藏关卡才对,为什么会由汇编语言给出?这就说明应该是我们前面的输入,保存到了这个地方。使得隐藏函数的以触发。

这是第四关的答案,说明隐藏关卡在第四关,但是还缺少一个字符串

 80492e2:	c7 44 24 04 72 a3 04 	movl   $0x804a372,0x4(%esp)
 80492e9:	08 
 80492ea:	8d 44 24 2c          	lea    0x2c(%esp),%eax
 80492ee:	89 04 24             	mov    %eax,(%esp)
 80492f1:	e8 24 fd ff ff       	call   804901a <strings_not_equal>

我们知道可以通过在第4关输入"24 2 DrEvil"作为通关密钥的同时,开启隐藏关卡。

进入调试阶段,提醒我们已经进入隐藏关卡

 08048f0a <secret_phase>:
 8048f0a:	53                   	push   %ebx
 8048f0b:	83 ec 18             	sub    $0x18,%esp
 8048f0e:	e8 89 02 00 00       	call   804919c <read_line>
 8048f13:	c7 44 24 08 0a 00 00 	movl   $0xa,0x8(%esp) #按十进制转换
 8048f1a:	00 
 8048f1b:	c7 44 24 04 00 00 00 	movl   $0x0,0x4(%esp)#将字符串要保存到的地址设置为空地址
 8048f22:	00 
 8048f23:	89 04 24             	mov    %eax,(%esp)#要转换的字符串是标准输入进来的,为0x6e
 8048f26:	e8 a5 f9 ff ff       	call   80488d0 <strtol@plt>
 8048f2b:	89 c3                	mov    %eax,%ebx #保存该转换后的数字
 8048f2d:	8d 40 ff             	lea    -0x1(%eax),%eax #将该数字-=1
 8048f30:	3d e8 03 00 00       	cmp    $0x3e8,%eax
 8048f35:	76 05                	jbe    8048f3c <secret_phase+0x32>
 8048f37:	e8 e9 01 00 00       	call   8049125 <explode_bomb>
 8048f3c:	89 5c 24 04          	mov    %ebx,0x4(%esp)
 8048f40:	c7 04 24 88 c0 04 08 	movl   $0x804c088,(%esp)//存放根的值
 8048f47:	e8 6d ff ff ff       	call   8048eb9 <fun7>
 8048f4c:	83 f8 05             	cmp    $0x5,%eax
     //如果<fun7>的返回值%eax如果等于5我们就能成功拆除炸弹
 8048f4f:	74 05                	je     8048f56 <secret_phase+0x4c>
 8048f51:	e8 cf 01 00 00       	call   8049125 <explode_bomb>
 8048f56:	c7 04 24 74 a1 04 08 	movl   $0x804a174,(%esp)
 8048f5d:	e8 8e f8 ff ff       	call   80487f0 <puts@plt>
 8048f62:	e8 2f 03 00 00       	call   8049296 <phase_defused>
 8048f67:	83 c4 18             	add    $0x18,%esp
 8048f6a:	5b                   	pop    %ebx
 8048f6b:	c3                   	ret    
 8048f6c:	66 90                	xchg   %ax,%ax
 8048f6e:	66 90                	xchg   %ax,%ax
 8048f0e:	e8 89 02 00 00       	call   804919c <read_line>
 8048f13:	c7 44 24 08 0a 00 00 	movl   $0xa,0x8(%esp) #按十进制转换
 8048f1a:	00 
 8048f1b:	c7 44 24 04 00 00 00 	movl   $0x0,0x4(%esp)#将字符串要保存到的地址设置为空地址
 8048f22:	00 
 8048f23:	89 04 24             	mov    %eax,(%esp)#要转换的字符串是标准输入进来的
输入的值通过 x/4bx,查到是0x6e
 
8048f40:	c7 04 24 88 c0 04 08 	movl   $0x804c088,(%esp)//里面的值是0x24
 8048f47:	e8 6d ff ff ff       	call   8048eb9 <fun7>
 8048f4c:	83 f8 05             	cmp    $0x5,%eax
     //如果<fun7>的返回值%eax如果等于5我们就能成功拆除炸弹
08048eb9 <fun7>:
 8048eb9:	53                   	push   %ebx
 8048eba:	83 ec 18             	sub    $0x18,%esp
 8048ebd:	8b 54 24 20          	mov    0x20(%esp),%edx//edx = 根节点的地址
 8048ec1:	8b 4c 24 24          	mov    0x24(%esp),%ecx//ecx = 输入参数
 8048ec5:	85 d2                	test   %edx,%edx//根节点为空时返回-1
 8048ec7:	74 37                	je     8048f00 <fun7+0x47>
 8048ec9:	8b 1a                	mov    (%edx),%ebx//ebx = 根节点的值
 8048ecb:	39 cb                	cmp    %ecx,%ebx# if 根节点值 <= 参数
 8048ecd:	7e 13                	jle    8048ee2 <fun7+0x29># 进入右子树
 8048ecf:	89 4c 24 04          	mov    %ecx,0x4(%esp) # 否则进入左子树
 8048ed3:	8b 42 04             	mov    0x4(%edx),%eax
 8048ed6:	89 04 24             	mov    %eax,(%esp)
 8048ed9:	e8 db ff ff ff       	call   8048eb9 <fun7>
 8048ede:	01 c0                	add    %eax,%eax
 8048ee0:	eb 23                	jmp    8048f05 <fun7+0x4c>
 8048ee2:	b8 00 00 00 00       	mov    $0x0,%eax
 8048ee7:	39 cb                	cmp    %ecx,%ebxl
 8048ee9:	74 1a                	je     8048f05 <fun7+0x4c>
 8048eeb:	89 4c 24 04          	mov    %ecx,0x4(%esp)
 8048eef:	8b 42 08             	mov    0x8(%edx),%eax
 8048ef2:	89 04 24             	mov    %eax,(%esp)
 8048ef5:	e8 bf ff ff ff       	call   8048eb9 <fun7>
 8048efa:	8d 44 00 01          	lea    0x1(%eax,%eax,1),%eax
 8048efe:	eb 05                	jmp    8048f05 <fun7+0x4c>
 8048f00:	b8 ff ff ff ff       	mov    $0xffffffff,%eax
 8048f05:	83 c4 18             	add    $0x18,%esp
 8048f08:	5b                   	pop    %ebx
 8048f09:	c3                   	ret    

将func7翻译成c语言

int fun7(int *address, int number) {
	if (address == null)
		return -1;
	if (*address <= number) {
		if (*address == number )
			return 0;
		else
			2 * fun7(*(address + 8), number) + 1;
	} else
		2 * fun7(*(address + 4), number);
}

因为返回值要为5,推导:0->1->2->5,地址+8跳转到2 * fun7((address + 8), number) + 1;地址+4跳转到2 * fun7((address + 4), number);
所以地址变化:加8、加4、加8,依次查看(向右,向左,向右
用的是 08048f0a <secret_phase>:
8048f40: c7 04 24 88 c0 04 08 movl $0x804c088,(%esp)//里面的值是0x24
从0x804c088开始找

分析其为二叉树,画出二叉树

加8、加4、加8,依次查看(向右,向左,向右
最后答案是0x2f

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值