【csapp lab】lab2_bomblab

news2024/11/18 15:30:19

文章目录

    • 前言
    • 实验内容
      • 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   %ebp
 8048b31:	89 e5                	mov    %esp,%ebp
 8048b33:	83 ec 10             	sub    $0x10,%esp
 8048b36:	68 ec a0 04 08       	push   $0x804a0ec
 8048b3b:	ff 75 08             	push   0x8(%ebp)
 8048b3e:	e8 3f 05 00 00       	call   8049082 <strings_not_equal>
 8048b43:	83 c4 10             	add    $0x10,%esp
 8048b46:	85 c0                	test   %eax,%eax
 8048b48:	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   %ebp
 8048b52:	89 e5                	mov    %esp,%ebp
 8048b54:	53                   	push   %ebx
 8048b55:	83 ec 2c             	sub    $0x2c,%esp
 8048b58:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 8048b5e:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8048b61:	31 c0                	xor    %eax,%eax
 8048b63:	8d 45 dc             	lea    -0x24(%ebp),%eax
 8048b66:	50                   	push   %eax
 8048b67:	ff 75 08             	push   0x8(%ebp)
 8048b6a:	e8 3e 06 00 00       	call   80491ad <read_six_numbers>
 8048b6f:	83 c4 10             	add    $0x10,%esp
 8048b72:	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),%eax
 8048b88:	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,%ebx
 8048b96:	83 fb 06             	cmp    $0x6,%ebx
 8048b99:	75 e7                	jne    8048b82 <phase_2+0x31>
 8048b9b:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8048b9e:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 8048ba5:	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),%ebx
 8048baf:	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),%eax
 8048b88:	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,%ebx
 8048b96:	83 fb 06             	cmp    $0x6,%ebx
 8048b99:	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   %ebp
 8048bb2:	89 e5                	mov    %esp,%ebp
 8048bb4:	83 ec 24             	sub    $0x24,%esp
 8048bb7:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 8048bbd:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8048bc0:	31 c0                	xor    %eax,%eax
 8048bc2:	8d 45 f0             	lea    -0x10(%ebp),%eax
 8048bc5:	50                   	push   %eax
 8048bc6:	8d 45 eb             	lea    -0x15(%ebp),%eax
 8048bc9:	50                   	push   %eax
 8048bca:	8d 45 ec             	lea    -0x14(%ebp),%eax
 8048bcd:	50                   	push   %eax
 8048bce:	68 42 a1 04 08       	push   $0x804a142
 8048bd3:	ff 75 08             	push   0x8(%ebp)
 8048bd6:	e8 35 fc ff ff       	call   8048810 <__isoc99_sscanf@plt>
 8048bdb:	83 c4 20             	add    $0x20,%esp
 8048bde:	83 f8 02             	cmp    $0x2,%eax
 8048be1:	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),%eax
 8048bf5:	ff 24 85 54 a1 04 08 	jmp    *0x804a154(,%eax,4)
 8048bfc:	b8 78 00 00 00       	mov    $0x78,%eax
 8048c01:	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,%eax
 8048c18:	e9 ce 00 00 00       	jmp    8048ceb <phase_3+0x13a>
 8048c1d:	b8 69 00 00 00       	mov    $0x69,%eax
 8048c22:	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,%eax
 8048c39:	e9 ad 00 00 00       	jmp    8048ceb <phase_3+0x13a>
 8048c3e:	b8 74 00 00 00       	mov    $0x74,%eax
 8048c43:	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,%eax
 8048c5a:	e9 8c 00 00 00       	jmp    8048ceb <phase_3+0x13a>
 8048c5f:	b8 68 00 00 00       	mov    $0x68,%eax
 8048c64:	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,%eax
 8048c77:	eb 72                	jmp    8048ceb <phase_3+0x13a>
 8048c79:	b8 79 00 00 00       	mov    $0x79,%eax
 8048c7e:	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,%eax
 8048c91:	eb 58                	jmp    8048ceb <phase_3+0x13a>
 8048c93:	b8 62 00 00 00       	mov    $0x62,%eax
 8048c98:	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,%eax
 8048cab:	eb 3e                	jmp    8048ceb <phase_3+0x13a>
 8048cad:	b8 64 00 00 00       	mov    $0x64,%eax
 8048cb2:	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,%eax
 8048cc5:	eb 24                	jmp    8048ceb <phase_3+0x13a>
 8048cc7:	b8 65 00 00 00       	mov    $0x65,%eax
 8048ccc:	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,%eax
 8048cdf:	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,%eax
 8048ceb:	3a 45 eb             	cmp    -0x15(%ebp),%al
 8048cee:	74 05                	je     8048cf5 <phase_3+0x144>
 8048cf0:	e8 90 04 00 00       	call   8049185 <explode_bomb>
 8048cf5:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8048cf8:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 8048cff:	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   $0x804a142
 8048bd3:	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,%esp
 8048bde:	83 f8 02             	cmp    $0x2,%eax
 8048be1:	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),%eax
 8048bc5:	50                  	push   %eax
 8048bc6:	8d 45 eb             	lea    -0x15(%ebp),%eax
 8048bc9:	50                  	push   %eax
 8048bca:	8d 45 ec             	lea    -0x14(%ebp),%eax
 8048bcd:	50                  	push   %eax

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

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

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

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

image-20231119023945131

跳转到了:

 8048c1d:	b8 69 00 00 00       	mov    $0x69,%eax
 8048c22:	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),%al
 8048cee:	74 05                	je     8048cf5 <phase_3+0x144>
 8048cf0:	e8 90 04 00 00       	call   8049185 <explode_bomb>
 8048cf5:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8048cf8:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 8048cff:	    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   %ebp
 8048d09:	89 e5                	mov    %esp,%ebp
 8048d0b:	56                   	push   %esi
 8048d0c:	53                   	push   %ebx
 8048d0d:	8b 55 08             	mov    0x8(%ebp),%edx
 8048d10:	8b 4d 0c             	mov    0xc(%ebp),%ecx
 8048d13:	8b 75 10             	mov    0x10(%ebp),%esi
 8048d16:	89 f0                	mov    %esi,%eax
 8048d18:	29 c8                	sub    %ecx,%eax
 8048d1a:	89 c3                	mov    %eax,%ebx
 8048d1c:	c1 eb 1f             	shr    $0x1f,%ebx
 8048d1f:	01 d8                	add    %ebx,%eax
 8048d21:	d1 f8                	sar    %eax
 8048d23:	8d 1c 08             	lea    (%eax,%ecx,1),%ebx
 8048d26:	39 d3                	cmp    %edx,%ebx
 8048d28:	7e 15                	jle    8048d3f <func4+0x37>
 8048d2a:	83 ec 04             	sub    $0x4,%esp
 8048d2d:	8d 43 ff             	lea    -0x1(%ebx),%eax
 8048d30:	50                   	push   %eax
 8048d31:	51                   	push   %ecx
 8048d32:	52                   	push   %edx
 8048d33:	e8 d0 ff ff ff       	call   8048d08 <func4>
 8048d38:	83 c4 10             	add    $0x10,%esp
 8048d3b:	01 d8                	add    %ebx,%eax
 8048d3d:	eb 19                	jmp    8048d58 <func4+0x50>
 8048d3f:	89 d8                	mov    %ebx,%eax
 8048d41:	39 d3                	cmp    %edx,%ebx
 8048d43:	7d 13                	jge    8048d58 <func4+0x50>
 8048d45:	83 ec 04             	sub    $0x4,%esp
 8048d48:	56                   	push   %esi
 8048d49:	8d 43 01             	lea    0x1(%ebx),%eax
 8048d4c:	50                   	push   %eax
 8048d4d:	52                   	push   %edx
 8048d4e:	e8 b5 ff ff ff       	call   8048d08 <func4>
 8048d53:	83 c4 10             	add    $0x10,%esp
 8048d56:	01 d8                	add    %ebx,%eax
 8048d58:	8d 65 f8             	lea    -0x8(%ebp),%esp
 8048d5b:	5b                   	pop    %ebx
 8048d5c:	5e                   	pop    %esi
 8048d5d:	5d                   	pop    %ebp
 8048d5e:	c3                   	ret    

08048d5f <phase_4>:
 8048d5f:	55                   	push   %ebp
 8048d60:	89 e5                	mov    %esp,%ebp
 8048d62:	83 ec 18             	sub    $0x18,%esp
 8048d65:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 8048d6b:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8048d6e:	31 c0                	xor    %eax,%eax
 8048d70:	8d 45 f0             	lea    -0x10(%ebp),%eax
 8048d73:	50                   	push   %eax
 8048d74:	8d 45 ec             	lea    -0x14(%ebp),%eax
 8048d77:	50                   	push   %eax
 8048d78:	68 93 a2 04 08       	push   $0x804a293
 8048d7d:	ff 75 08             	push   0x8(%ebp)
 8048d80:	e8 8b fa ff ff       	call   8048810 <__isoc99_sscanf@plt>
 8048d85:	83 c4 10             	add    $0x10,%esp
 8048d88:	83 f8 02             	cmp    $0x2,%eax
 8048d8b:	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,%esp
 8048d9b:	6a 0e                	push   $0xe
 8048d9d:	6a 00                	push   $0x0
 8048d9f:	ff 75 ec             	push   -0x14(%ebp)
 8048da2:	e8 61 ff ff ff       	call   8048d08 <func4>
 8048da7:	83 c4 10             	add    $0x10,%esp
 8048daa:	83 f8 13             	cmp    $0x13,%eax
 8048dad:	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),%eax
 8048dbd:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 8048dc4:	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),%eax
 8048d73:	50                  	push   %eax
 8048d74:	8d 45 ec             	lea    -0x14(%ebp),%eax
 8048d77:	50                  	push   %eax
 8048d78:	68 93 a2 04 08       	push   $0x804a293
 8048d7d:	ff 75 08             	push   0x8(%ebp)
 8048d80:	e8 8b fa ff ff       	call   8048810 <__isoc99_sscanf@plt>
 8048d85:	83 c4 10             	add    $0x10,%esp
 8048d88:	83 f8 02             	cmp    $0x2,%eax
 8048d8b:	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,%esp
 8048d9b:	6a 0e                	push   $0xe
 8048d9d:	6a 00                	push   $0x0
 8048d9f:	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),%edx
 8048d10:	8b 4d 0c             	mov    0xc(%ebp),%ecx
 8048d13:	8b 75 10             	mov    0x10(%ebp),%esi

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

 8048d16:	89 f0                	mov    %esi,%eax
 8048d18:	29 c8                	sub    %ecx,%eax
 8048d1a:	89 c3                	mov    %eax,%ebx
 8048d1c:	c1 eb 1f             	shr    $0x1f,%ebx
 8048d1f:	01 d8                	add    %ebx,%eax
 8048d21:	d1 f8                	sar    %eax
 8048d23:	8d 1c 08             	lea    (%eax,%ecx,1),%ebx
 8048d26:	39 d3                	cmp    %edx,%ebx
 8048d28:	7e 15                	jle    8048d3f <func4+0x37>

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

img

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

 8048d2a:	83 ec 04             	sub    $0x4,%esp
 8048d2d:	8d 43 ff             	lea    -0x1(%ebx),%eax
 8048d30:	50                   	push   %eax
 8048d31:	51                   	push   %ecx
 8048d32:	52                   	push   %edx
 8048d33:	e8 d0 ff ff ff       	call   8048d08 <func4>

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

img

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

img

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

img

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

img

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

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

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

img

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

 8048d58:	8d 65 f8             	lea    -0x8(%ebp),%esp
 8048d5b:	5b                  	pop    %ebx
 8048d5c:	5e                  	pop    %esi
 8048d5d:	5d                  	pop    %ebp
 8048d5e:	c3                  	ret   

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

 8048d33:	e8 d0 ff ff ff       	call   8048d08 <func4>
 8048d38:	83 c4 10             	add    $0x10,%esp
 8048d3b:	01 d8                	add    %ebx,%eax
 8048d3d:	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,%esp
 8048daa:	83 f8 13             	cmp    $0x13,%eax
 8048dad:	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   %ebp
 8048dce:	89 e5                	mov    %esp,%ebp
 8048dd0:	53                   	push   %ebx
 8048dd1:	83 ec 20             	sub    $0x20,%esp
 8048dd4:	8b 5d 08             	mov    0x8(%ebp),%ebx
 8048dd7:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 8048ddd:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8048de0:	31 c0                	xor    %eax,%eax
 8048de2:	53                   	push   %ebx
 8048de3:	e8 78 02 00 00       	call   8049060 <string_length>
 8048de8:	83 c4 10             	add    $0x10,%esp
 8048deb:	83 f8 06             	cmp    $0x6,%eax
 8048dee:	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,%eax
 8048dfa:	0f b6 14 03          	movzbl (%ebx,%eax,1),%edx
 8048dfe:	83 e2 0f             	and    $0xf,%edx
 8048e01:	0f b6 92 74 a1 04 08 	movzbl 0x804a174(%edx),%edx
 8048e08:	88 54 05 ed          	mov    %dl,-0x13(%ebp,%eax,1)
 8048e0c:	83 c0 01             	add    $0x1,%eax
 8048e0f:	83 f8 06             	cmp    $0x6,%eax
 8048e12:	75 e6                	jne    8048dfa <phase_5+0x2d>
 8048e14:	c6 45 f3 00          	movb   $0x0,-0xd(%ebp)
 8048e18:	83 ec 08             	sub    $0x8,%esp
 8048e1b:	68 4b a1 04 08       	push   $0x804a14b
 8048e20:	8d 45 ed             	lea    -0x13(%ebp),%eax
 8048e23:	50                   	push   %eax
 8048e24:	e8 59 02 00 00       	call   8049082 <strings_not_equal>
 8048e29:	83 c4 10             	add    $0x10,%esp
 8048e2c:	85 c0                	test   %eax,%eax
 8048e2e:	74 05                	je     8048e35 <phase_5+0x68>
 8048e30:	e8 50 03 00 00       	call   8049185 <explode_bomb>
 8048e35:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8048e38:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 8048e3f:	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),%ebx
 8048e49:	c9                   	leave  
 8048e4a:	c3                   	ret    

先看部分代码:

 8048de3:	e8 78 02 00 00       	call   8049060 <string_length>
 8048de8:	83 c4 10             	add    $0x10,%esp
 8048deb:	83 f8 06             	cmp    $0x6,%eax
 8048dee:	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,%eax
 8048dfa:	0f b6 14 03          	movzbl  (%ebx,%eax,1),%edx
 8048dfe:	83 e2 0f             	and    $0xf,%edx
 8048e01:	0f b6 92 74 a1 04 08 	movzbl  0x804a174(%edx),%edx
 8048e08:	88 54 05 ed          	mov    %dl,-0x13(%ebp,%eax,1)
 8048e0c:	83 c0 01             	add    $0x1,%eax
 8048e0f:	83 f8 06             	cmp    $0x6,%eax
 8048e12:	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   $0x804a14b
 8048e20:	8d 45 ed             	lea    -0x13(%ebp),%eax
 8048e23:	50                  	push   %eax
 8048e24:	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   %ebp
 8048e4c:	89 e5                	mov    %esp,%ebp
 8048e4e:	56                   	push   %esi
 8048e4f:	53                   	push   %ebx
 8048e50:	83 ec 48             	sub    $0x48,%esp
 8048e53:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 8048e59:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8048e5c:	31 c0                	xor    %eax,%eax
 8048e5e:	8d 45 c4             	lea    -0x3c(%ebp),%eax
 8048e61:	50                   	push   %eax
 8048e62:	ff 75 08             	push   0x8(%ebp)
 8048e65:	e8 43 03 00 00       	call   80491ad <read_six_numbers>
 8048e6a:	83 c4 10             	add    $0x10,%esp
 8048e6d:	be 00 00 00 00       	mov    $0x0,%esi
 8048e72:	8b 44 b5 c4          	mov    -0x3c(%ebp,%esi,4),%eax
 8048e76:	83 e8 01             	sub    $0x1,%eax
 8048e79:	83 f8 05             	cmp    $0x5,%eax
 8048e7c:	76 05                	jbe    8048e83 <phase_6+0x38>
 8048e7e:	e8 02 03 00 00       	call   8049185 <explode_bomb>

 8048e83:	83 c6 01             	add    $0x1,%esi
 8048e86:	83 fe 06             	cmp    $0x6,%esi
 8048e89:	74 33                	je     8048ebe <phase_6+0x73>
 8048e8b:	89 f3                	mov    %esi,%ebx
 8048e8d:	8b 44 9d c4          	mov    -0x3c(%ebp,%ebx,4),%eax
 8048e91:	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,%ebx
 8048e9f:	83 fb 05             	cmp    $0x5,%ebx
 8048ea2:	7e e9                	jle    8048e8d <phase_6+0x42>
 8048ea4:	eb cc                	jmp    8048e72 <phase_6+0x27>

 8048ea6:	8b 52 08             	mov    0x8(%edx),%edx
 8048ea9:	83 c0 01             	add    $0x1,%eax
 8048eac:	39 c8                	cmp    %ecx,%eax
 8048eae:	75 f6                	jne    8048ea6 <phase_6+0x5b>
 8048eb0:	89 54 b5 dc          	mov    %edx,-0x24(%ebp,%esi,4)
 8048eb4:	83 c3 01             	add    $0x1,%ebx
 8048eb7:	83 fb 06             	cmp    $0x6,%ebx
 8048eba:	75 07                	jne    8048ec3 <phase_6+0x78>
 8048ebc:	eb 1c                	jmp    8048eda <phase_6+0x8f>

 8048ebe:	bb 00 00 00 00       	mov    $0x0,%ebx
 8048ec3:	89 de                	mov    %ebx,%esi
 8048ec5:	8b 4 c 9d c4          	mov    -0x3c(%ebp,%ebx,4),%ecx
 8048ec9:	b8 01 00 00 00       	mov    $0x1,%eax
 8048ece:	ba 3c c1 04 08       	mov    $0x804c13c,%edx
 8048ed3:	83 f9 01             	cmp    $0x1,%ecx
 8048ed6:	7f ce                	jg     8048ea6 <phase_6+0x5b>
 8048ed8:	eb d6                	jmp    8048eb0 <phase_6+0x65>

 8048eda:	8b 5d dc             	mov    -0x24(%ebp),%ebx
 8048edd:	8d 45 dc             	lea    -0x24(%ebp),%eax
 8048ee0:	8d 75 f0             	lea    -0x10(%ebp),%esi
 8048ee3:	89 d9                	mov    %ebx,%ecx
 8048ee5:	8b 50 04             	mov    0x4(%eax),%edx
 8048ee8:	89 51 08             	mov    %edx,0x8(%ecx)
 8048eeb:	83 c0 04             	add    $0x4,%eax
 8048eee:	89 d1                	mov    %edx,%ecx
 8048ef0:	39 f0                	cmp    %esi,%eax
 8048ef2:	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,%esi
 8048f00:	8b 43 08             	mov    0x8(%ebx),%eax
 8048f03:	8b 00                	mov    (%eax),%eax
 8048f05:	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),%ebx
 8048f11:	83 ee 01             	sub    $0x1,%esi
 8048f14:	75 ea                	jne    8048f00 <phase_6+0xb5>

 8048f16:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8048f19:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 8048f20:	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),%esp
 8048f2a:	5b                   	pop    %ebx
 8048f2b:	5e                   	pop    %esi
 8048f2c:	5d                   	pop    %ebp
 8048f2d:	c3                   	ret    

先看:

 8048e5e:	8d 45 c4             	lea    -0x3c(%ebp),%eax
 8048e61:	50                  	push   %eax
 8048e62:	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,%esp
 8048e6d:	be 00 00 00 00       	mov    $0x0,%esi
 8048e72:	8b 44 b5 c4          	mov    -0x3c(%ebp,%esi,4),%eax
 8048e76:	83 e8 01             	sub    $0x1,%eax
 8048e79:	83 f8 05             	cmp    $0x5,%eax
 8048e7c:	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,%esi
 8048e86:	83 fe 06             	cmp    $0x6,%esi
 8048e89:	74 33                	je     8048ebe <phase_6+0x73>
 8048e8b:	89 f3                	mov    %esi,%ebx
 8048e8d:	8b 44 9d c4          	mov    -0x3c(%ebp,%ebx,4),%eax
 8048e91:	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,%ebx
 8048e9f:	83 fb 05             	cmp    $0x5,%ebx
 8048ea2:	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),%edx
 8048ea9:	83 c0 01             	add    $0x1,%eax
 8048eac:	39 c8                	cmp    %ecx,%eax
 8048eae:	75 f6                	jne    8048ea6 <phase_6+0x5b>
 8048eb0:	89 54 b5 dc          	mov    %edx,-0x24(%ebp,%esi,4)
 8048eb4:	83 c3 01             	add    $0x1,%ebx
 8048eb7:	83 fb 06             	cmp    $0x6,%ebx
 8048eba:	75 07                	jne    8048ec3 <phase_6+0x78>
 8048ebc:	eb 1c                	jmp    8048eda <phase_6+0x8f>

 8048ebe:	bb 00 00 00 00       	mov    $0x0,%ebx
 8048ec3:	89 de                	mov    %ebx,%esi
 8048ec5:	8b 4 c 9d c4          	mov    -0x3c(%ebp,%ebx,4),%ecx
 8048ec9:	b8 01 00 00 00       	mov    $0x1,%eax
 8048ece:	ba 3c c1 04 08       	mov    $0x804c13c,%edx
 8048ed3:	83 f9 01             	cmp    $0x1,%ecx
 8048ed6:	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),%ebx
 8048edd:	8d 45 dc             	lea    -0x24(%ebp),%eax
 8048ee0:	8d 75 f0             	lea    -0x10(%ebp),%esi
 8048ee3:	89 d9                	mov    %ebx,%ecx
 8048ee5:	8b 50 04             	mov    0x4(%eax),%edx
 8048ee8:	89 51 08             	mov    %edx,0x8(%ecx)
 8048eeb:	83 c0 04             	add    $0x4,%eax
 8048eee:	89 d1                	mov    %edx,%ecx
 8048ef0:	39 f0                	cmp    %esi,%eax
 8048ef2:	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,%esi
 8048f00:	8b 43 08             	mov    0x8(%ebx),%eax
 8048f03:	8b 00               	mov    (%eax),%eax
 8048f05:	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),%ebx
 8048f11:	83 ee 01             	sub    $0x1,%esi
 8048f14:	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   %ebp
 8048f81:	89 e5                	mov    %esp,%ebp
 8048f83:	53                   	push   %ebx
 8048f84:	83 ec 04             	sub    $0x4,%esp
 8048f87:	e8 5b 02 00 00       	call   80491e7 <read_line>
 8048f8c:	83 ec 04             	sub    $0x4,%esp
 8048f8f:	6a 0a                	push   $0xa
 8048f91:	6a 00                	push   $0x0
 8048f93:	50                   	push   %eax
 8048f94:	e8 e7 f8 ff ff       	call   8048880 <strtol@plt>
 8048f99:	89 c3                	mov    %eax,%ebx
 8048f9b:	8d 40 ff             	lea    -0x1(%eax),%eax
 8048f9e:	83 c4 10             	add    $0x10,%esp
 8048fa1:	3d e8 03 00 00       	cmp    $0x3e8,%eax
 8048fa6:	76 05                	jbe    8048fad <secret_phase+0x2d>
 8048fa8:	e8 d8 01 00 00       	call   8049185 <explode_bomb>
 8048fad:	83 ec 08             	sub    $0x8,%esp
 8048fb0:	53                   	push   %ebx
 8048fb1:	68 88 c0 04 08       	push   $0x804c088
 8048fb6:	e8 73 ff ff ff       	call   8048f2e <fun7>
 8048fbb:	83 c4 10             	add    $0x10,%esp
 8048fbe:	83 f8 03             	cmp    $0x3,%eax
 8048fc1:	74 05                	je     8048fc8 <secret_phase+0x48>
 8048fc3:	e8 bd 01 00 00       	call   8049185 <explode_bomb>
 8048fc8:	83 ec 0c             	sub    $0xc,%esp
 8048fcb:	68 1c a1 04 08       	push   $0x804a11c
 8048fd0:	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,%esp
 8048fdd:	8b 5d fc             	mov    -0x4(%ebp),%ebx
 8048fe0:	c9                   	leave  
 8048fe1:	c3                   	ret   

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

080492ea <phase_defused>:
 80492ea:	55                   	push   %ebp
 80492eb:	89 e5                	mov    %esp,%ebp
 80492ed:	83 ec 68             	sub    $0x68,%esp
 80492f0:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 80492f6:	89 45 f4             	mov    %eax,-0xc(%ebp)
 80492f9:	31 c0                	xor    %eax,%eax
 80492fb:	83 3d cc c3 04 08 06 	cmpl   $0x6,0x804c3cc
 8049302:	75 6f                	jne    8049373 <phase_defused+0x89>
 8049304:	83 ec 0c             	sub    $0xc,%esp
 8049307:	8d 45 a4             	lea    -0x5c(%ebp),%eax
 804930a:	50                   	push   %eax
 804930b:	8d 45 a0             	lea    -0x60(%ebp),%eax
 804930e:	50                   	push   %eax
 804930f:	8d 45 9c             	lea    -0x64(%ebp),%eax
 8049312:	50                   	push   %eax
 8049313:	68 ed a2 04 08       	push   $0x804a2ed
 8049318:	68 d0 c4 04 08       	push   $0x804c4d0
 804931d:	e8 ee f4 ff ff       	call   8048810 <__isoc99_sscanf@plt>
 8049322:	83 c4 20             	add    $0x20,%esp
 8049325:	83 f8 03             	cmp    $0x3,%eax
 8049328:	75 39                	jne    8049363 <phase_defused+0x79>
 804932a:	83 ec 08             	sub    $0x8,%esp
 804932d:	68 f6 a2 04 08       	push   $0x804a2f6
 8049332:	8d 45 a4             	lea    -0x5c(%ebp),%eax
 8049335:	50                   	push   %eax
 8049336:	e8 47 fd ff ff       	call   8049082 <strings_not_equal>
 804933b:	83 c4 10             	add    $0x10,%esp
 804933e:	85 c0                	test   %eax,%eax
 8049340:	75 21                	jne    8049363 <phase_defused+0x79>
 8049342:	83 ec 0c             	sub    $0xc,%esp
 8049345:	68 bc a1 04 08       	push   $0x804a1bc
 804934a:	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,%esp
 8049363:	83 ec 0c             	sub    $0xc,%esp
 8049366:	68 1c a2 04 08       	push   $0x804a21c
 804936b:	e8 50 f4 ff ff       	call   80487c0 <puts@plt>
 8049370:	83 c4 10             	add    $0x10,%esp
 8049373:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8049376:	65 33 05 14 00 00 00 	xor    %gs:0x14,%eax
 804937d:	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   %eax
 8049313:	68 ed a2 04 08       	push   $0x804a2ed
 8049318:	68 d0 c4 04 08       	push   $0x804c4d0
 804931d:	e8 ee f4 ff ff       	call   8048810 <__isoc99_sscanf@plt>
 8049322:	83 c4 20             	add    $0x20,%esp
 8049325:	83 f8 03             	cmp    $0x3,%eax
 8049328:	75 39                	jne    8049363 <phase_defused+0x79>

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

img

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

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

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

img

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

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

img

回过头来对secret_phase进行分析:

 8048f8f:	6a 0a                	push   $0xa
 8048f91:	6a 00                	push   $0x0
 8048f93:	50                  	push   %eax
 8048f94:	e8 e7 f8 ff ff       	call   8048880 <strtol@plt>
 8048f99:	89 c3                	mov    %eax,%ebx
 8048f9b:	8d 40 ff             	lea    -0x1(%eax),%eax
 8048f9e:	83 c4 10             	add    $0x10,%esp
 8048fa1:	3d e8 03 00 00       	cmp    $0x3e8,%eax
 8048fa6:	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   %ebx
 8048fb1:	68 88 c0 04 08       	push   $0x804c088
 8048fb6:	e8 73 ff ff ff       	call   8048f2e <fun7>
 8048fbb:	83 c4 10             	add    $0x10,%esp
 8048fbe:	83 f8 03             	cmp    $0x3,%eax
 8048fc1:	74 05                	je     8048fc8 <secret_phase+0x48>
 8048fc3:	e8 bd 01 00 00       	call   8049185 <explode_bomb>
 8048fbb:	83 c4 10             	add    $0x10,%esp
 8048fbe:	83 f8 03             	cmp    $0x3,%eax
 8048fc1:	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   %ebp
 8048f2f:	89 e5                	mov    %esp,%ebp
 8048f31:	53                   	push   %ebx
 8048f32:	83 ec 04             	sub    $0x4,%esp
 8048f35:	8b 55 08             	mov    0x8(%ebp),%edx
 8048f38:	8b 4d 0c             	mov    0xc(%ebp),%ecx
 8048f3b:	85 d2                	test   %edx,%edx
 8048f3d:	74 37                	je     8048f76 <fun7+0x48>

 8048f3f:	8b 1a                	mov    (%edx),%ebx
 8048f41:	39 cb                	cmp    %ecx,%ebx
 8048f43:	7e 13                	jle    8048f58 <fun7+0x2a>
 8048f45:	83 ec 08             	sub    $0x8,%esp
 8048f48:	51                   	push   %ecx
 8048f49:	ff 72 04             	push   0x4(%edx)
 8048f4c:	e8 dd ff ff ff       	call   8048f2e <fun7>

 8048f51:	83 c4 10             	add    $0x10,%esp
 8048f54:	01 c0                	add    %eax,%eax
 8048f56:	eb 23                	jmp    8048f7b <fun7+0x4d>
  
 8048f58:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f5d:	39 cb                	cmp    %ecx,%ebx
 8048f5f:	74 1a                	je     8048f7b <fun7+0x4d>

 8048f61:	83 ec 08             	sub    $0x8,%esp
 8048f64:	51                   	push   %ecx
 8048f65:	ff 72 08             	push   0x8(%edx)
 8048f68:	e8 c1 ff ff ff       	call   8048f2e <fun7>

 8048f6d:	83 c4 10             	add    $0x10,%esp
 8048f70:	8d 44 00 01          	lea    0x1(%eax,%eax,1),%eax
 8048f74:	eb 05                	jmp    8048f7b <fun7+0x4d>
 
 8048f76:	b8 ff ff ff ff       	mov    $0xffffffff,%eax

 8048f7b:	8b 5d fc             	mov    -0x4(%ebp),%ebx
 8048f7e:	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.coloradmin.cn/o/1226281.html

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

相关文章

湖北成人自考毕业学位申请照片要求及自拍制作方法

湖北成人自考学位申请需要上传照片是为了身份验证和学籍管理的目的。通过上传照片&#xff0c;学校可以确认申请者的身份&#xff0c;并将照片与其他申请信息进行关联。这有助于提高学校对学生的管理效率&#xff0c;确保学籍信息的准确性。同时&#xff0c;照片也用于学位证书…

基于FPGA的五子棋(论文+源码)

1.系统设计 在本次设计中&#xff0c;整个系统硬件框图如下图所示&#xff0c;以ALTERA的FPGA作为硬件载体&#xff0c;VGA接口&#xff0c;PS/2鼠标来完成设计&#xff0c;整个系统可以完成人人对战&#xff0c;人机对战的功能。系统通过软件编程来实现上述功能。将在硬件设计…

计算机硬件的基本组成

一、冯诺依曼结构 存储程序&#xff1a; “存储程序”的概念是指将指令以二进制代码的形式事先输入计算机的主存储器&#xff0c;然后按其在存储器中的首地址执行程序的第一条指令&#xff0c;以后就按该程序的规定顺序执行其他指令&#xff0c;直至程序执行结束。 冯诺依曼计…

C语言每日一题(33)随机链表的复制

力扣138 随机链表的复制 题目描述 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都…

理论与实践相结合之Cisco Packet Tracer网络模拟器安装教程

简介 Packet Tracer是由思科设计的跨平台可视化仿真工具&#xff0c;它允许用户创建网络拓扑以模仿计算机网络和使用命令行界面来模拟配置思科路由器和交换机。Packet Tracer的用户界面为拖放式&#xff0c;允许用户根据自己的需要添加和删除模拟的网络设备。 Packet Tracer很…

卡片排列-第15届蓝桥第二次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第159讲。 第15届蓝桥杯第2次STEMA测评已于2023年10月29日落下帷幕&#xff0c;编程题一共有6题&#xff0c;分别如下&…

cesium雷达扫描(模糊圆效果)

cesium雷达扫描(模糊圆效果) 1、实现思路 使用ellipse方法加载圆型,修改ellipse中‘material’方法重写自己的glsl来实现当前效果 1、示例源码 index.html <!DOCTYPE html> <html lang="en"><head><!<

如何将vscode和Linux远程链接:

如何将vscode和Linux远程链接&#xff1a; Remote - SSH - 远程登录Linux 安装Remote - SSH 我们下载完后&#xff0c;就会出现这些图标 这里点一下号 查看一下我们的主机名&#xff0c;并复制 输入ssh 用户名主机名 这里是要将ssh这个文件要放在主机下的哪个路径下&#xff…

最强人工智能ChatGPT引领AIGC发展

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- ——AI不会淘汰所有人&#xff0c;但会淘汰不懂AI的人 一、最强人工智能GPT-4 Turbo 在前不久的OpenAI开发者大会&#xff0c;正值Chatgpt3.5发布一…

微信第三方平台开发重点概念流程梳理

标题 微信开发的亿点点概念第三方平台代开发流程亿些概念开发流程 代公众号使用JS SDK一些概念具体流程引用 微信开发的亿点点概念 AppID&#xff1a;AppID是不同类型的产品的账号ID,是账号的唯一标识符。例如公众号的AppID、小程序的AppID、开放平台的AppID、第三方平台的App…

C++之内建函数对象

C之内建函数对象 算术仿函数 #include<iostream> using namespace std; #include<functional>//内建函数对象头文件 //内建函数对象 算术仿函数void test() {// negate 一元仿函数 取反仿函数negate<int>n;cout << n(100) << endl;//plus 二元仿…

油猴脚本(JavaScript)-练手-简单的随机音乐播放器

浅浅的写个简单的随机音乐播放脚本(可移动)&#xff0c;注释很详细&#xff0c;直接上源码 效果&#xff1a; // UserScript // name 播放音乐脚本 // namespace 代码对我眨眼睛 // version 1.2 // description 在API上请求音乐链接并随机自动连续播放音乐&…

解决向日葵远程控制linux命令行版本无法输入密码的问题

就是如下所示的框&#xff0c;官方说是按方向键↓选择用户名和密码的输入框输入&#xff0c;但是按方向键死活没用&#xff0c;研究了之后按tab键就行了。

WMS仓库管理系统库位分配规划

分配说明 每个商品必须至少有一个分拣位&#xff08;整箱或拆零均可&#xff09;如果只设了拆零分拣位&#xff0c;则入库不分配存储位&#xff0c;只上拆零分拣位&#xff0c;对于DPS分拣商品是一品固定一个货位&#xff0c;对于RF分拣商品是动态分配货位&#xff0c;一个商品…

Java集合大总结——List的简单使用

List简单介绍 鉴于Java中数组用来存储数据的局限性&#xff0c;我们通常使用java.util.List替代数组List集合类中元素有序、且可重复&#xff0c;集合中的每个元素都有其对应的顺序索引。JDK API中List接口的实现类常用的有&#xff1a;ArrayList、LinkedList和Vector。 List…

Linux:清空或删除大文件内容的5种方法

在Linux终端下处理文件时&#xff0c;有时我们想直接清空文件的内容但又不必使用任何Linux命令行编辑器 去打开这些文件。那怎样才能达到这个目的呢&#xff1f;在这篇文章中&#xff0c;我们将介绍几种借助一些实用的命令来清空文件内容的方法。 注意&#xff1a;在我们进一步…

美国政府首席信息安全官详细介绍零信任战略竞赛

如果企业想吸取教训&#xff0c;为庞大的组织快速制定零信任战略&#xff0c;他们应该看看美国联邦政府在 2024 年之前让所有机构合规的努力。 这就是被任命为联邦办公室 CISO&#xff08;首席信息安全官&#xff09; 的克里斯德鲁沙 (Chris DeRusha) 的看法。 周三&#xf…

OpenAI变天:也许会有另一个OpenAI要崛起?

本周五&#xff0c;OpenAI发布重磅声明&#xff0c;创始人兼CEO山姆奥特曼辞任OpenAI&#xff0c;并退出董事会。总裁Greg Brockman&#xff08;格雷格布罗克曼&#xff09;将辞去董事会主席一职&#xff0c;但将继续在公司担任职务&#xff0c;向CEO汇报。 作为吃瓜群众&#…

[CUDA]去除Eigen库中的warning

一、问题提出 假如使用nvcc对cuda代码进行编译时&#xff0c;如果代码中使用了Eigen库&#xff08;头文件&#xff09;&#xff0c;编译时可能会显示很多warning information&#xff0c;如下图红框中所示&#xff1a; 这些warning信息虽然不会影响代码的实际运行&#xff0c;…

【WiFI问题自助】解决WiFi能连上但是没有网的问题

WiFi能连上但是没有网的问题 背景&#xff1a;wifi能连上&#xff0c;但是没有网 解决 遇事不决&#xff0c;先重启啊&#xff01;怎么重启&#xff1f;拔掉电源再插上&#xff01;拔掉网线再插上&#xff01; 直接ok了。 思考记录 今天WiFi又上不了网了&#xff0c;昨天报…