【实验记录】csapp实验二(详细):BOMB LAB

总共7个phase,非常好玩…
进入每一个phase时,我们应该弄清楚的是:
1、输入格式:需要我们输入什么,是字符串,还是整数,还是字符,输入个数是多少?
2、爆炸点:哪些语句可能引起爆炸,通常为一个比较语句cmp,这是解题的关键,告诉应该输入的值是多少。因此,找到这些爆炸点即可能跳到<explode_bomb>爆炸函数的语句,在这些地方打上断点哦。
3、循环、递归:当发现jump会往之前的语句跳时,可能是循环或者递归,建议在这段代码做个标记,弄清楚每一段在做什么操作。
4、每个寄存器是用来干什么的:
在这里插入图片描述
最常使用的gdb语句:
1、b+空格+地址/函数名打断点
2、x /s+地址/寄存器 打印该地址处的字符串,s可以换成其他字母,d打印十进制整数,c打印字符,x打印十六进制整数。
3、i r查看寄存器的值(同info r)。
4、stepi单步进入,不跳过子函数;nexti跳过子函数,逐步执行主函数。
5、continue跳到下一个断点。
6、run开始运行。

另外!!可以画图帮助理解!!

命令行中进入实验,然后打开gdb开始调试:

gdb ./bomb

然后在每个炸弹处打断点:phase_1 到 phase_6

(gdb) b phase_1

phase_1

000000000400ead <phase_1>:
  400ead:	48 83 ec 08          	sub    $0x8,%rsp
  400eb1:	be 8c 24 40 00       	mov    $0x40248c,%esi
  400eb6:	e8 4b 05 00 00       	callq  401406 <strings_not_equal>
  400ebb:	85 c0                	test   %eax,%eax
  400ebd:	74 05                	je     400ec4 <phase_1+0x17>
  400ebf:	e8 41 06 00 00       	callq  401505 <explode_bomb>
  400ec4:	48 83 c4 08          	add    $0x8,%rsp
  400ec8:	c3                   	retq   

进入phase_1后,第二行看到比较输入参数和存储在地址 0x40248c 处的值,gdb调试中输入并得到:

(gdb) x /s 0x40248c
0x40248c:       "Public speaking is very easy."

答案 :Public speaking is very easy.

phase_2

小 tips:先把炸弹找出来,然后在可能跳到炸弹的地方打断点。

000000000400ec9 <phase_2>:
  400ec9:	55                   	push   %rbp
  400eca:	53                   	push   %rbx
  400ecb:	48 83 ec 28          	sub    $0x28,%rsp
  400ecf:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  400ed6:	00 00 
  400ed8:	48 89 44 24 18       	mov    %rax,0x18(%rsp)
  400edd:	31 c0                	xor    %eax,%eax
  400edf:	48 89 e6             	mov    %rsp,%rsi
  400ee2:	e8 40 06 00 00       	callq  401527 <read_six_numbers>
  400ee7:	83 3c 24 00          	cmpl   $0x0,(%rsp)       //x1=0
  400eeb:	75 07                	jne    400ef4 <phase_2+0x2b>     
  400eed:	83 7c 24 04 01       	cmpl   $0x1,0x4(%rsp)    //x2=1
  400ef2:	74 05                	je     400ef9 <phase_2+0x30>
  400ef4:	e8 0c 06 00 00       	callq  401505 <explode_bomb>
  400ef9:	48 89 e3             	mov    %rsp,%rbx
  400efc:	48 8d 6c 24 10       	lea    0x10(%rsp),%rbp//x5
                                           //循环
  400f01:	8b 43 04             	mov    0x4(%rbx),%eax//x2 x3..x5
  400f04:	03 03                	add    (%rbx),%eax //x1+x2  x2+x3.. x4+x5
  400f06:	39 43 08             	cmp    %eax,0x8(%rbx)
                  //x3=x1+x2=1 x4=x2+x3=2 x5=x3+x4 x6=x4+x5=5
  400f09:	74 05                	je     400f10 <phase_2+0x47>
  400f0b:	e8 f5 05 00 00       	callq  401505 <explode_bomb>
  400f10:	48 83 c3 04          	add    $0x4,%rbx//x2->x5
  400f14:	48 39 eb             	cmp    %rbp,%rbx//比较x2和x5 x3和x5..
  400f17:	75 e8                	jne    400f01 <phase_2+0x38>   
                                           //循环结束 
  400f19:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  400f1e:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  400f25:	00 00 
  400f27:	74 05                	je     400f2e <phase_2+0x65>
  400f29:	e8 f2 fb ff ff       	callq  400b20 <__stack_chk_fail@plt>
  400f2e:	48 83 c4 28          	add    $0x28,%rsp
  400f32:	5b                   	pop    %rbx
  400f33:	5d                   	pop    %rbp
  400f34:	c3                   	retq   

前5行和后7行可以跳过,callq 401527 <read_six_numbers>告诉我们读取6个数,猜测输入为6个整数。
往下看,有给在栈中,栈顶保存的值应为x1=0,向上x2=1,否则会jump到
401505 <explode_bomb>炸弹爆炸。
然后在%rbp中保留了x5,即lea 0x10(%rsp),%rbp 0x10是16,栈顶为x1,每4位一个整数,那么0x10(%rsp)就是x5,然后进入循环,循环过程打在代码数字里面了,最后发现是斐波那契数列的前六个数。
答案 : 0 1 1 2 3 5

phase_3

粗略地总体看一下,中间有很多400f8e: 00类似的语句,然后它们之间的代码好像做的都是差不多是操作。

000000000400f35 <phase_3>:
  400f35:	48 83 ec 28          	sub    $0x28,%rsp
  400f39:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  400f40:	00 00 
  400f42:	48 89 44 24 18       	mov    %rax,0x18(%rsp)
  400f47:	31 c0                	xor    %eax,%eax
  400f49:	4c 8d 44 24 14       	lea    0x14(%rsp),%r8
  400f4e:	48 8d 4c 24 0f       	lea    0xf(%rsp),%rcx
  400f53:	48 8d 54 24 10       	lea    0x10(%rsp),%rdx
  400f58:	be aa 24 40 00       	mov    $0x4024aa,%esi     // "%d %c %d"
  400f5d:	e8 7e fc ff ff       	callq  400be0 <__isoc99_sscanf@plt> 
  400f62:	83 f8 02             	cmp    $0x2,%eax      //输入的东西个数为3
  400f65:	7f 05                	jg     400f6c <phase_3+0x37>
  400f67:	e8 99 05 00 00       	callq  401505 <explode_bomb>
  
  400f6c:	83 7c 24 10 07       	cmpl   $0x7,0x10(%rsp)
  400f71:	0f 87 fc 00 00 00    	ja     401073 <phase_3+0x13e> //不可以跳<=7
  400f77:	8b 44 24 10          	mov    0x10(%rsp),%eax
  400f7b:	ff 24 c5 c0 24 40 00 	jmpq   *0x4024c0(,%rax,8)
  400f82:	b8 77 00 00 00       	mov    $0x77,%eax
  400f87:	81 7c 24 14 91 03 00 	cmpl   $0x391,0x14(%rsp) //相等
  400f8e:	00 
  400f8f:	0f 84 e8 00 00 00    	je     40107d <phase_3+0x148>
  400f95:	e8 6b 05 00 00       	callq  401505 <explode_bomb>
  400f9a:	b8 77 00 00 00       	mov    $0x77,%eax
  400f9f:	e9 d9 00 00 00       	jmpq   40107d <phase_3+0x148>
  400fa4:	b8 6a 00 00 00       	mov    $0x6a,%eax
  400fa9:	81 7c 24 14 f6 02 00 	cmpl   $0x2f6,0x14(%rsp)
  400fb0:	00 
  400fb1:	0f 84 c6 00 00 00    	je     40107d <phase_3+0x148>
  400fb7:	e8 49 05 00 00       	callq  401505 <explode_bomb>
  400fbc:	b8 6a 00 00 00       	mov    $0x6a,%eax
  400fc1:	e9 b7 00 00 00       	jmpq   40107d <phase_3+0x148>
  400fc6:	b8 61 00 00 00       	mov    $0x61,%eax
  400fcb:	81 7c 24 14 7d 03 00 	cmpl   $0x37d,0x14(%rsp)
  400fd2:	00 
  400fd3:	0f 84 a4 00 00 00    	je     40107d <phase_3+0x148>
  400fd9:	e8 27 05 00 00       	callq  401505 <explode_bomb>
  400fde:	b8 61 00 00 00       	mov    $0x61,%eax
  400fe3:	e9 95 00 00 00       	jmpq   40107d <phase_3+0x148>
  400fe8:	b8 65 00 00 00       	mov    $0x65,%eax
  400fed:	81 7c 24 14 85 00 00 	cmpl   $0x85,0x14(%rsp)
  400ff4:	00 
  400ff5:	0f 84 82 00 00 00    	je     40107d <phase_3+0x148>
  400ffb:	e8 05 05 00 00       	callq  401505 <explode_bomb>
  401000:	b8 65 00 00 00       	mov    $0x65,%eax
  401005:	eb 76                	jmp    40107d <phase_3+0x148>
  401007:	b8 64 00 00 00       	mov    $0x64,%eax
  40100c:	81 7c 24 14 f3 00 00 	cmpl   $0xf3,0x14(%rsp)
  401013:	00 
  401014:	74 67                	je     40107d <phase_3+0x148>
  401016:	e8 ea 04 00 00       	callq  401505 <explode_bomb>
  40101b:	b8 64 00 00 00       	mov    $0x64,%eax
  401020:	eb 5b                	jmp    40107d <phase_3+0x148>
  401022:	b8 6f 00 00 00       	mov    $0x6f,%eax
  401027:	81 7c 24 14 9d 03 00 	cmpl   $0x39d,0x14(%rsp)
  40102e:	00 
  40102f:	74 4c                	je     40107d <phase_3+0x148>
  401031:	e8 cf 04 00 00       	callq  401505 <explode_bomb>
  401036:	b8 6f 00 00 00       	mov    $0x6f,%eax
  40103b:	eb 40                	jmp    40107d <phase_3+0x148>
  40103d:	b8 6e 00 00 00       	mov    $0x6e,%eax
  401042:	81 7c 24 14 bf 01 00 	cmpl   $0x1bf,0x14(%rsp)
  401049:	00 
  40104a:	74 31                	je     40107d <phase_3+0x148>
  40104c:	e8 b4 04 00 00       	callq  401505 <explode_bomb>
  401051:	b8 6e 00 00 00       	mov    $0x6e,%eax
  401056:	eb 25                	jmp    40107d <phase_3+0x148>
  401058:	b8 6b 00 00 00       	mov    $0x6b,%eax
  40105d:	81 7c 24 14 a0 01 00 	cmpl   $0x1a0,0x14(%rsp)
  401064:	00 0
  401065:	74 16                	je     40107d <phase_3+0x148>
  401067:	e8 99 04 00 00       	callq  401505 <explode_bomb>
  40106c:	b8 6b 00 00 00       	mov    $0x6b,%eax
  401071:	eb 0a                	jmp    40107d <phase_3+0x148>
  401073:	e8 8d 04 00 00       	callq  401505 <explode_bomb>
  401078:	b8 62 00 00 00       	mov    $0x62,%eax
  
  40107d:	3a 44 24 0f          	cmp    0xf(%rsp),%al //相等
  401081:	74 05                	je     401088 <phase_3+0x153>
  401083:	e8 7d 04 00 00       	callq  401505 <explode_bomb>
  401088:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  40108d:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  401094:	00 00 
  401096:	74 05                	je     40109d <phase_3+0x168>
  401098:	e8 83 fa ff ff       	callq  400b20 <__stack_chk_fail@plt>
  40109d:	48 83 c4 28          	add    $0x28,%rsp
  4010a1:	c3                   	retq   

一开始 0x400f49->0x400f53 很令人迷惑,不知道在干嘛,继续往下看。
看了后四行恍然大悟,看到 mov $0x4024aa,%esi,gdb查看0x4024aa处的值
因为%rsi为参数寄存器,会传给下一个函数
callq 400be0 <__isoc99_sscanf@plt>,我们可以查一下这个标准函数是计算输入个数的,那么0x4024aa处应该是一个串,我们s查看

(gdb) x /s 0x4024aa
0x4024aa:       "%d %c %d"

!! 输入格式为 "%d %c %d"

然后是比较输入个数,输入个数必须要超过2,明显可以看出我们的输入个数为3个,会跳过炸弹。
到这里,回头看这三句就可以理解啦!

  400f49:	4c 8d 44 24 14          lea    0x14(%rsp),%r8
  400f4e:	48 8d 4c 24 0f       	lea    0xf(%rsp),%rcx
  400f53:	48 8d 54 24 10       	lea    0x10(%rsp),%rdx

从下往上 0xf(%rsp) 存输入 %c0x10(%rsp)0x14(%rsp) 分别存了输入的两个整数 %d
猜一下,第一个数x1保存在0x10(%rsp) ,第二个数保存在0x14(%rsp)

  400f6c:	83 7c 24 10 07       	cmpl   $0x7,0x10(%rsp)
  400f71:	0f 87 fc 00 00 00    	ja     401073 <phase_3+0x13e>

这两句,提示x1>=7,不然就会爆炸。
紧接着:出现一个地址,还有一个随着x1变化的偏移量,gdb中查看该地址处的值

 400f7b:	ff 24 c5 c0 24 40 00 	jmpq   *0x4024c0(,%rax,8)
(gdb) x /x 0x4024c0
0x4024c0:       0x00400f82

这一句是就是下一个语句,当x1=0便会跳到这一句,前面有x1<=7的条件,那猜测如果x1=1、2、3、4、5、6、7呢,在gdb中获取另外7个地址,但x1=7时是无效地址,所以舍去。
然后依次查看这些地址,有很多重复操作的地方:如下

mov    $0x77,%eax
cmpl   $0x391,0x14(%rsp)
je     40107d <phase_3+0x148>

这段时关键,%rax此时存一个值,这个值会在0x40107d与输入的进行比较:

40107d:	3a 44 24 0f          	cmp    0xf(%rsp),%al

所以当x1=0时,输入字符的ASCII值为0x77,x2为0x391,转换成字符与十进制整数就是0 w 913。另还有6个答案。至此,可以知道这是一个switch语句,当值为0-6时跳转到不同的地方。
答案 :0 w 913 / 1 i 758 / 2 a 893 / 3 e 133 / 4 d 243 / 5 o 925 / 6 n 447

phase_4

00000000004010d5 <phase_4>:
  4010d5:	48 83 ec 18          	sub    $0x18,%rsp
  4010d9:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  4010e0:	00 00 
  4010e2:	48 89 44 24 08       	mov    %rax,0x8(%rsp)
  4010e7:	31 c0                	xor    %eax,%eax
  4010e9:	48 8d 4c 24 04       	lea    0x4(%rsp),%rcx
  4010ee:	48 89 e2             	mov    %rsp,%rdx
  4010f1:	be 77 26 40 00       	mov    $0x402677,%esi
  4010f6:	e8 e5 fa ff ff       	callq  400be0 <__isoc99_sscanf@plt>
  4010fb:	83 f8 02             	cmp    $0x2,%eax        //=2
  4010fe:	75 06                	jne    401106 <phase_4+0x31>
  401100:	83 3c 24 0e          	cmpl   $0xe,(%rsp)      //<=e
  401104:	76 05                	jbe    40110b <phase_4+0x36>
  401106:	e8 fa 03 00 00       	callq  401505 <explode_bomb>
  40110b:	ba 0e 00 00 00       	mov    $0xe,%edx
  401110:	be 00 00 00 00       	mov    $0x0,%esi
  401115:	8b 3c 24             	mov    (%rsp),%edi
  401118:	e8 85 ff ff ff       	callq  4010a2 <func4>
  40111d:	83 f8 23             	cmp    $0x23,%eax
  401120:	75 07                	jne    401129 <phase_4+0x54>
  401122:	83 7c 24 04 23       	cmpl   $0x23,0x4(%rsp) //返回0x23
  401127:	74 05                	je     40112e <phase_4+0x59>
  401129:	e8 d7 03 00 00       	callq  401505 <explode_bomb>
  40112e:	48 8b 44 24 08       	mov    0x8(%rsp),%rax
  401133:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  40113a:	00 00 
  40113c:	74 05                	je     401143 <phase_4+0x6e>
  40113e:	e8 dd f9 ff ff       	callq  400b20 <__stack_chk_fail@plt>
  401143:	48 83 c4 18          	add    $0x18,%rsp
  401147:	c3                   	retq   

同样,出现这一段:

  4010f1:	be 77 26 40 00       	mov    $0x402677,%esi
  4010f6:	e8 e5 fa ff ff       	callq  400be0 <__isoc99_sscanf@plt>
  4010fb:	83 f8 02             	cmp    $0x2,%eax        //=2
  4010fe:	75 06                	jne    401106 <phase_4+0x31>

我们查看0x402677处的东西:

(gdb) x /s 0x402677
0x402677:       "%d %d"

了解到输入是两个整数,设为x1和x2。下面是对输入个数的判断,不为两个则会引爆炸弹。
然后下面的一段,为函数func4作参数准备,%rdi、%rsi、%rdx应该为3个参数,

  401100:	83 3c 24 0e          	cmpl   $0xe,(%rsp)      //<=e
  401104:	76 05                	jbe    40110b <phase_4+0x36>
  401106:	e8 fa 03 00 00       	callq  401505 <explode_bomb>
  40110b:	ba 0e 00 00 00       	mov    $0xe,%edx
  401110:	be 00 00 00 00       	mov    $0x0,%esi
  401115:	8b 3c 24             	mov    (%rsp),%edi
  401118:	e8 85 ff ff ff       	callq  4010a2 <func4>

栈顶处的值必须<=e,然后%rdi存栈顶值,%rsi置0,%rdx为e。然后不慌着看func4,我们继续往后看phase_4:

  40111d:	83 f8 23             	cmp    $0x23,%eax
  401120:	75 07                	jne    401129 <phase_4+0x54>
  401122:	83 7c 24 04 23       	cmpl   $0x23,0x4(%rsp) //返回0x23
  401127:	74 05                	je     40112e <phase_4+0x59>
  401129:	e8 d7 03 00 00       	callq  401505 <explode_bomb>
  40112e:	48 8b 44 24 08       	mov    0x8(%rsp),%rax

说明func4的返回值必须为0x23,否则会引爆炸弹,并且栈顶+4处的值也应该为0x23,猜想(%rsp)栈顶处存x1的值,0x4(%rsp)处存x2=0x23(十进制为35),然后我们带着要使func4的返回值为0x23的目的进入func4,x1为第一个参数。

00000000004010a2 <func4>:
  4010a2:	53                   	push   %rbx
  4010a3:	89 d0                	mov    %edx,%eax
  4010a5:	29 f0                	sub    %esi,%eax
  4010a7:	89 c3                	mov    %eax,%ebx
  4010a9:	c1 eb 1f             	shr    $0x1f,%ebx //向0舍入除法
  4010ac:	01 d8                	add    %ebx,%eax
  4010ae:	d1 f8                	sar    %eax
  4010b0:	8d 1c 30             	lea    (%rax,%rsi,1),%ebx
  4010b3:	39 fb                	cmp    %edi,%ebx //x1与某值比较
  4010b5:	7e 0c                	jle    4010c3 <func4+0x21> //x1>=这个值
  4010b7:	8d 53 ff             	lea    -0x1(%rbx),%edx   //小于时         
  4010ba:	e8 e3 ff ff ff       	callq  4010a2 <func4>
  4010bf:	01 d8                	add    %ebx,%eax
  4010c1:	eb 10                	jmp    4010d3 <func4+0x31>
  4010c3:	89 d8                	mov    %ebx,%eax
  4010c5:	39 fb                	cmp    %edi,%ebx 
  4010c7:	7d 0a                	jge    4010d3 <func4+0x31>
  4010c9:	8d 73 01             	lea    0x1(%rbx),%esi
  4010cc:	e8 d1 ff ff ff       	callq  4010a2 <func4>
  4010d1:	01 d8                	add    %ebx,%eax
  4010d3:	5b                   	pop    %rbx
  4010d4:	c3                   	retq   

前面的代码是给%rbx一个值,并与x1进行比较,可以直接info r查看值,也可以自己算一下,差不多就是(%rdx-%rsi)/2向0 舍入。第一次:%rbx=7

  4010b3:	39 fb                	cmp    %edi,%ebx //x1与某值比较
  4010b5:	7e 0c                	jle    4010c3 <func4+0x21> //x1>=这个值
  4010b7:	8d 53 ff             	lea    -0x1(%rbx),%edx   //小于时         
  4010ba:	e8 e3 ff ff ff       	callq  4010a2 <func4>

当x1>=7时,跳到0x4010c3,否则将%rbx的值减1后给第三个参数寄存器,又进入func4,这里提示,func4又调用func4,说明应该是一个递归,那我们的关键是找到出口。先不管上一次递归,我们看当x1>=7时,跳转到0x4010c3:

  4010c3:	89 d8                	mov    %ebx,%eax
  4010c5:	39 fb                	cmp    %edi,%ebx
  4010c7:	7d 0a                	jge    4010d3 <func4+0x31>
  4010c9:	8d 73 01             	lea    0x1(%rbx),%esi
  4010cc:	e8 d1 ff ff ff       	callq  4010a2 <func4>

又比较x1和7的值,如果x1<=7,就不做递归,否则还是要将%rbx的值加1后继续call func4。跳转到0x4010c3的条件是x1>=7,然后递归结束的条件是x1<=7,因此结束递归的条件应该为x1=7(第一次操作为7,通用是x1=%rbx为递归结束条件)。
假设在这里我们就跳出循环,那么返回值为7,不满足0x23。所以还是需要做递归,每次call cunc4后,会有add %ebx,%eax
我们写一下,并且画一张图,就一目了然了。
在这里插入图片描述

答案 :8 35

phase_5

0000000000401148 <phase_5>:
  401148:	48 83 ec 18          	sub    $0x18,%rsp
  40114c:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  401153:	00 00 
  401155:	48 89 44 24 08       	mov    %rax,0x8(%rsp)
  40115a:	31 c0                	xor    %eax,%eax
  40115c:	48 8d 4c 24 04       	lea    0x4(%rsp),%rcx
  401161:	48 89 e2             	mov    %rsp,%rdx
  401164:	be 77 26 40 00       	mov    $0x402677,%esi
  401169:	e8 72 fa ff ff       	callq  400be0 <__isoc99_sscanf@plt>
  40116e:	83 f8 01             	cmp    $0x1,%eax //输入的个数大于1
  401171:	7f 05                	jg     401178 <phase_5+0x30>
  401173:	e8 8d 03 00 00       	callq  401505 <explode_bomb>
  401178:	8b 04 24             	mov    (%rsp),%eax
  40117b:	83 e0 0f             	and    $0xf,%eax //取后四位
  40117e:	89 04 24             	mov    %eax,(%rsp)
  401181:	83 f8 0f             	cmp    $0xf,%eax
  401184:	74 2f                	je     4011b5 <phase_5+0x6d>0 //后四位不为f
  401186:	b9 00 00 00 00       	mov    $0x0,%ecx
  40118b:	ba 00 00 00 00       	mov    $0x0,%edx
  401190:	83 c2 01             	add    $0x1,%edx
  401193:	48 98                	cltq   
  401195:	8b 04 85 00 25 40 00 	mov    0x402500(,%rax,4),%eax
  40119c:	01 c1                	add    %eax,%ecx
  40119e:	83 f8 0f             	cmp    $0xf,%eax
  4011a1:	75 ed                	jne    401190 <phase_5+0x48>
  4011a3:	c7 04 24 0f 00 00 00 	movl   $0xf,(%rsp)
  4011aa:	83 fa 0f             	cmp    $0xf,%edx //等于15
  4011ad:	75 06                	jne    4011b5 <phase_5+0x6d>
  4011af:	3b 4c 24 04          	cmp    0x4(%rsp),%ecx
  4011b3:	74 05                	je     4011ba <phase_5+0x72>
  4011b5:	e8 4b 03 00 00       	callq  401505 <explode_bomb>
  4011ba:	48 8b 44 24 08       	mov    0x8(%rsp),%rax
  4011bf:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4011c6:	00 00 
  4011c8:	74 05                	je     4011cf <phase_5+0x87>
  4011ca:	e8 51 f9 ff ff       	callq  400b20 <__stack_chk_fail@plt>
  4011cf:	48 83 c4 18          	add    $0x18,%rsp
  4011d3:	c3                   	retq   

查看0x402677处的东西:(和phase_4相同)输入“%d %d”。但是后面的比较语句看来,输入个数只需大于1就可,不一定是两个。
同样0x4(%rsp)存x2,(%rsp)存x1。

  401178:	8b 04 24             	mov    (%rsp),%eax
  40117b:	83 e0 0f             	and    $0xf,%eax //取后四位
  40117e:	89 04 24             	mov    %eax,(%rsp)
  401181:	83 f8 0f             	cmp    $0xf,%eax
  401184:	74 2f                	je     4011b5 <phase_5+0x6d>0 //后四位不为f

这段说明,x1的后四位不是0xf,否则会引爆。

  401190:	83 c2 01             	add    $0x1,%edx
  401193:	48 98                	cltq   
  401195:	8b 04 85 00 25 40 00 	mov    0x402500(,%rax,4),%eax
  40119c:	01 c1                	add    %eax,%ecx
  40119e:	83 f8 0f             	cmp    $0xf,%eax
  4011a1:	75 ed                	jne    401190 <phase_5+0x48>

上面这段,开始循环,一开始%eax保存的是x1的后四位,然后取0x402500(,%rax,4)处的值给%rax,直到%rax的值为0xf,并且%rdx每次会加1,%rcx每次会累加%rax的值。%rax一开始可能是0x0-0xe中任意一个数,查看这15个数。

(gdb) x /16d 0x402500
0x402500 <array.3600>:  10      2       14      7
0x402510 <array.3600+16>:       8       12      15      11
0x402520 <array.3600+32>:       0       4       1       13
0x402530 <array.3600+48>:       3       9       6       5

是一个数组:10 2 14 7 8 12 15 11 0 4 1 13 3 9 6 (5)。

  4011a3:	c7 04 24 0f 00 00 00 	movl   $0xf,(%rsp)
  4011aa:	83 fa 0f             	cmp    $0xf,%edx //等于15
  4011ad:	75 06                	jne    4011b5 <phase_5+0x6d>
  4011af:	3b 4c 24 04          	cmp    0x4(%rsp),%ecx
  4011b3:	74 05                	je     4011ba <phase_5+0x72>

%rdx=15说明上面的循环做了15次,也就是说%rcx是这个数组15个整数的和,它等于我们要输入的x2也就是0x4(%rsp)。而关键在于这一句

401195:	8b 04 85 00 25 40 00 	mov    0x402500(,%rax,4),%eax

怎样让最后一次%rax=15,并且寻址了15次,用数组下标来看,就是说每次i=a[i],15的下标为6,找到6的下标为14,这样推下去:15->6->14->2->10->0->8->4->9->13->11->7->3->12->5 ->15会指回15。那我们一开始输入的是5。
答案 :5 115

phase_6

其实做到这里已经掌握一些套路了,也越做越顺,phase_6给我的感觉就是非常绕,非常多的跳转,然后我后面把代码分成一段一段看,做好标记,就好很多。就像下面这样:

00000000004011d4 <phase_6>:
  4011d4:	41 55                	push   %r13
  4011d6:	41 54                	push   %r12
  4011d8:	55                   	push   %rbp
  4011d9:	53                   	push   %rbx
  4011da:	48 83 ec 68          	sub    $0x68,%rsp
  4011de:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  4011e5:	00 00 
  4011e7:	48 89 44 24 58       	mov    %rax,0x58(%rsp)
  4011ec:	31 c0                	xor    %eax,%eax
  4011ee:	48 89 e6             	mov    %rsp,%rsi
  4011f1:	e8 31 03 00 00       	callq  401527 <read_six_numbers>
  4011f6:	49 89 e4             	mov    %rsp,%r12 
  4011f9:	41 bd 00 00 00 00    	mov    $0x0,%r13d
  ①六个数小于等于6
  4011ff:	4c 89 e5             	mov    %r12,%rbp
  401202:	41 8b 04 24          	mov    (%r12),%eax
  401206:	83 e8 01             	sub    $0x1,%eax
  401209:	83 f8 05             	cmp    $0x5,%eax //x1<=6
  40120c:	76 05                	jbe    401213 <phase_6+0x3f>
  40120e:	e8 f2 02 00 00       	callq  401505 <explode_bomb>
  401213:	41 83 c5 01          	add    $0x1,%r13d
  401217:	41 83 fd 06          	cmp    $0x6,%r13d //第一步
  40121b:	74 3d                	je     40125a <phase_6+0x86>
  ②且每个数不相等6
  40121d:	44 89 eb             	mov    %r13d,%ebx
  401220:	48 63 c3             	movslq %ebx,%rax
  401223:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  401226:	39 45 00             	cmp    %eax,0x0(%rbp)
  401229:	75 05                	jne    401230 <phase_6+0x5c>
  40122b:	e8 d5 02 00 00       	callq  401505 <explode_bomb>
  401230:	83 c3 01             	add    $0x1,%ebx
  401233:	83 fb 05             	cmp    $0x5,%ebx
  401236:	7e e8                	jle    401220 <phase_6+0x4c>//每个数不相等
  401238:	49 83 c4 04          	add    $0x4,%r12
  40123c:	eb c1                	jmp    4011ff <phase_6+0x2b>
  ④当x的值>1时,
  40123e:	48 8b 52 08          	mov    0x8(%rdx),%rdx
  401242:	83 c0 01             	add    $0x1,%eax  //count+1
  401245:	39 c8                	cmp    %ecx,%eax  //count加到和x相等为止
  401247:	75 f5                	jne    40123e <phase_6+0x6a>
  x<=1 || 从上面进入 将每个node中的数依次填入栈中,顺序按照输入的值给出。
  401249:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)
  40124e:	48 83 c6 04          	add    $0x4,%rsi
  401252:	48 83 fe 18          	cmp    $0x18,%rsi  //加到%rsi=24
  401256:	75 07                	jne    40125f <phase_6+0x8b>
  401258:	eb 19                	jmp    401273 <phase_6+0x9f> //跳出40125a:	be 00 00 00 00       	mov    $0x0,%esi
  40125f:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx
  401262:	b8 01 00 00 00       	mov    $0x1,%eax    //count=1
  401267:	ba f0 42 60 00       	mov    $0x6042f0,%edx   //指针node1
  40126c:	83 f9 01             	cmp    $0x1,%ecx
  40126f:	7f cd                	jg     40123e <phase_6+0x6a>
  401271:	eb d6                	jmp    401249 <phase_6+0x75>
  ⑤新创建链表
  401273:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx
  401278:	48 8d 44 24 20       	lea    0x20(%rsp),%rax
  40127d:	48 8d 74 24 48       	lea    0x48(%rsp),%rsi
  401282:	48 89 d9             	mov    %rbx,%rcx
  401285:	48 8b 50 08          	mov    0x8(%rax),%rdx
  401289:	48 89 51 08          	mov    %rdx,0x8(%rcx)
  40128d:	48 83 c0 08          	add    $0x8,%rax
  401291:	48 89 d1             	mov    %rdx,%rcx
  401294:	48 39 f0             	cmp    %rsi,%rax
  401297:	75 ec                	jne    401285 <phase_6+0xb1>
  401299:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)
  4012a0:	00  
  ⑥从大到小
  4012a1:	bd 05 00 00 00       	mov    $0x5,%ebp
  4012a6:	48 8b 43 08          	mov    0x8(%rbx),%rax
  4012aa:	8b 00                	mov    (%rax),%eax
  *4012ac:	39 03                	cmp    %eax,(%rbx)
  4012ae:	7d 05                	jge    4012b5 <phase_6+0xe1>
  4012b0:	e8 50 02 00 00       	callq  401505 <explode_bomb>
  4012b5:	48 8b 5b 08          	mov    0x8(%rbx),%rbx
  4012b9:	83 ed 01             	sub    $0x1,%ebp
  4012bc:	75 e8                	jne    4012a6 <phase_6+0xd2>
  4012be:	48 8b 44 24 58       	mov    0x58(%rsp),%rax
  4012c3:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4012ca:	00 00 
  4012cc:	74 05                	je     4012d3 <phase_6+0xff>
  4012ce:	e8 4d f8 ff ff       	callq  400b20 <__stack_chk_fail@plt>
  4012d3:	48 83 c4 68          	add    $0x68,%rsp
  4012d7:	5b                   	pop    %rbx
  4012d8:	5d                   	pop    %rbp
  4012d9:	41 5c                	pop    %r12
  4012db:	41 5d                	pop    %r13
  4012dd:	c3                   	retq   

解题过程标在代码中了,具体来说就是考察链表与指针,一开始题目给了一个链表,然后会根据我们给的0-6的顺序,将这些结点的值存入栈中,顺序是从大到小,最初链表如下:

(gdb) x/24wx 0x6042f0
0x6042f0 <node1>:       0x000000f1      0x00000001      0x00604300      0x00000000
0x604300 <node2>:       0x0000038f      0x00000002      0x00604310      0x00000000
0x604310 <node3>:       0x00000075      0x00000003      0x00604320      0x00000000
0x604320 <node4>:       0x00000123      0x00000004      0x00604330      0x00000000
0x604330 <node5>:       0x00000297      0x00000005      0x00604340      0x00000000
0x604340 <node6>:       0x00000399      0x00000006      0x00000000      0x00000000

从大到小,答案 :6 2 5 4 1 3

secret_phase

听同学说才知道还有一个,做完好几天了,也忘记之前干了啥。
然后又重新看,这个炸弹在phase_defused里面

  4016a0:	83 3d e5 30 20 00 06 	cmpl   $0x6,0x2030e5(%rip)        # 60478c <num_input_strings>
  4016a7:	75 5e                	jne    401707 <phase_defused+0x7b>

在phase_defused处打断点,每通过一个炸弹,0x2030e5(%rip)的值会加1,直到通过6个炸弹。

 4016b8:	be c1 26 40 00       	mov    $0x4026c1,%esi
  4016bd:	bf 90 48 60 00       	mov    $0x604890,%edi

这两句,查看一下这两个地址

(gdb) x /s 0x604890
0x604890 <input_strings+240>:   "8 35"
(gdb) x /s 0x4026c1
0x4026c1:       "%d %d %s"

8 35是我们在第4关输入的,要在后面加一个字符串才能触发secret_phase。

  4016cc:	be ca 26 40 00       	mov    $0x4026ca,%esi
(gdb) x /s 0x4026ca
0x4026ca:       "DrEvil"

要在后面输入的是DrEvil。进入secret_phase:

000000000040131c <secret_phase>:
  40131c:	53                   	push   %rbx
  40131d:	e8 44 02 00 00       	callq  401566 <read_line>
  401322:	ba 0a 00 00 00       	mov    $0xa,%edx
  401327:	be 00 00 00 00       	mov    $0x0,%esi
  40132c:	48 89 c7             	mov    %rax,%rdi
  40132f:	e8 8c f8 ff ff       	callq  400bc0 <strtol@plt>
  401334:	48 89 c3             	mov    %rax,%rbx
  401337:	8d 40 ff             	lea    -0x1(%rax),%eax
  40133a:	3d e8 03 00 00       	cmp    $0x3e8,%eax  //<=0x3e9
  40133f:	76 05                	jbe    401346 <secret_phase+0x2a>
  401341:	e8 bf 01 00 00       	callq  401505 <explode_bomb>
  401346:	89 de                	mov    %ebx,%esi
  401348:	bf 10 41 60 00       	mov    $0x604110,%edi
  40134d:	e8 8c ff ff ff       	callq  4012de <fun7>
  401352:	83 f8 03             	cmp    $0x3,%eax  //返回值为3
  401355:	74 05                	je     40135c <secret_phase+0x40>
  401357:	e8 a9 01 00 00       	callq  401505 <explode_bomb>
  40135c:	bf 40 25 40 00       	mov    $0x402540,%edi
  401361:	e8 9a f7 ff ff       	callq  400b00 <puts@plt>
  401366:	e8 21 03 00 00       	callq  40168c <phase_defused>
  40136b:	5b                   	pop    %rbx
  40136c:	c3                   	retq   

把输入变成一个十进制整数(查一下strtol函数,第三个参数为0xa,所以转换为10进制),这个数不大于0x3e9(1001),然后设置了%rsi=x(输入的数),%rdi=0x604110,应该是一个结构体?(反正就是包含有一个整数值,两个指针n1、n2),进入fun7。(注意还是先看返回值,返回值是3,带着答案去看。)
fun7也是一个递归,不同条件,下一次递归的参数不同。

00000000004012de <fun7>:
  4012de:	48 83 ec 08          	sub    $0x8,%rsp
  4012e2:	48 85 ff             	test   %rdi,%rdi  //不为0
  4012e5:	74 2b                	je     401312 <fun7+0x34>
  4012e7:	8b 17                	mov    (%rdi),%edx  //24
  4012e9:	39 f2                	cmp    %esi,%edx  
  4012eb:	7e 0d                	jle    4012fa <fun7+0x1c>
  4012ed:	48 8b 7f 08          	mov    0x8(%rdi),%rdi
  4012f1:	e8 e8 ff ff ff       	callq  4012de <fun7> //递归
  4012f6:	01 c0                	add    %eax,%eax
  4012f8:	eb 1d                	jmp    401317 <fun7+0x39>

  4012fa:	b8 00 00 00 00       	mov    $0x0,%eax
  4012ff:	39 f2                	cmp    %esi,%edx
  401301:	74 14                	je     401317 <fun7+0x39>
  401303:	48 8b 7f 10          	mov    0x10(%rdi),%rdi
  401307:	e8 d2 ff ff ff       	callq  4012de <fun7>
  40130c:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401310:	eb 05                	jmp    401317 <fun7+0x39>

  401312:	b8 ff ff ff ff       	mov    $0xffffffff,%eax
  401317:	48 83 c4 08          	add    $0x8,%rsp
  40131b:	c3                   	retq 

条件是当这个结构的值d等于x的时候,返回0,如果d<x,a置0,调用fun7(n2)并且a=2a+1;如果d>x,调用fun7(n1),并且a=2a。因为我们要a=3,所以只能是a=20+1=1,a=21+1=3,都进入d<x这一边,调了两次,如下:

(gdb) x /60wx 0x0604110
0x604110 <n1>:  0x00000024      0x00000000      0x00604130      0x00000000
0x604120 <n1+16>:       0x00604150      0x00000000      0x00000000      0x00000000
0x604130 <n21>: 0x00000008      0x00000000      0x006041b0      0x00000000
0x604140 <n21+16>:      0x00604170      0x00000000      0x00000000      0x00000000
0x604150 <n22>: 0x00000032      0x00000000      0x00604190      0x00000000
0x604160 <n22+16>:      0x006041d0      0x00000000      0x00000000      0x00000000
0x604170 <n32>: 0x00000016      0x00000000      0x00604290      0x00000000
0x604180 <n32+16>:      0x00604250      0x00000000      0x00000000      0x00000000
0x604190 <n33>: 0x0000002d      0x00000000      0x006041f0      0x00000000
0x6041a0 <n33+16>:      0x006042b0      0x00000000      0x00000000      0x00000000
0x6041b0 <n31>: 0x00000006      0x00000000      0x00604210      0x00000000
0x6041c0 <n31+16>:      0x00604270      0x00000000      0x00000000      0x00000000
0x6041d0 <n34>: 0x0000006b      0x00000000      0x00604230      0x00000000
0x6041e0 <n34+16>:      0x006042d0      0x00000000      0x00000000      0x00000000
0x6041f0 <n45>: 0x00000028      0x00000000      0x00000000      0x00000000
0x604200 <n45+16>:      0x00000000      0x00000000      0x00000000      0x00000000

开始时0x604110第一次0x604150第二次0x6041d0,*0x6041d0值为0x6b,转换成十进制为107。
答案 :107

!!!!后我们做一次总的输入输出,终于解完啦!!BOOM!!

 Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Public speaking is very easy.
Phase 1 defused. How about the next one?
0 1 1 2 3 5
That's number 2.  Keep going!
0 w 913
Halfway there!
8 35 DrEvil
So you got that one.  Try this one.
5 115
Good work!  On to the next...
6 2 5 4 1 3
Curses, you've found the secret phase!
But finding it and solving it are quite different...
Continuing.
107
Wow! You've defused the secret stage!
Congratulations! You've defused the bomb!

呼~~下个实验见。
本科小白!若有错误请指正!

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
malloclab是CSAPP(Computer Systems: A Programmer's Perspective)教材中的一个实验项目,旨在帮助学生了解内存管理和动态内存分配的细节。 实验的主要任务是实现一个简单的动态内存分配器。这个内存分配器需要提供malloc、free和realloc函数的功能,来动态管理内存。实验中提供了一个基本的代码框架,学生需要在这个框架上完成具体的实现。 整个实验可以分为三个部分:分配器的初始化、分配和释放内存的处理。 在初始化部分,学生需要定义一个初始的堆,为其分配一块内存,并根据实验要求设置好堆的初始状态。 在分配内存的部分,学生需要实现malloc函数。这个函数接收一个参数(需要分配的字节数)并返回指向分配内存的指针。学生需要根据实验要求分配内存,并保证分配的内存块满足对齐和避免碎片化的要求。 在释放内存的部分,学生需要实现free函数。这个函数接收一个参数(指向待释放内存块的指针)并将该内存块标记为可用。学生需要根据实验要求处理不同的情况,比如释放合并相邻的空闲块。 此外,实验还有一些额外的要求,如实现realloc函数,处理内存使用情况的统计等。 通过完成malloclab实验,学生可以深入了解内存管理和动态内存分配的工作原理。这个实验还提供了一个实践机会,让学生亲自动手实现一个简单的内存分配器,从而更好地理解和掌握相关的概念和技术。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值