【csapp lab】lab2_bomblab

文章目录

    • 前言
    • 实验内容
      • phase_1
      • phase_2
      • phase_3
      • phase_4
      • phase_5
      • phase_6
      • secret_phase

前言

刚做了csapp lab2,记录一下。

我这里用的的系统环境是Ubuntu22.04,是64位系统,与用32位系统可能有所差异。

实验共包括七个阶段,每个阶段考察机器级语言程序的不同方面,难度递增

  • 阶段一:字符串比较
  • 阶段二:循环
  • 阶段三:条件/分支,含switch语句
  • 阶段四:递归调用和栈
  • 阶段五:指针
  • 阶段六:链表/指针/结构
  • 隐藏阶段:第四阶段之后附加特定字符串后出现

在实验过程中gdb调试起到了相当重要的作用,下面是我调试过程中频繁使用的几条指令,不熟悉gdb的小伙伴一定要熟悉一下:

  • r ans.txt - 开始运行,ans.txt为命令行参数,可以省略

  • c - 运行至下一个断点处

  • b \*addr - 在addr处的指令打断点

  • d num - 删除断点num

  • display /x %reg - 每次执行完指令时打印寄存器rgx的值

  • undisplay num - 删除监视变量num

  • ni - 执行下一条指令

  • x/nws addr - x是examine,表示进行内存检查;n表示显示n个数据项;w表示以8个字节为单位进行显示;s是以字符串的形式显示解释,可以替换成x,以十六进制的形式进行解释,可以替换成u,以十进制的形式进行解释

为了方便,我们创建一个ans.txt文件,每做出来一题就把答案写进去,这样就避免了一条一条输入答案。一题占一行,要注意最后要多一个空行,目的是最后一题的输入以 换行符结尾,保证是正确输入:

image-20231119105551853

实验内容

phase_1

找到 phase_1 函数在 main 函数中被调用的位置:

 8048a6d:	c7 04 24 70 a0 04 08 	movl   $0x804a070,(%esp)8048a74:	e8 47 fd ff ff       	call   80487c0 <puts@plt>8048a79:	e8 69 07 00 00       	call   80491e7 <read_line>8048a7e:	89 04 24             	mov    %eax,(%esp)8048a81:	e8 aa 00 00 00       	call   8048b30 <phase_1>8048a86:	e8 5f 08 00 00       	call   80492ea <phase_defused>

在反汇编文件中继续查找 phase_1 的位置:

08048b30 <phase_1>:8048b30:	55                  	push   %ebp8048b31:	89 e5                	mov    %esp,%ebp8048b33:	83 ec 10             	sub    $0x10,%esp8048b36:	68 ec a0 04 08       	push   $0x804a0ec8048b3b:	ff 75 08             	push   0x8(%ebp)8048b3e:	e8 3f 05 00 00       	call   8049082 <strings_not_equal>8048b43:	83 c4 10             	add    $0x10,%esp8048b46:	85 c0                	test   %eax,%eax8048b48:	74 05                	je     8048b4f <phase_1+0x1f>8048b4a:	e8 36 06 00 00        	call   8049185 <explode_bomb>8048b4f:	c9                  	leave  8048b50:	c3                  	ret    

$0x804a0ec: 数据区地址,也是 strings_not_equal 的第二个参数

0x8(%ebp): phase_1 的参数,也是 strings_not_equal 的第一个参数

main()函数的汇编代码中,可以进一步找到:

 8048a79:	e8 69 07 00 00       	call   80491e7 <read_line>8048a7e:	89 04 24             	mov    %eax,(%esp)

%eax 里存储的是调用 read_line 函数的返回值,也是用户输入的字符串首地址

推测拆弹密码字符串的存储地址为 $0x804a0ec,因为调用 strings_not_equal前有语句:

8048b36: 68 ec a0 04 08 push $0x804a0ec

执行 gdb bomb 找到答案When a problem comes along, you must zip it!

image-20231119023040251

phase_2

查看phase_2的代码:

08048b51 <phase_2>:8048b51:	55                   	push   %ebp8048b52:	89 e5                	mov    %esp,%ebp8048b54:	53                   	push   %ebx8048b55:	83 ec 2c             	sub    $0x2c,%esp8048b58:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax8048b5e:	89 45 f4             	mov    %eax,-0xc(%ebp)8048b61:	31 c0                	xor    %eax,%eax8048b63:	8d 45 dc             	lea    -0x24(%ebp),%eax8048b66:	50                   	push   %eax8048b67:	ff 75 08             	push   0x8(%ebp)8048b6a:	e8 3e 06 00 00       	call   80491ad <read_six_numbers>8048b6f:	83 c4 10             	add    $0x10,%esp8048b72:	83 7d dc 00          	cmpl   $0x0,-0x24(%ebp)8048b76:	79 05                	jns    8048b7d <phase_2+0x2c>8048b78:	e8 08 06 00 00       	call   8049185 <explode_bomb>8048b7d:	bb 01 00 00 00       	mov    $0x1,%ebx			  8048b82:	89 d8                	mov    %ebx,%eax			 8048b84:	03 44 9d d8          	add    -0x28(%ebp,%ebx,4),%eax8048b88:	39 44 9d dc          	cmp    %eax,-0x24(%ebp,%ebx,4)8048b8c:	74 05                	je     8048b93 <phase_2+0x42>8048b8e:	e8 f2 05 00 00       	call   8049185 <explode_bomb>8048b93:	83 c3 01             	add    $0x1,%ebx8048b96:	83 fb 06             	cmp    $0x6,%ebx8048b99:	75 e7                	jne    8048b82 <phase_2+0x31>8048b9b:	8b 45 f4             	mov    -0xc(%ebp),%eax8048b9e:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax8048ba5:	74 05                	je     8048bac <phase_2+0x5b>8048ba7:	e8 e4 fb ff ff       	call   8048790 <__stack_chk_fail@plt>8048bac:	8b 5d fc             	mov    -0x4(%ebp),%ebx8048baf:	c9                   	leave  8048bb0:	c3                   	ret  

关注到8048b6a: e8 3e 06 00 00 call 80491ad <read_six_numbers>,这题应该是要输入六个数字。

观察这部分汇编代码:

 8048b7d:	bb 01 00 00 00       	mov    $0x1,%ebx			  8048b82:	89 d8                	mov    %ebx,%eax			 8048b84:	03 44 9d d8          	add    -0x28(%ebp,%ebx,4),%eax8048b88:	39 44 9d dc          	cmp    %eax,-0x24(%ebp,%ebx,4)8048b8c:	74 05                	je     8048b93 <phase_2+0x42>8048b8e:	e8 f2 05 00 00       	call   8049185 <explode_bomb>8048b93:	83 c3 01             	add    $0x1,%ebx8048b96:	83 fb 06             	cmp    $0x6,%ebx8048b99:	75 e7                	jne    8048b82 <phase_2+0x31>

可以看出这就是一段循环,循环次数为5,每次循环是做一次比较,%ebx是循环计数器,每轮循环结束后 +1。循环内会进行一次比较,如果两个数不相等就会爆炸。那么关键就是待比较的两个数。

ebx比较数1比较数2
11 + ebp-0x28+1*4ebp-0x24+1*4
22 + ebp-0x28+2*4ebp-0x24+2*4
33 + ebp-0x28+3*4ebp-0x24+3*4
44 + ebp-0x28+4*4ebp-0x24+4*4
55 + ebp-0x28+5*4ebp-0x24+5*4

经过观察和不断地调试发现比较数1是第一个输入的数+ebx,比较数2是第二个输入的数。

经过大量试错调试,最终得出这一题的答案:输入六个数,每两个数之间的差依次为1/2/3/4/5

所以这样得到本题的一组答案:1 2 4 7 11 16,当然答案不唯一,比如符合条件的2 3 5 8 12 17也是可以通 过的。

部分调试记录截图:

image-20231119023438558

image-20231119023442324

这题后面的比较循环一开始看到以6结尾,想当然地认为循环比较六次,这样就多出来一个输入的数,百思不得其解,在网上查阅相关教程发现题目也不一样。最终就逐步调试,发现只是循环了5次,这样就对上了。在调试过程中也找到了本题的答案。

phase_3

先把phase_3的代码贴出来:

08048bb1 <phase_3>:8048bb1:	55                   	push   %ebp8048bb2:	89 e5                	mov    %esp,%ebp8048bb4:	83 ec 24             	sub    $0x24,%esp8048bb7:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax8048bbd:	89 45 f4             	mov    %eax,-0xc(%ebp)8048bc0:	31 c0                	xor    %eax,%eax8048bc2:	8d 45 f0             	lea    -0x10(%ebp),%eax8048bc5:	50                   	push   %eax8048bc6:	8d 45 eb             	lea    -0x15(%ebp),%eax8048bc9:	50                   	push   %eax8048bca:	8d 45 ec             	lea    -0x14(%ebp),%eax8048bcd:	50                   	push   %eax8048bce:	68 42 a1 04 08       	push   $0x804a1428048bd3:	ff 75 08             	push   0x8(%ebp)8048bd6:	e8 35 fc ff ff       	call   8048810 <__isoc99_sscanf@plt>8048bdb:	83 c4 20             	add    $0x20,%esp8048bde:	83 f8 02             	cmp    $0x2,%eax8048be1:	7f 05                	jg     8048be8 <phase_3+0x37>8048be3:	e8 9d 05 00 00       	call   8049185 <explode_bomb>8048be8:	83 7d ec 07          	cmpl   $0x7,-0x14(%ebp)8048bec:	0f 87 ef 00 00 00    	ja     8048ce1 <phase_3+0x130>8048bf2:	8b 45 ec             	mov    -0x14(%ebp),%eax8048bf5:	ff 24 85 54 a1 04 08 	jmp    *0x804a154(,%eax,4)8048bfc:	b8 78 00 00 00       	mov    $0x78,%eax8048c01:	81 7d f0 44 01 00 00 	cmpl   $0x144,-0x10(%ebp)8048c08:	0f 84 dd 00 00 00    	je     8048ceb <phase_3+0x13a>8048c0e:	e8 72 05 00 00       	call   8049185 <explode_bomb>8048c13:	b8 78 00 00 00       	mov    $0x78,%eax8048c18:	e9 ce 00 00 00       	jmp    8048ceb <phase_3+0x13a>8048c1d:	b8 69 00 00 00       	mov    $0x69,%eax8048c22:	81 7d f0 99 01 00 00 	cmpl   $0x199,-0x10(%ebp)8048c29:	0f 84 bc 00 00 00    	je     8048ceb <phase_3+0x13a>8048c2f:	e8 51 05 00 00       	call   8049185 <explode_bomb>8048c34:	b8 69 00 00 00       	mov    $0x69,%eax8048c39:	e9 ad 00 00 00       	jmp    8048ceb <phase_3+0x13a>8048c3e:	b8 74 00 00 00       	mov    $0x74,%eax8048c43:	81 7d f0 f6 02 00 00 	cmpl   $0x2f6,-0x10(%ebp)8048c4a:	0f 84 9b 00 00 00    	je     8048ceb <phase_3+0x13a>8048c50:	e8 30 05 00 00       	call   8049185 <explode_bomb>8048c55:	b8 74 00 00 00       	mov    $0x74,%eax8048c5a:	e9 8c 00 00 00       	jmp    8048ceb <phase_3+0x13a>8048c5f:	b8 68 00 00 00       	mov    $0x68,%eax8048c64:	81 7d f0 37 02 00 00 	cmpl   $0x237,-0x10(%ebp)8048c6b:	74 7e                	je     8048ceb <phase_3+0x13a>8048c6d:	e8 13 05 00 00       	call   8049185 <explode_bomb>8048c72:	b8 68 00 00 00       	mov    $0x68,%eax8048c77:	eb 72                	jmp    8048ceb <phase_3+0x13a>8048c79:	b8 79 00 00 00       	mov    $0x79,%eax8048c7e:	81 7d f0 1c 03 00 00 	cmpl   $0x31c,-0x10(%ebp)8048c85:	74 64                	je     8048ceb <phase_3+0x13a>8048c87:	e8 f9 04 00 00       	call   8049185 <explode_bomb>8048c8c:	b8 79 00 00 00       	mov    $0x79,%eax8048c91:	eb 58                	jmp    8048ceb <phase_3+0x13a>8048c93:	b8 62 00 00 00       	mov    $0x62,%eax8048c98:	81 7d f0 bd 01 00 00 	cmpl   $0x1bd,-0x10(%ebp)8048c9f:	74 4a                	je     8048ceb <phase_3+0x13a>8048ca1:	e8 df 04 00 00       	call   8049185 <explode_bomb>8048ca6:	b8 62 00 00 00       	mov    $0x62,%eax8048cab:	eb 3e                	jmp    8048ceb <phase_3+0x13a>8048cad:	b8 64 00 00 00       	mov    $0x64,%eax8048cb2:	81 7d f0 5a 03 00 00 	cmpl   $0x35a,-0x10(%ebp)8048cb9:	74 30                	je     8048ceb <phase_3+0x13a>8048cbb:	e8 c5 04 00 00       	call   8049185 <explode_bomb>8048cc0:	b8 64 00 00 00       	mov    $0x64,%eax8048cc5:	eb 24                	jmp    8048ceb <phase_3+0x13a>8048cc7:	b8 65 00 00 00       	mov    $0x65,%eax8048ccc:	81 7d f0 50 02 00 00 	cmpl   $0x250,-0x10(%ebp)8048cd3:	74 16                	je     8048ceb <phase_3+0x13a>8048cd5:	e8 ab 04 00 00       	call   8049185 <explode_bomb>8048cda:	b8 65 00 00 00       	mov    $0x65,%eax8048cdf:	eb 0a                	jmp    8048ceb <phase_3+0x13a>8048ce1:	e8 9f 04 00 00       	call   8049185 <explode_bomb>8048ce6:	b8 6b 00 00 00       	mov    $0x6b,%eax8048ceb:	3a 45 eb             	cmp    -0x15(%ebp),%al8048cee:	74 05                	je     8048cf5 <phase_3+0x144>8048cf0:	e8 90 04 00 00       	call   8049185 <explode_bomb>8048cf5:	8b 45 f4             	mov    -0xc(%ebp),%eax8048cf8:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax8048cff:	74 05                	je     8048d06 <phase_3+0x155>8048d01:	e8 8a fa ff ff       	call   8048790 <__stack_chk_fail@plt>8048d06:	c9                   	leave  8048d07:	c3                   	ret    

首先观察到phase_3的代码中有一段:

 8048bce:	68 42 a1 04 08       	push   $0x804a1428048bd3:	ff 75 08             	push   0x8(%ebp)8048bd6:	e8 35 fc ff ff       	call   8048810 <__isoc99_sscanf@plt>

其中$0x804a142是输入格式字符串,这里要作为参数压栈,传递给sscanf,查看一下:

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

这题的输入就是两个整数中间用字符隔开。

紧接着的一段代码也印证了这一点:

 8048bdb:	83 c4 20             	add    $0x20,%esp8048bde:	83 f8 02             	cmp    $0x2,%eax8048be1:	7f 05                	jg     8048be8 <phase_3+0x37>8048be3:	e8 9d 05 00 00       	call   8049185 <explode_bomb>

eax也就是sscanf的返回值,也就是输入的变量的个数,如果小于等于2就bomb。

紧接着有一个判断:

 8048be8:	83 7d ec 07          	cmpl   $0x7,-0x14(%ebp)8048bec:	0f 87 ef 00 00 00    	ja     8048ce1 <phase_3+0x130>

如果-0x14(%ebp) > 0x7,就会跳转,这里会跳转到call <explode_bomb>,所以要求-0x14(%ebp) <= 7,那它是什么呢?观察调用sscanf之前的一段代码:

 8048bc2:	8d 45 f0             	lea    -0x10(%ebp),%eax8048bc5:	50                  	push   %eax8048bc6:	8d 45 eb             	lea    -0x15(%ebp),%eax8048bc9:	50                  	push   %eax8048bca:	8d 45 ec             	lea    -0x14(%ebp),%eax8048bcd:	50                  	push   %eax

根据参数传递的顺序应该是我们输入的第一个数,这也就要求我们输入的第一个数小于等于7。

继续往下看,发现程序会跳转,并且跳转的位置和我们输入的数相关联:

 8048bf2:	8b 45 ec             	mov    -0x14(%ebp),%eax8048bf5:	ff 24 85 54 a1 04 08 	jmp    *0x804a154(,%eax,4)

用第一个输入的数是1进行下一步调试:

image-20231119023945131

跳转到了:

 8048c1d:	b8 69 00 00 00       	mov    $0x69,%eax8048c22:	81 7d f0 99 01 00 00 	cmpl   $0x199,-0x10(%ebp)8048c29:	0f 84 bc 00 00 00    	je     8048ceb <phase_3+0x13a>8048c2f:	e8 51 05 00 00       	call   8049185 <explode_bomb>

继续看,这里把eax更新成了0x69,并且比较了我们的第三个输入,也就是第二个整数和0x199也就是409,所以确定了我们要输入的第二个数是409,接下来程序跳转到了8048ceb

 8048ceb:	3a 45 eb             	cmp    -0x15(%ebp),%al8048cee:	74 05                	je     8048cf5 <phase_3+0x144>8048cf0:	e8 90 04 00 00       	call   8049185 <explode_bomb>8048cf5:	8b 45 f4             	mov    -0xc(%ebp),%eax8048cf8:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax8048cff:	    74 05               je     8048d06 <phase_3+0x155>8048d01:	e8 8a fa ff ff       	call   8048790 <__stack_chk_fail@plt>8048d06:	c9                  	leave  8048d07:	c3                  	ret  

这里比较的是我们输入的字符和%al%al是累加器寄存器eax的低八位,如下图所示,转成十进制就是105,所以我们要输入的字符的ascii码值是105,也就是i。这样就得到了最终的答案1i409

image-20231119024053668

不过这道题应该有8个答案,因为输入的第一个整数有8个取值,所以会有八个分支,对应八个答案。

phase_4

先贴代码:

08048d08 <func4>:8048d08:	55                   	push   %ebp8048d09:	89 e5                	mov    %esp,%ebp8048d0b:	56                   	push   %esi8048d0c:	53                   	push   %ebx8048d0d:	8b 55 08             	mov    0x8(%ebp),%edx8048d10:	8b 4d 0c             	mov    0xc(%ebp),%ecx8048d13:	8b 75 10             	mov    0x10(%ebp),%esi8048d16:	89 f0                	mov    %esi,%eax8048d18:	29 c8                	sub    %ecx,%eax8048d1a:	89 c3                	mov    %eax,%ebx8048d1c:	c1 eb 1f             	shr    $0x1f,%ebx8048d1f:	01 d8                	add    %ebx,%eax8048d21:	d1 f8                	sar    %eax8048d23:	8d 1c 08             	lea    (%eax,%ecx,1),%ebx8048d26:	39 d3                	cmp    %edx,%ebx8048d28:	7e 15                	jle    8048d3f <func4+0x37>8048d2a:	83 ec 04             	sub    $0x4,%esp8048d2d:	8d 43 ff             	lea    -0x1(%ebx),%eax8048d30:	50                   	push   %eax8048d31:	51                   	push   %ecx8048d32:	52                   	push   %edx8048d33:	e8 d0 ff ff ff       	call   8048d08 <func4>8048d38:	83 c4 10             	add    $0x10,%esp8048d3b:	01 d8                	add    %ebx,%eax8048d3d:	eb 19                	jmp    8048d58 <func4+0x50>8048d3f:	89 d8                	mov    %ebx,%eax8048d41:	39 d3                	cmp    %edx,%ebx8048d43:	7d 13                	jge    8048d58 <func4+0x50>8048d45:	83 ec 04             	sub    $0x4,%esp8048d48:	56                   	push   %esi8048d49:	8d 43 01             	lea    0x1(%ebx),%eax8048d4c:	50                   	push   %eax8048d4d:	52                   	push   %edx8048d4e:	e8 b5 ff ff ff       	call   8048d08 <func4>8048d53:	83 c4 10             	add    $0x10,%esp8048d56:	01 d8                	add    %ebx,%eax8048d58:	8d 65 f8             	lea    -0x8(%ebp),%esp8048d5b:	5b                   	pop    %ebx8048d5c:	5e                   	pop    %esi8048d5d:	5d                   	pop    %ebp8048d5e:	c3                   	ret    08048d5f <phase_4>:8048d5f:	55                   	push   %ebp8048d60:	89 e5                	mov    %esp,%ebp8048d62:	83 ec 18             	sub    $0x18,%esp8048d65:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax8048d6b:	89 45 f4             	mov    %eax,-0xc(%ebp)8048d6e:	31 c0                	xor    %eax,%eax8048d70:	8d 45 f0             	lea    -0x10(%ebp),%eax8048d73:	50                   	push   %eax8048d74:	8d 45 ec             	lea    -0x14(%ebp),%eax8048d77:	50                   	push   %eax8048d78:	68 93 a2 04 08       	push   $0x804a2938048d7d:	ff 75 08             	push   0x8(%ebp)8048d80:	e8 8b fa ff ff       	call   8048810 <__isoc99_sscanf@plt>8048d85:	83 c4 10             	add    $0x10,%esp8048d88:	83 f8 02             	cmp    $0x2,%eax8048d8b:	75 06                	jne    8048d93 <phase_4+0x34>8048d8d:	83 7d ec 0e          	cmpl   $0xe,-0x14(%ebp)8048d91:	76 05                	jbe    8048d98 <phase_4+0x39>8048d93:	e8 ed 03 00 00       	call   8049185 <explode_bomb>8048d98:	83 ec 04             	sub    $0x4,%esp8048d9b:	6a 0e                	push   $0xe8048d9d:	6a 00                	push   $0x08048d9f:	ff 75 ec             	push   -0x14(%ebp)8048da2:	e8 61 ff ff ff       	call   8048d08 <func4>8048da7:	83 c4 10             	add    $0x10,%esp8048daa:	83 f8 13             	cmp    $0x13,%eax8048dad:	75 06                	jne    8048db5 <phase_4+0x56>8048daf:	83 7d f0 13          	cmpl   $0x13,-0x10(%ebp)8048db3:	74 05                	je     8048dba <phase_4+0x5b>8048db5:	e8 cb 03 00 00       	call   8049185 <explode_bomb>8048dba:	8b 45 f4             	mov    -0xc(%ebp),%eax8048dbd:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax8048dc4:	74 05                	je     8048dcb <phase_4+0x6c>8048dc6:	e8 c5 f9 ff ff       	call   8048790 <__stack_chk_fail@plt>8048dcb:	c9                   	leave  8048dcc:	c3                   	ret    

还是先观察调用sscanf之前的代码确定输入格式:

 8048d70:	8d 45 f0             	lea    -0x10(%ebp),%eax8048d73:	50                  	push   %eax8048d74:	8d 45 ec             	lea    -0x14(%ebp),%eax8048d77:	50                  	push   %eax8048d78:	68 93 a2 04 08       	push   $0x804a2938048d7d:	ff 75 08             	push   0x8(%ebp)8048d80:	e8 8b fa ff ff       	call   8048810 <__isoc99_sscanf@plt>8048d85:	83 c4 10             	add    $0x10,%esp8048d88:	83 f8 02             	cmp    $0x2,%eax8048d8b:	75 06                	jne    8048d93 <phase_4+0x34>

image-20231119024159720

输入格式是两个整数,中间用空格隔开。

其中第一个数存在-0x14(%ebp),第二个数存在-0x10(%ebp)

继续向下看:

 8048d8d:	83 7d ec 0e          	cmpl   $0xe,-0x14(%ebp)8048d91:	76 05                	jbe    8048d98 <phase_4+0x39>8048d93:	e8 ed 03 00 00       	call   8049185 <explode_bomb>

这里比较了输入的第一个数和0xe,也就是14,说明第一个数要小于等于14,这里还是用输入1来进一步调试。继续看代码:

 8048d98:	83 ec 04             	sub    $0x4,%esp8048d9b:	6a 0e                	push   $0xe8048d9d:	6a 00                	push   $0x08048d9f:	ff 75 ec             	push   -0x14(%ebp)8048da2:	e8 61 ff ff ff       	call   8048d08 <func4>

调用了func4,先分析一下参数:第一个参数是输入的第一个整数,第二个参数是 0,第三个参数是0xe也就是14。继续分析func4的代码,先看参数的处理:

 8048d0d:	8b 55 08             	mov    0x8(%ebp),%edx8048d10:	8b 4d 0c             	mov    0xc(%ebp),%ecx8048d13:	8b 75 10             	mov    0x10(%ebp),%esi

这里把第一个参数,也就是输入的第一个整数1赋给了edx,把0赋给了ecx14赋给了esi,继续看代码:

 8048d16:	89 f0                	mov    %esi,%eax8048d18:	29 c8                	sub    %ecx,%eax8048d1a:	89 c3                	mov    %eax,%ebx8048d1c:	c1 eb 1f             	shr    $0x1f,%ebx8048d1f:	01 d8                	add    %ebx,%eax8048d21:	d1 f8                	sar    %eax8048d23:	8d 1c 08             	lea    (%eax,%ecx,1),%ebx8048d26:	39 d3                	cmp    %edx,%ebx8048d28:	7e 15                	jle    8048d3f <func4+0x37>

一直执行到比较之前,各个寄存器存放的值如下:

img

接下来过不了比较,会继续向下执行:

 8048d2a:	83 ec 04             	sub    $0x4,%esp8048d2d:	8d 43 ff             	lea    -0x1(%ebx),%eax8048d30:	50                   	push   %eax8048d31:	51                   	push   %ecx8048d32:	52                   	push   %edx8048d33:	e8 d0 ff ff ff       	call   8048d08 <func4>

这样就开始了递归,先看一下此时递归前各个寄存器存放的值:

img

从左到右三个参数依次为1、0、1,与上一次调用相比第三个参数发生了变化,继续调试到比较:

img

此时仍无法结束递归,下面会进行第三次调用,调用前各个寄存器的值如下:

img

第三个参数变成了2,继续调试到比较:

img

此时终于符合条件ebx <= edx,跳转到新阶段:

 8048d3f:	89 d8               mov    %ebx,%eax8048d41:	39 d3               cmp    %edx,%ebx8048d43:	7d 13               jge    8048d58 <func4+0x50>

接下来有个判断,要求ebx >= edx,先看一下此时各个寄存器的值:

img

符合条件,跳转到新位置:

 8048d58:	8d 65 f8             	lea    -0x8(%ebp),%esp8048d5b:	5b                  	pop    %ebx8048d5c:	5e                  	pop    %esi8048d5d:	5d                  	pop    %ebp8048d5e:	c3                  	ret   

此时跳出第三次调用,来到第二次调用的栈帧:

 8048d33:	e8 d0 ff ff ff       	call   8048d08 <func4>8048d38:	83 c4 10             	add    $0x10,%esp8048d3b:	01 d8                	add    %ebx,%eax8048d3d:	eb 19                	jmp    8048d58 <func4+0x50>

跳转之前各个寄存器的值如下:

img

第二次调用随之也结束,来到第一次调用的栈帧,还是与第二次一样,返回phase_4之前eax变为11

之后回到phase_4的栈帧:

 8048da2:	e8 61 ff ff ff       	call   8048d08 <func4>8048da7:	83 c4 10             	add    $0x10,%esp8048daa:	83 f8 13             	cmp    $0x13,%eax8048dad:	75 06                	jne    8048db5 <phase_4+0x56>8048daf:	83 7d f0 13          	cmpl   $0x13,-0x10(%ebp)8048db3:	74 05                	je     8048dba <phase_4+0x5b>8048db5:	e8 cb 03 00 00       	call   8049185 <explode_bomb>

此时各个寄存器的值如下:

img

此时eax(11) != 0x13(19),所以会爆炸,所以拆弹的关键来到了eax。在经过函数递归之后,eax的值要变为19,那就观察一下eax的值是如何变化的。不过这里还能看出第二个输入的整数应该是0x13(19)

在分析eax的过程中被绕晕了,索性摆烂,反正最大不超过14,一个个试,试出了正确答案4

img

所以这一题的最终答案就是:4 19

phase_5

贴代码:

08048dcd <phase_5>:8048dcd:	55                   	push   %ebp8048dce:	89 e5                	mov    %esp,%ebp8048dd0:	53                   	push   %ebx8048dd1:	83 ec 20             	sub    $0x20,%esp8048dd4:	8b 5d 08             	mov    0x8(%ebp),%ebx8048dd7:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax8048ddd:	89 45 f4             	mov    %eax,-0xc(%ebp)8048de0:	31 c0                	xor    %eax,%eax8048de2:	53                   	push   %ebx8048de3:	e8 78 02 00 00       	call   8049060 <string_length>8048de8:	83 c4 10             	add    $0x10,%esp8048deb:	83 f8 06             	cmp    $0x6,%eax8048dee:	74 05                	je     8048df5 <phase_5+0x28>8048df0:	e8 90 03 00 00       	call   8049185 <explode_bomb>8048df5:	b8 00 00 00 00       	mov    $0x0,%eax8048dfa:	0f b6 14 03          	movzbl (%ebx,%eax,1),%edx8048dfe:	83 e2 0f             	and    $0xf,%edx8048e01:	0f b6 92 74 a1 04 08 	movzbl 0x804a174(%edx),%edx8048e08:	88 54 05 ed          	mov    %dl,-0x13(%ebp,%eax,1)8048e0c:	83 c0 01             	add    $0x1,%eax8048e0f:	83 f8 06             	cmp    $0x6,%eax8048e12:	75 e6                	jne    8048dfa <phase_5+0x2d>8048e14:	c6 45 f3 00          	movb   $0x0,-0xd(%ebp)8048e18:	83 ec 08             	sub    $0x8,%esp8048e1b:	68 4b a1 04 08       	push   $0x804a14b8048e20:	8d 45 ed             	lea    -0x13(%ebp),%eax8048e23:	50                   	push   %eax8048e24:	e8 59 02 00 00       	call   8049082 <strings_not_equal>8048e29:	83 c4 10             	add    $0x10,%esp8048e2c:	85 c0                	test   %eax,%eax8048e2e:	74 05                	je     8048e35 <phase_5+0x68>8048e30:	e8 50 03 00 00       	call   8049185 <explode_bomb>8048e35:	8b 45 f4             	mov    -0xc(%ebp),%eax8048e38:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax8048e3f:	74 05                	je     8048e46 <phase_5+0x79>8048e41:	e8 4a f9 ff ff       	call   8048790 <__stack_chk_fail@plt>8048e46:	8b 5d fc             	mov    -0x4(%ebp),%ebx8048e49:	c9                   	leave  8048e4a:	c3                   	ret    

先看部分代码:

 8048de3:	e8 78 02 00 00       	call   8049060 <string_length>8048de8:	83 c4 10             	add    $0x10,%esp8048deb:	83 f8 06             	cmp    $0x6,%eax8048dee:	74 05                	je     8048df5 <phase_5+0x28>8048df0:	e8 90 03 00 00       	call   8049185 <explode_bomb>

一开始调用了一次string_length,并且比较了一下字符串的长度和6,如果不相等就会爆炸,需要知道string_length是计算的谁的长度:

img

img

经过测试发现是我们输入的字符串的长度,这样就确定了我们要输入的字符串的长度是6

接下来是一段循环:

 8048df5:	b8 00 00 00 00       	mov    $0x0,%eax8048dfa:	0f b6 14 03          	movzbl  (%ebx,%eax,1),%edx8048dfe:	83 e2 0f             	and    $0xf,%edx8048e01:	0f b6 92 74 a1 04 08 	movzbl  0x804a174(%edx),%edx8048e08:	88 54 05 ed          	mov    %dl,-0x13(%ebp,%eax,1)8048e0c:	83 c0 01             	add    $0x1,%eax8048e0f:	83 f8 06             	cmp    $0x6,%eax8048e12:	75 e6                	jne    8048dfa <phase_5+0x2d>

eax0开始,每次+1,直到等于6。分析一下这个循环做了什么。

首先给edx赋值,且这个值随着循环次数改变而改变,然后保留edx低4位,把某个地址加上第四位作为偏移量,得到的地址处的值赋给edx,然后把这个值赋给-0x13(%ebp,%eax,1),只占一个字节空间,猜测每一次取了一个字符,并且后面调用了strings_not_equal

 8048e1b:	68 4b a1 04 08       	push   $0x804a14b8048e20:	8d 45 ed             	lea    -0x13(%ebp),%eax8048e23:	50                  	push   %eax8048e24:	e8 59 02 00 00       	call   8049082 <strings_not_equal>

六次循环得到一个字符串,并把这个字符串的首地址作为参数传给strings_not_equal,所以这六个字符串是什么呢,答案在0x804a14b

img

所以要通过循环构造出这么一个字符串。循环是从0x804a174加偏移得到的,先看一下0x804a174指向的内容:

img

很显然要从maduiersnfotvbylSo通过加偏移量的方式依次构造出f l a m e s,偏移量依次是9 15 1 0 5 7,偏移量从哪来呢:

8048dd4: 8b 5d 08 mov 0x8(%ebp),%ebx

很显然是传过来的参数,这个参数就是我们输入的字符串,所以是取我们输入的字符串对应的ascii码值的低四位作为偏移量,所以答案的要求就出来了:低四位分别是1001(9) 1111(15) 0001(1) 0000(0) 0101(5) 0111(7)

令高位为0100(64),得到一组解I(73) O(79) A(65) @(64) E(69) G(71),所以正确答案就是IOA@EG

phase_6

贴代码:

08048e4b <phase_6>:8048e4b:	55                   	push   %ebp8048e4c:	89 e5                	mov    %esp,%ebp8048e4e:	56                   	push   %esi8048e4f:	53                   	push   %ebx8048e50:	83 ec 48             	sub    $0x48,%esp8048e53:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax8048e59:	89 45 f4             	mov    %eax,-0xc(%ebp)8048e5c:	31 c0                	xor    %eax,%eax8048e5e:	8d 45 c4             	lea    -0x3c(%ebp),%eax8048e61:	50                   	push   %eax8048e62:	ff 75 08             	push   0x8(%ebp)8048e65:	e8 43 03 00 00       	call   80491ad <read_six_numbers>8048e6a:	83 c4 10             	add    $0x10,%esp8048e6d:	be 00 00 00 00       	mov    $0x0,%esi8048e72:	8b 44 b5 c4          	mov    -0x3c(%ebp,%esi,4),%eax8048e76:	83 e8 01             	sub    $0x1,%eax8048e79:	83 f8 05             	cmp    $0x5,%eax8048e7c:	76 05                	jbe    8048e83 <phase_6+0x38>8048e7e:	e8 02 03 00 00       	call   8049185 <explode_bomb>8048e83:	83 c6 01             	add    $0x1,%esi8048e86:	83 fe 06             	cmp    $0x6,%esi8048e89:	74 33                	je     8048ebe <phase_6+0x73>8048e8b:	89 f3                	mov    %esi,%ebx8048e8d:	8b 44 9d c4          	mov    -0x3c(%ebp,%ebx,4),%eax8048e91:	39 44 b5 c0          	cmp    %eax,-0x40(%ebp,%esi,4)8048e95:	75 05                	jne    8048e9c <phase_6+0x51>8048e97:	e8 e9 02 00 00       	call   8049185 <explode_bomb>8048e9c:	83 c3 01             	add    $0x1,%ebx8048e9f:	83 fb 05             	cmp    $0x5,%ebx8048ea2:	7e e9                	jle    8048e8d <phase_6+0x42>8048ea4:	eb cc                	jmp    8048e72 <phase_6+0x27>8048ea6:	8b 52 08             	mov    0x8(%edx),%edx8048ea9:	83 c0 01             	add    $0x1,%eax8048eac:	39 c8                	cmp    %ecx,%eax8048eae:	75 f6                	jne    8048ea6 <phase_6+0x5b>8048eb0:	89 54 b5 dc          	mov    %edx,-0x24(%ebp,%esi,4)8048eb4:	83 c3 01             	add    $0x1,%ebx8048eb7:	83 fb 06             	cmp    $0x6,%ebx8048eba:	75 07                	jne    8048ec3 <phase_6+0x78>8048ebc:	eb 1c                	jmp    8048eda <phase_6+0x8f>8048ebe:	bb 00 00 00 00       	mov    $0x0,%ebx8048ec3:	89 de                	mov    %ebx,%esi8048ec5:	8b 4 c 9d c4          	mov    -0x3c(%ebp,%ebx,4),%ecx8048ec9:	b8 01 00 00 00       	mov    $0x1,%eax8048ece:	ba 3c c1 04 08       	mov    $0x804c13c,%edx8048ed3:	83 f9 01             	cmp    $0x1,%ecx8048ed6:	7f ce                	jg     8048ea6 <phase_6+0x5b>8048ed8:	eb d6                	jmp    8048eb0 <phase_6+0x65>8048eda:	8b 5d dc             	mov    -0x24(%ebp),%ebx8048edd:	8d 45 dc             	lea    -0x24(%ebp),%eax8048ee0:	8d 75 f0             	lea    -0x10(%ebp),%esi8048ee3:	89 d9                	mov    %ebx,%ecx8048ee5:	8b 50 04             	mov    0x4(%eax),%edx8048ee8:	89 51 08             	mov    %edx,0x8(%ecx)8048eeb:	83 c0 04             	add    $0x4,%eax8048eee:	89 d1                	mov    %edx,%ecx8048ef0:	39 f0                	cmp    %esi,%eax8048ef2:	75 f1                	jne    8048ee5 <phase_6+0x9a>8048ef4:	c7 42 08 00 00 00 00 	movl   $0x0,0x8(%edx)8048efb:	be 05 00 00 00       	mov    $0x5,%esi8048f00:	8b 43 08             	mov    0x8(%ebx),%eax8048f03:	8b 00                	mov    (%eax),%eax8048f05:	39 03                	cmp    %eax,(%ebx)8048f07:	7d 05                	jge    8048f0e <phase_6+0xc3>8048f09:	e8 77 02 00 00       	call   8049185 <explode_bomb>8048f0e:	8b 5b 08             	mov    0x8(%ebx),%ebx8048f11:	83 ee 01             	sub    $0x1,%esi8048f14:	75 ea                	jne    8048f00 <phase_6+0xb5>8048f16:	8b 45 f4             	mov    -0xc(%ebp),%eax8048f19:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax8048f20:	74 05                	je     8048f27 <phase_6+0xdc>8048f22:	e8 69 f8 ff ff       	call   8048790 <__stack_chk_fail@plt>8048f27:	8d 65 f8             	lea    -0x8(%ebp),%esp8048f2a:	5b                   	pop    %ebx8048f2b:	5e                   	pop    %esi8048f2c:	5d                   	pop    %ebp8048f2d:	c3                   	ret    

先看:

 8048e5e:	8d 45 c4             	lea    -0x3c(%ebp),%eax8048e61:	50                  	push   %eax8048e62:	ff 75 08             	push   0x8(%ebp)8048e65:	e8 43 03 00 00       	call   80491ad <read_six_numbers>

通过开始的一段代码可知是输入六个数字,并且首个元素存放地址为-0x3c(%ebp),假设输入的六个数字分别是a[0], a[1], a[2], a[3], a[4], a[5]

之后有一个判断:

 8048e6a:	83 c4 10             	add    $0x10,%esp8048e6d:	be 00 00 00 00       	mov    $0x0,%esi8048e72:	8b 44 b5 c4          	mov    -0x3c(%ebp,%esi,4),%eax8048e76:	83 e8 01             	sub    $0x1,%eax8048e79:	83 f8 05             	cmp    $0x5,%eax8048e7c:	76 05                	jbe    8048e83 <phase_6+0x38>8048e7e:	e8 02 03 00 00       	call   8049185 <explode_bomb>

跳转条件是(a[0] - 1 <= 5),这就限制了a[0] <= 6,后面以输入1进行尝试。

 8048e83:	83 c6 01             	add    $0x1,%esi8048e86:	83 fe 06             	cmp    $0x6,%esi8048e89:	74 33                	je     8048ebe <phase_6+0x73>8048e8b:	89 f3                	mov    %esi,%ebx8048e8d:	8b 44 9d c4          	mov    -0x3c(%ebp,%ebx,4),%eax8048e91:	39 44 b5 c0          	cmp    %eax,-0x40(%ebp,%esi,4)8048e95:	75 05                	jne    8048e9c <phase_6+0x51>8048e97:	e8 e9 02 00 00       	call   8049185 <explode_bomb>

接下来esi + 16进行比较,可以猜想出这是一个循环,esi是计数器,循环六次。接下来又比较了a[0]和a[1],要求两个数不能相等。

 8048e9c:	83 c3 01             	add    $0x1,%ebx8048e9f:	83 fb 05             	cmp    $0x5,%ebx8048ea2:	7e e9                	jle    8048e8d <phase_6+0x42>8048ea4:	eb cc                	jmp    8048e72 <phase_6+0x27>

然后ebx成了新计数器,循环5次,这里是把a[0]依次与a[1] ~ a[5]各比较一次,保证不相等。可以发现其实这是两层循环,先判断循环到的a[i]是否小于等于6,然后判断它与后面几个数是否相等。

整个大循环结束后来到新部分:

 8048ea6:	8b 52 08             	mov    0x8(%edx),%edx8048ea9:	83 c0 01             	add    $0x1,%eax8048eac:	39 c8                	cmp    %ecx,%eax8048eae:	75 f6                	jne    8048ea6 <phase_6+0x5b>8048eb0:	89 54 b5 dc          	mov    %edx,-0x24(%ebp,%esi,4)8048eb4:	83 c3 01             	add    $0x1,%ebx8048eb7:	83 fb 06             	cmp    $0x6,%ebx8048eba:	75 07                	jne    8048ec3 <phase_6+0x78>8048ebc:	eb 1c                	jmp    8048eda <phase_6+0x8f>8048ebe:	bb 00 00 00 00       	mov    $0x0,%ebx8048ec3:	89 de                	mov    %ebx,%esi8048ec5:	8b 4 c 9d c4          	mov    -0x3c(%ebp,%ebx,4),%ecx8048ec9:	b8 01 00 00 00       	mov    $0x1,%eax8048ece:	ba 3c c1 04 08       	mov    $0x804c13c,%edx8048ed3:	83 f9 01             	cmp    $0x1,%ecx8048ed6:	7f ce                	jg     8048ea6 <phase_6+0x5b>8048ed8:	eb d6                	jmp    8048eb0 <phase_6+0x65>

程序从8048ebe开始执行,这里的计数器是ebx,从0开始循环到6,共循环7次。

第一次cmp跳转之前各个寄存器的值如图:

img

比较的是ecx1ecxa[ebx],第一次是a[0],我输入的是1 2 3 4 5 6,显然jg不会跳转,程序来到了8048eb0。接下来把edx给到了-0x24(%ebp,%esi,4)地址处,推测ebp-0x24地址处存放的是一个指针804c13c

可以看一下这个地址处存放的内容:

img

推测是链表,进一步查看:

img

链表一共有六个节点,每个节点存放三个数据,显然第三个数据是下一个节点的地址。第二个数据从1~6,推测是链表的节点编号,那第一个数据应该就是链表存放的有效数据。

mov 0x8(%edx), %edx 操作其实是把edx更新成下个节点的指针,当eaxecx相等时把节点指针压栈,

否则会进入一个循环:eax++; edx继续指向下个指针,直到eax == ecx,这也就意味着六个节点压栈的顺序与我们输入的六个数字相关,如果输入的2 4 1 3 6 5,则六个节点在栈中存放的顺序依次为node2 node4 node1 node3 node6 node5,存放地址依次为%ebp-0x24、%ebp-0x20、%ebp-0x1c、%ebp-0x18、%ebp-0x14、%ebp-0x10。其实就是node[a[0]] ~ node[a[6]]

继续看代码:

 8048eda:	8b 5d dc             	mov    -0x24(%ebp),%ebx8048edd:	8d 45 dc             	lea    -0x24(%ebp),%eax8048ee0:	8d 75 f0             	lea    -0x10(%ebp),%esi8048ee3:	89 d9                	mov    %ebx,%ecx8048ee5:	8b 50 04             	mov    0x4(%eax),%edx8048ee8:	89 51 08             	mov    %edx,0x8(%ecx)8048eeb:	83 c0 04             	add    $0x4,%eax8048eee:	89 d1                	mov    %edx,%ecx8048ef0:	39 f0                	cmp    %esi,%eax8048ef2:	75 f1                	jne    8048ee5 <phase_6+0x9a>

这段代码也是循环,会改变链表指向,通过多次调试可以发现:如果输入的是1 2 3 4 5 6,则链表指向不变;如果输入的是6 5 4 3 2 1,则链表指向变为6>5>4>3>2>1>2,最后有个环;如果输入的是1 3 5 2 4 6,则链表指向变为1>3>5>2>4>6

部分调试记录如下:

img

img

以上发现了链表指向顺序会跟输入的六个数有关。

来到最后一段代码:

 8048ef4:	c7 42 08 00 00 00 00 	movl   $0x0,0x8(%edx)8048efb:	be 05 00 00 00       	mov    $0x5,%esi8048f00:	8b 43 08             	mov    0x8(%ebx),%eax8048f03:	8b 00               	mov    (%eax),%eax8048f05:	39 03                	cmp    %eax,(%ebx)8048f07:	7d 05               	jge    8048f0e <phase_6+0xc3>8048f09:	e8 77 02 00 00       	call   8049185 <explode_bomb>8048f0e:	8b 5b 08             	mov    0x8(%ebx),%ebx8048f11:	83 ee 01             	sub    $0x1,%esi8048f14:	75 ea                	jne    8048f00 <phase_6+0xb5>

这段代码其实就是遍历链表,遍历顺序就是刚刚重新排列好的顺序,然后依次取相邻两个链表的值进行比较,这一点可以调试到 8048f05 cmp %eax, (%ebx) 之前,看一下eax的值和ebx指向的值,如果前者大于后者就能通过,然后继续遍历,否则bomb!

所以链表的正确排列顺序就有依据了,先记录一下各个链表存放的数据都是多少:

img

1-995 2-959 3-779 4-921 5-853 6-363

要求前者大于后者,所以正确顺序也就是正确答案应该是:1 2 4 5 3 6

secret_phase

还有一个函数名叫secret_phase的,代码如下:

08048f80 <secret_phase>:8048f80:	55                   	push   %ebp8048f81:	89 e5                	mov    %esp,%ebp8048f83:	53                   	push   %ebx8048f84:	83 ec 04             	sub    $0x4,%esp8048f87:	e8 5b 02 00 00       	call   80491e7 <read_line>8048f8c:	83 ec 04             	sub    $0x4,%esp8048f8f:	6a 0a                	push   $0xa8048f91:	6a 00                	push   $0x08048f93:	50                   	push   %eax8048f94:	e8 e7 f8 ff ff       	call   8048880 <strtol@plt>8048f99:	89 c3                	mov    %eax,%ebx8048f9b:	8d 40 ff             	lea    -0x1(%eax),%eax8048f9e:	83 c4 10             	add    $0x10,%esp8048fa1:	3d e8 03 00 00       	cmp    $0x3e8,%eax8048fa6:	76 05                	jbe    8048fad <secret_phase+0x2d>8048fa8:	e8 d8 01 00 00       	call   8049185 <explode_bomb>8048fad:	83 ec 08             	sub    $0x8,%esp8048fb0:	53                   	push   %ebx8048fb1:	68 88 c0 04 08       	push   $0x804c0888048fb6:	e8 73 ff ff ff       	call   8048f2e <fun7>8048fbb:	83 c4 10             	add    $0x10,%esp8048fbe:	83 f8 03             	cmp    $0x3,%eax8048fc1:	74 05                	je     8048fc8 <secret_phase+0x48>8048fc3:	e8 bd 01 00 00       	call   8049185 <explode_bomb>8048fc8:	83 ec 0c             	sub    $0xc,%esp8048fcb:	68 1c a1 04 08       	push   $0x804a11c8048fd0:	e8 eb f7 ff ff       	call   80487c0 <puts@plt>8048fd5:	e8 10 03 00 00       	call   80492ea <phase_defused>8048fda:	83 c4 10             	add    $0x10,%esp8048fdd:	8b 5d fc             	mov    -0x4(%ebp),%ebx8048fe0:	c9                   	leave  8048fe1:	c3                   	ret   

phase_defused中有调用,所以贴一下phase_defused的代码:

080492ea <phase_defused>:80492ea:	55                   	push   %ebp80492eb:	89 e5                	mov    %esp,%ebp80492ed:	83 ec 68             	sub    $0x68,%esp80492f0:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax80492f6:	89 45 f4             	mov    %eax,-0xc(%ebp)80492f9:	31 c0                	xor    %eax,%eax80492fb:	83 3d cc c3 04 08 06 	cmpl   $0x6,0x804c3cc8049302:	75 6f                	jne    8049373 <phase_defused+0x89>8049304:	83 ec 0c             	sub    $0xc,%esp8049307:	8d 45 a4             	lea    -0x5c(%ebp),%eax804930a:	50                   	push   %eax804930b:	8d 45 a0             	lea    -0x60(%ebp),%eax804930e:	50                   	push   %eax804930f:	8d 45 9c             	lea    -0x64(%ebp),%eax8049312:	50                   	push   %eax8049313:	68 ed a2 04 08       	push   $0x804a2ed8049318:	68 d0 c4 04 08       	push   $0x804c4d0804931d:	e8 ee f4 ff ff       	call   8048810 <__isoc99_sscanf@plt>8049322:	83 c4 20             	add    $0x20,%esp8049325:	83 f8 03             	cmp    $0x3,%eax8049328:	75 39                	jne    8049363 <phase_defused+0x79>804932a:	83 ec 08             	sub    $0x8,%esp804932d:	68 f6 a2 04 08       	push   $0x804a2f68049332:	8d 45 a4             	lea    -0x5c(%ebp),%eax8049335:	50                   	push   %eax8049336:	e8 47 fd ff ff       	call   8049082 <strings_not_equal>804933b:	83 c4 10             	add    $0x10,%esp804933e:	85 c0                	test   %eax,%eax8049340:	75 21                	jne    8049363 <phase_defused+0x79>8049342:	83 ec 0c             	sub    $0xc,%esp8049345:	68 bc a1 04 08       	push   $0x804a1bc804934a:	e8 71 f4 ff ff       	call   80487c0 <puts@plt>804934f:	c7 04 24 e4 a1 04 08 	movl   $0x804a1e4,(%esp)8049356:	e8 65 f4 ff ff       	call   80487c0 <puts@plt>804935b:	e8 20 fc ff ff       	call   8048f80 <secret_phase>8049360:	83 c4 10             	add    $0x10,%esp8049363:	83 ec 0c             	sub    $0xc,%esp8049366:	68 1c a2 04 08       	push   $0x804a21c804936b:	e8 50 f4 ff ff       	call   80487c0 <puts@plt>8049370:	83 c4 10             	add    $0x10,%esp8049373:	8b 45 f4             	mov    -0xc(%ebp),%eax8049376:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax804937d:	74 05                	je     8049384 <phase_defused+0x9a>804937f:	e8 0c f4 ff ff       	call   8048790 <__stack_chk_fail@plt>8049384:	c9                   	leave  8049385:	c3                   	ret    

phase_defused的代码中发现了这句:

804935b: e8 20 fc ff ff call 8048f80 <secret_phase>

这也就意味着每次拆除炸弹都有可能触发secret_phase,继续对phase_defused的代码进行分析,寻找触发条件,着重关注最这行:

 8049312:	50                  	push   %eax8049313:	68 ed a2 04 08       	push   $0x804a2ed8049318:	68 d0 c4 04 08       	push   $0x804c4d0804931d:	e8 ee f4 ff ff       	call   8048810 <__isoc99_sscanf@plt>8049322:	83 c4 20             	add    $0x20,%esp8049325:	83 f8 03             	cmp    $0x3,%eax8049328:	75 39                	jne    8049363 <phase_defused+0x79>

调用sscanf之前先看一下输入格式:

img

两个整数一个字符串,这里会判断输入了几个,如果输入的是两个数据并不会bomb,而是正常结束,输入两个的正好是phase_4,猜测phase_4多输一个字符串会触发secret_phase,下面继续分析这个字符串应该是什么:

 804932a:	83 ec 08             	sub    $0x8,%esp804932d:	68 f6 a2 04 08       	push   $0x804a2f68049332:	8d 45 a4             	lea    -0x5c(%ebp),%eax8049335:	50                  	push   %eax8049336:	e8 47 fd ff ff       	call   8049082 <strings_not_equal>804933b:	83 c4 10             	add    $0x10,%esp804933e:	85 c0                	test   %eax,%eax8049340:	75 21                	jne    8049363 <phase_defused+0x79>

看到一个关键地址0x804a2f6,查看内容:

img

这就找到了我们要多输入的字符串:DrEvil

输入进去之后程序最后输出了小彩蛋,印证了它就是目标字符串;

img

回过头来对secret_phase进行分析:

 8048f8f:	6a 0a                	push   $0xa8048f91:	6a 00                	push   $0x08048f93:	50                  	push   %eax8048f94:	e8 e7 f8 ff ff       	call   8048880 <strtol@plt>8048f99:	89 c3                	mov    %eax,%ebx8048f9b:	8d 40 ff             	lea    -0x1(%eax),%eax8048f9e:	83 c4 10             	add    $0x10,%esp8048fa1:	3d e8 03 00 00       	cmp    $0x3e8,%eax8048fa6:	76 05                	jbe    8048fad <secret_phase+0x2d>8048fa8:	e8 d8 01 00 00       	call   8049185 <explode_bomb>

开始会调用一个strtol函数,将字符串转成long,这里要转的字符串的首地址是eax,也就是上一次调用的函数的返回值,上一个函数是read_line,所以也就是把我们的输入转成long-1后与0x3e8(1000)进行比较,要求小于等于1000,也就意味着我们要输入一个数字,并且这个数字要小于等于1001

继续向下看;

 8048fb0:	53                  	push   %ebx8048fb1:	68 88 c0 04 08       	push   $0x804c0888048fb6:	e8 73 ff ff ff       	call   8048f2e <fun7>8048fbb:	83 c4 10             	add    $0x10,%esp8048fbe:	83 f8 03             	cmp    $0x3,%eax8048fc1:	74 05                	je     8048fc8 <secret_phase+0x48>8048fc3:	e8 bd 01 00 00       	call   8049185 <explode_bomb>8048fbb:	83 c4 10             	add    $0x10,%esp8048fbe:	83 f8 03             	cmp    $0x3,%eax8048fc1:	74 05                	je     8048fc8 <secret_phase+0x48>8048fc3:	e8 bd 01 00 00       	call   8049185 <explode_bomb>

看最后三句可以看出当调用完fun7后,eax==3时才不会爆炸,secret_phase也就会结束,所以关键看eaxfun7中的变化。

调用fun7之前传递的参数为ebx0x804c088ebx根据之前的代码可知是我们输入的整数,看一下0x804c088存的是什么(64是显示64个单位,u是以十进制格式输出,换成x就是以十六进制格式输出,w是以8个字节为单位,我一开始是用默认的4个字节为单位,结果什么也看不出来,耽误了好久):

img

img

数据有nxx,后面还有nodex,其实就是phase_6中的链表节点结构。不难看出nxx也有着异曲同工之妙。再看一眼,能看出nxx是以三个单位为一组,第一个存放的是一个较小的数,猜测为有效数据,后两个显然是指针,并且前七个节点中的两个指针都有指向,猜测为二叉树结构,一共15个节点,8个叶子结点,根据各个节点之间的连接关系和对应地址处的标识,可以推断出这棵树的形状如下:

img

整理出来发现这是一颗平衡搜索二叉树,左节点都比父节点小,右节点都比父节点大。

那么fun7的参数就有了,第一个参数是这颗二叉树根节点的地址,第二个参数是我们输入的数,接下来可以继续分析fun7,先打出完整代码,然后顺着翻译一下:

08048f2e <fun7>:8048f2e:	55                   	push   %ebp8048f2f:	89 e5                	mov    %esp,%ebp8048f31:	53                   	push   %ebx8048f32:	83 ec 04             	sub    $0x4,%esp8048f35:	8b 55 08             	mov    0x8(%ebp),%edx8048f38:	8b 4d 0c             	mov    0xc(%ebp),%ecx8048f3b:	85 d2                	test   %edx,%edx8048f3d:	74 37                	je     8048f76 <fun7+0x48>8048f3f:	8b 1a                	mov    (%edx),%ebx8048f41:	39 cb                	cmp    %ecx,%ebx8048f43:	7e 13                	jle    8048f58 <fun7+0x2a>8048f45:	83 ec 08             	sub    $0x8,%esp8048f48:	51                   	push   %ecx8048f49:	ff 72 04             	push   0x4(%edx)8048f4c:	e8 dd ff ff ff       	call   8048f2e <fun7>8048f51:	83 c4 10             	add    $0x10,%esp8048f54:	01 c0                	add    %eax,%eax8048f56:	eb 23                	jmp    8048f7b <fun7+0x4d>8048f58:	b8 00 00 00 00       	mov    $0x0,%eax8048f5d:	39 cb                	cmp    %ecx,%ebx8048f5f:	74 1a                	je     8048f7b <fun7+0x4d>8048f61:	83 ec 08             	sub    $0x8,%esp8048f64:	51                   	push   %ecx8048f65:	ff 72 08             	push   0x8(%edx)8048f68:	e8 c1 ff ff ff       	call   8048f2e <fun7>8048f6d:	83 c4 10             	add    $0x10,%esp8048f70:	8d 44 00 01          	lea    0x1(%eax,%eax,1),%eax8048f74:	eb 05                	jmp    8048f7b <fun7+0x4d>8048f76:	b8 ff ff ff ff       	mov    $0xffffffff,%eax8048f7b:	8b 5d fc             	mov    -0x4(%ebp),%ebx8048f7e:	c9                   	leave  8048f7f:	c3                   	ret    

顺着思路翻译一下还是很简单的:

fun7 (node* root, int num) {if (root == null) {eax = 0xffffffff;return}if (root->val <= num) {eax = 0;				# ①if (root->val == num)return;fun7(root->right, num);eax = eax * 2 + 1;		# ②return;}fun7(root->left, num);eax *= 2;					# ③return;
}

本来是想一步步分析汇编的,但递归实在太绕了:

img

还是顺着把汇编翻译一下比较简单。

最终目标是让eax变为3。这里有关eax的有效操作有①eax = 0;②eax = eax * 2 + 1;③eax *= 2

所以一个可行的顺序是①②②,,对应的在递归第一层要执行②,第二层要执行②,第三层执行①。

来到第一层,此时root->val = 36,第一层要走到②之前那一句进入二层调用,这就要求num > 36

来到第二层,此时root->val = 50,仍需要走到②之前那一句进入三层调用,这就要求num > 50

来到第三层,此时root->val = 107,这次需要走到①处然后返回,要求num == 107

这样就推理出了最终答案:107

测试一下完全通过:

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4月2日-3日·上海 | 3DCC 第二届3D细胞培养与类器官研发峰会携手CGT Asia 重磅来袭

类器官&#xff08;Organoids&#xff09;作为干细胞研究领域最重要的成果之一&#xff0c;在基础医学研究、转化医学及药物研发领域展现出巨大的应用潜力&#xff0c;特别是在精准医疗以及药物安全性和有效性评价等方向凭借其先天优势引起了极大的市场关注&#xff0c;成为各大…

【智能家居】5、主流程设计以及外设框架编写与测试

目录 一、主流程设计 1、工厂模式结构体定义 &#xff08;1&#xff09;指令工厂 inputCmd.h &#xff08;2&#xff09;外设工厂 controlDevices.h 二、外设框架编写 1、创建外设工厂对象bathroomLight 2、编写相关函数框架 3、将浴室灯相关操作插入外设工厂链表等待被调…

pm2在Windows环境中的使用

pm2 进程管理工具可以Windows操作系统上运行&#xff0c;当一台Windows电脑上需要运行多个进程时&#xff0c;或者运维时需要运行多个进程以提供服务时。可以使用pm2&#xff0c;而不再是使用脚本。 1. 使用PM2管理进程 1.1. 启动PM2项目 1.1.1. 直接启动项目 参数说明&…

springboot集成nacos并实现自动刷新

目录 1.说明 2.示例 3.自动刷新的注意点 1.说明 springboot项目中存在好多配置文件&#xff0c;比如配置数据信息&#xff0c;redis信息等等&#xff0c;配置文件可以直接放在代码&#xff0c;也可以放在像nacos这样的组件中&#xff0c;实现动态的管理&#xff0c;修改配置…

浅谈滑动窗口

滑动窗口是什么&#xff1f; 滑动窗口其实是一个想象出来的数据结构。有左边界L和有边界R。 举例来说&#xff1a;数组 arr {3,1,5,7,6,5,8}; 其窗口就是我们规定的一个运动轨迹。 最开始时&#xff0c;边界LR都在数组的最左侧&#xff0c;此时没有包住任何数。 此时规定&…

ExoPlayer架构详解与源码分析(9)——TsExtractor

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

linux进程之进程的优先级➕环境变量

文章目录 1.优先级的认识1.1优先级的介绍1.2初识优先级1.3ps指令1.4查看/修改进程的优先级1.5对优先级的认识1.6对进程的深一步理解 2.环境变量2.0环境变量相关的命令2.1环境变量的概念2.2常见/查看环境变量2.3环境变量的作用2.4修改环境变量1.将zombie可执行程序放到PATH现有的…

CF1899B 250 Thousand Tons of TNT

题目链接 题目 题目大意 T T T 组测试数据 每组 n n n 个货物&#xff0c;第 i i i 个货物 的重量是 a i a_i ai​ 用k辆货车按顺序装这些货物&#xff0c;条件是每辆车上的货物个数都一样&#xff0c;也即是说 n n n 必须能被 k k k 整除&#xff0c; 求任意两辆车货物总…

Alibaba Nacos注册中心实战

为什么需要注册中心 思考&#xff1a;网络请求&#xff0c;如果服务提供者发生变动&#xff0c;服务调用者如何感知服务提供者的ip和端口变化&#xff1f; // 微服务之间通过RestTemplate调用&#xff0c;ip:port写死&#xff0c;如果ip或者port变化呢&#xff1f; String ur…

【学习笔记】Java安全之动态加载字节码

文章目录 什么是Java的字节码利用URLClassLoader加载远程class文件利用ClassLoader#defineClass直接加载字节码利用TemplatesImpl加载字节码利用BCEL ClassLoader加载字节码 最近在学习Phith0n师傅的知识星球的Java安全漫谈系列&#xff0c;随手记下笔记 什么是Java的字节码 J…

CCRC认证是什么?

什么是CCRC认证&#xff1f; 信息安全服务资质&#xff0c;是信息安全服务机构提供安全服务的一种资格&#xff0c;包括法律地位、资源状况、管理水平、技术能力等方面的要求。 信息安全服务资质&#xff08;CCRC&#xff09;是依据国家法律法规、国家标准、行业标准和技术规范…

iOS学习 --- Xcode 15 下载iOS_17.0.1_Simulator失败解决方法

1.去开发者官网下载安装包 https://developer.apple.com/download/all/?qiOS%2017 使用浏览器下载。 2.打开终端通过命令添加到xcode 命令如下&#xff1a; sudo xcode-select -s /Applications/Xcode.app(输入开始密码)xcodebuild -runFirstLaunch (等待一小会)xcrun simctl…

翻译软件Mate Translate mac中文版介绍说明

Mate Translate mac可以帮你翻译超过100种语言的单词和短语&#xff0c;使用文本到语音转换&#xff0c;并浏览历史上已经完成的翻译。你还可以使用Control S在弹出窗口中快速交换语言。 Mate Translate Mac版软件介绍 Mate Translate 可以在你的所有设备之间轻松同步&#x…

2023年首届天府杯数学建模国际大赛问题A思路详解与参考代码:大地测量数据中异常现象的特征和识别

地球变形观测是固体潮汐曲线分析和地震前体研究的重要手段&#xff0c;也是地球观测技术的重要组成部分。基于各种精密科学仪器的变形观测点主要集中在洞穴、地下井等易的自然灾害&#xff08;雷暴、强降雨、降雪等&#xff09;&#xff0c;人工维护、人工爆破等外部条件&#…

基于Vue+SpringBoot的厦门旅游电子商务预订系统 开源项目

项目编号&#xff1a; S 030 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S030&#xff0c;文末获取源码。} 项目编号&#xff1a;S030&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 景点类型模块2.2 景点档案模块2.3 酒…

Zookeeper实战案例(1)

前置知识&#xff1a; Zookeeper学习笔记&#xff08;1&#xff09;—— 基础知识-CSDN博客 Zookeeper学习笔记&#xff08;2&#xff09;—— Zookeeper API简单操作-CSDN博客 Zookeeper 服务器动态上下线监听案例 需求分析 某分布式系统中&#xff0c;主节点可以有多台&am…

【linux】nmon 工具使用

nmon 介绍 nmon是奈杰尔的性能监视器的缩写&#xff0c;适用于POWER、x86、x86_64、Mainframe和现在的ARM&#xff08;Raspberry Pi&#xff09;上的Linux。同样适用于nmon for AIX的工具&#xff08;与IBM的AIX一起提供&#xff09;。njmon与之类似&#xff0c;但将数据保存为…

Node.js环境配置级安装vue-cli脚手架

一、下载安装Node.js (略) 二、验证node.js并配置 1、下载安装后&#xff0c;cmd面板输入node -v查询版本、npm -v ,查看npm是否安装成功&#xff08;有版本号就行了&#xff09; 2、选择npm镜像&#xff08;npm config set registry https://registry.npm.taobao.org&…

optee4.0.0 qemu_v8的环境搭建篇(ubuntu20.10)

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈文章目录 前提条件1、拉取代码2、下载工具链3、编译4、运行

kubernetes|云原生| 如何优雅的重启和更新pod---pod生命周期管理实务

前言&#xff1a; kubernetes的管理维护的复杂性体现在了方方面面&#xff0c;例如&#xff0c;&#xff50;&#xff4f;&#xff44;的管理&#xff0c;服务的管理&#xff0c;用户的管理&#xff08;&#xff32;&#xff22;&#xff21;&#xff23;&#xff09;&#xf…