现在的位置: 首页 > 综合 > 正文

CSAPP lab. binary bomb 二进制炸弹

2017年10月17日 ⁄ 综合 ⁄ 共 9518字 ⁄ 字号 评论关闭

http://csapp.cs.cmu.edu/public/labs.html 下了个32位的bomb文件。。

使用

-objdump -d bomb

得到反汇编的代码

= =一大坨的完全被吓到了有木有

然后看到有main函数还有6个phase,于是抓住重点开始研究

call <phase_x>  之后如果ret出来再调用<phase_defused>就表示拆蛋。。!弹成功了

不然就会爆炸。

所以我们深入到每个phase_x里面研究。

先来看phase_1

08048b20 <phase_1>:
 8048b20:	55                   	push   %ebp
 8048b21:	89 e5                	mov    %esp,%ebp
 8048b23:	83 ec 08             	sub    $0x8,%esp
 8048b26:	8b 45 08             	mov    0x8(%ebp),%eax
 8048b29:	83 c4 f8             	add    $0xfffffff8,%esp
 8048b2c:	68 c0 97 04 08       	push   $0x80497c0
 8048b31:	50                   	push   %eax
 8048b32:	e8 f9 04 00 00       	call   8049030 <strings_not_equal>  ;这个函数改变了%eax的值
 8048b37:	83 c4 10             	add    $0x10,%esp
 8048b3a:	85 c0                	test   %eax,%eax
 8048b3c:	74 05                	je     8048b43 <phase_1+0x23>       ;如果eax不为0,那么字符串正确
 8048b3e:	e8 b9 09 00 00       	call   80494fc <explode_bomb>
 8048b43:	89 ec                	mov    %ebp,%esp
 8048b45:	5d                   	pop    %ebp
 8048b46:	c3                   	ret    
 8048b47:	90                   	nop

我们看到,

其中会调用<strings_not_equal>函数,之后再判断寄存器%eax是否为0,如果为0的话,phase_1正常ret,不然就调用explode_bomb引爆炸弹

所以关键就是strings_not_equal函数,部分代码见下面:

08049030 <strings_not_equal>:
 8049030:	55                   	push   %ebp
 8049031:	89 e5                	mov    %esp,%ebp
 8049033:	83 ec 0c             	sub    $0xc,%esp
 8049036:	57                   	push   %edi
 8049037:	56                   	push   %esi
 8049038:	53                   	push   %ebx
 8049039:	8b 75 08             	mov    0x8(%ebp),%esi
 804903c:	8b 7d 0c             	mov    0xc(%ebp),%edi
 804903f:	83 c4 f4             	add    $0xfffffff4,%esp

 8049039:	8b 75 08             	mov    0x8(%ebp),%esi
 804903c:	8b 7d 0c             	mov    0xc(%ebp),%edi

这两行可以看出strings_not_equal有两个参数,那么是哪两个呢?我们回到phase_1里面,看到再调用之前的两个进栈命令

进栈的分别是%eax和$0x80497c0,猜测比较两个字符串的函数的参数必然是两个指向char类型的指针,所以继续猜想eax是我们输入的字符串,而0x80497c0就是系统给定的字符串了,然后从整个文件里搜0x80497c0.发现什么都没有= =怎么办好zhaoji!!!。。。。

不过我们好像忘了什么东西!!gdb!!以前调试C的时候用过,发现不方便就再也不用了!没想到它在逆向工程的时候这么逆天!

好了我们  gdb comb

设断点:b *0x8048b2c    

查看字符串内容:p (char*) 0x80497c0

出现了!

“Public speaking is very easy.”   ,nice 第一关pass

接着看phase_2

08048b48 <phase_2>:
 8048b48:	55                   	push   %ebp
 8048b49:	89 e5                	mov    %esp,%ebp
 8048b4b:	83 ec 20             	sub    $0x20,%esp
 8048b4e:	56                   	push   %esi
 8048b4f:	53                   	push   %ebx
 8048b50:	8b 55 08             	mov    0x8(%ebp),%edx           ;phase_2的参数

 8048b53:	83 c4 f8             	add    $0xfffffff8,%esp
 8048b56:	8d 45 e8             	lea    -0x18(%ebp),%eax
 8048b59:	50                   	push   %eax                  ;
 8048b5a:	52                   	push   %edx		      ;read_six_numbers的参数
 8048b5b:	e8 78 04 00 00       	call   8048fd8 <read_six_numbers>
 8048b60:	83 c4 10             	add    $0x10,%esp
 8048b63:	83 7d e8 01          	cmpl   $0x1,-0x18(%ebp)                 ;第一个数get  1
 8048b67:	74 05                	je     8048b6e <phase_2+0x26>

 8048b69:	e8 8e 09 00 00       	call   80494fc <explode_bomb>
 8048b6e:	bb 01 00 00 00       	mov    $0x1,%ebx                    ebx为1
 8048b73:	8d 75 e8             	lea    -0x18(%ebp),%esi             esi为第一个数的地址
 8048b76:	8d 43 01             	lea    0x1(%ebx),%eax               eax为2,eax为3
 8048b79:	0f af 44 9e fc       	imul   -0x4(%esi,%ebx,4),%eax        第一个数*eax=2,第二个数*eax=6
 8048b7e:	39 04 9e             	cmp    %eax,(%esi,%ebx,4)               ;第二个数get 2,get 6,阶乘233333
 8048b81:	74 05                	je     8048b88 <phase_2+0x40>
 8048b83:	e8 74 09 00 00       	call   80494fc <explode_bomb>
 8048b88:	43                   	inc    %ebx                         ebx为2
 8048b89:	83 fb 05             	cmp    $0x5,%ebx                    2<5      
 8048b8c:	7e e8                	jle    8048b76 <phase_2+0x2e>
 8048b8e:	8d 65 d8             	lea    -0x28(%ebp),%esp
 8048b91:	5b                   	pop    %ebx
 8048b92:	5e                   	pop    %esi
 8048b93:	89 ec                	mov    %ebp,%esp
 8048b95:	5d                   	pop    %ebp
 8048b96:	c3                   	ret    
 8048b97:	90                   	nop

好了我们来进行分析:

8048b56:	8d 45 e8             	lea    -0x18(%ebp),%eax

注意这一行,这是给局部变量留出来的空间0x18=十进制24阿,正好6个int型整数。

所以read_six_number我们猜测是一个有6个整型元素的数组,并读取6个整数到给定位置中的函数

之后我们要进行的就是让程序的整个流程都不接触到explode_bomb函数

分析每个与cmp有关的函数

第一步观察 

8048b63:	83 7d e8 01          	cmpl   $0x1,-0x18(%ebp)                 

比较1和a[0],我们假定数组名为a,相等可以跳过explode_bomb这一条指令,因此可以确定a[0],继续向下看

很显然这是一个以ebx为迭代量的循环过程

依次判断前一个值*当前迭代下标是否等于后一个值,当迭代量ebx>5的时候就退出循环

否则的话比较A[i]*(ebx+1)是否等于A[i+1],当然ebx是从1开始的

由A[0]=1 推理得到A[6]={1,2,6,24,120,720}

这个 数组就是我们的答案,

做到这里应该已经掌握基本的拆弹套路了,继续看phase_3

08048b98 <phase_3>:
 8048b98:	55                   	push   %ebp
 8048b99:	89 e5                	mov    %esp,%ebp
 8048b9b:	83 ec 14             	sub    $0x14,%esp
 8048b9e:	53                   	push   %ebx
 8048b9f:	8b 55 08             	mov    0x8(%ebp),%edx
 8048ba2:	83 c4 f4             	add    $0xfffffff4,%esp
 8048ba5:	8d 45 fc             	lea    -0x4(%ebp),%eax         一个int
 8048ba8:	50                   	push   %eax
 8048ba9:	8d 45 fb             	lea    -0x5(%ebp),%eax         一个char
 8048bac:	50                   	push   %eax
 8048bad:	8d 45 f4             	lea    -0xc(%ebp),%eax         一个int,3个局部变量作为参数
 8048bb0:	50                   	push   %eax
 8048bb1:	68 de 97 04 08       	push   $0x80497de
 8048bb6:	52                   	push   %edx
 8048bb7:	e8 a4 fc ff ff       	call   8048860 <sscanf@plt>
 8048bbc:	83 c4 20             	add    $0x20,%esp

 8048bbf:	83 f8 02             	cmp    $0x2,%eax                >2  eax一直为3
 8048bc2:	7f 05                	jg     8048bc9 <phase_3+0x31>
 8048bc4:	e8 33 09 00 00       	call   80494fc <explode_bomb>

 8048bc9:	83 7d f4 07          	cmpl   $0x7,-0xc(%ebp)          <=7  第一个数,无符号<=7,只能0,1,2,3,4,5,6,7其中一个
 8048bcd:	0f 87 b5 00 00 00    	ja     8048c88 <phase_3+0xf0>
 8048bd3:	8b 45 f4             	mov    -0xc(%ebp),%eax          第一个数给eax
 8048bd6:	ff 24 85 e8 97 04 08 	jmp    *0x80497e8(,%eax,4)        这个跳到哪里阿。。。0x8048be0+4*eax
 8048bdd:	8d 76 00             	lea    0x0(%esi),%esi
 8048be0:	b3 71                	mov    $0x71,%bl                      跳到这个,第一个数get 0,

 8048be2:	81 7d fc 09 03 00 00 	cmpl   $0x309,-0x4(%ebp)        第三个数get 0x309= 777
 8048be9:	0f 84 a0 00 00 00    	je     8048c8f <phase_3+0xf7>  
 8048bef:	e8 08 09 00 00       	call   80494fc <explode_bomb>

 8048bf4:	e9 96 00 00 00       	jmp    8048c8f <phase_3+0xf7>

 8048bf9:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
 8048c00:	b3 62                	mov    $0x62,%bl
 8048c02:	81 7d fc d6 00 00 00 	cmpl   $0xd6,-0x4(%ebp)
 8048c09:	0f 84 80 00 00 00    	je     8048c8f <phase_3+0xf7>
 8048c0f:	e8 e8 08 00 00       	call   80494fc <explode_bomb>

 8048c14:	eb 79                	jmp    8048c8f <phase_3+0xf7>

 8048c16:	b3 62                	mov    $0x62,%bl
 8048c18:	81 7d fc f3 02 00 00 	cmpl   $0x2f3,-0x4(%ebp)
 8048c1f:	74 6e                	je     8048c8f <phase_3+0xf7>
 8048c21:	e8 d6 08 00 00       	call   80494fc <explode_bomb>

 8048c26:	eb 67                	jmp    8048c8f <phase_3+0xf7>

 8048c28:	b3 6b                	mov    $0x6b,%bl
 8048c2a:	81 7d fc fb 00 00 00 	cmpl   $0xfb,-0x4(%ebp)
 8048c31:	74 5c                	je     8048c8f <phase_3+0xf7>
 8048c33:	e8 c4 08 00 00       	call   80494fc <explode_bomb>

 8048c38:	eb 55                	jmp    8048c8f <phase_3+0xf7>

 8048c3a:	8d b6 00 00 00 00    	lea    0x0(%esi),%esi
 8048c40:	b3 6f                	mov    $0x6f,%bl
 8048c42:	81 7d fc a0 00 00 00 	cmpl   $0xa0,-0x4(%ebp)
 8048c49:	74 44                	je     8048c8f <phase_3+0xf7>
 8048c4b:	e8 ac 08 00 00       	call   80494fc <explode_bomb>

 8048c50:	eb 3d                	jmp    8048c8f <phase_3+0xf7>

 8048c52:	b3 74                	mov    $0x74,%bl
 8048c54:	81 7d fc ca 01 00 00 	cmpl   $0x1ca,-0x4(%ebp)
 8048c5b:	74 32                	je     8048c8f <phase_3+0xf7>
 8048c5d:	e8 9a 08 00 00       	call   80494fc <explode_bomb>

 8048c62:	eb 2b                	jmp    8048c8f <phase_3+0xf7>

 8048c64:	b3 76                	mov    $0x76,%bl
 8048c66:	81 7d fc 0c 03 00 00 	cmpl   $0x30c,-0x4(%ebp)
 8048c6d:	74 20                	je     8048c8f <phase_3+0xf7>
 8048c6f:	e8 88 08 00 00       	call   80494fc <explode_bomb>

 8048c74:	eb 19                	jmp    8048c8f <phase_3+0xf7>

 8048c76:	b3 62                	mov    $0x62,%bl
 8048c78:	81 7d fc 0c 02 00 00 	cmpl   $0x20c,-0x4(%ebp)
 8048c7f:	74 0e                	je     8048c8f <phase_3+0xf7>
 8048c81:	e8 76 08 00 00       	call   80494fc <explode_bomb>

 8048c86:	eb 07                	jmp    8048c8f <phase_3+0xf7>

 8048c88:	b3 78                	mov    $0x78,%bl                  排除
 8048c8a:	e8 6d 08 00 00       	call   80494fc <explode_bomb>

 8048c8f:	3a 5d fb             	cmp    -0x5(%ebp),%bl              第二个数get = 0x71 = 113
 8048c92:	74 05                	je     8048c99 <phase_3+0x101>
 8048c94:	e8 63 08 00 00       	call   80494fc <explode_bomb>

 8048c99:	8b 5d e8             	mov    -0x18(%ebp),%ebx
 8048c9c:	89 ec                	mov    %ebp,%esp
 8048c9e:	5d                   	pop    %ebp
 8048c9f:	c3                   	ret    

观察0x80497de位置的字符串,发现是这样的"%d %c %d",猜测我们的答案肯定是一个整数一个char类型,接着一个整数

分析发现这段代码会根据%eax,即第一个参数的值而跳转到不同的地方,是不是和switch语句很相似呢?

不过这道题好像有多解。。我取了第一个数为0,然后按代码跳转依次得到第二个参数和第三个参数的值。。

为此在断网的情况查看ascii码我居然顺手拿起了谭浩强的C语言。。。

第三题答案

0 q 777

phase_4

08048ce0 <phase_4>:
 8048ce0:	55                   	push   %ebp
 8048ce1:	89 e5                	mov    %esp,%ebp
 8048ce3:	83 ec 18             	sub    $0x18,%esp
 8048ce6:	8b 55 08             	mov    0x8(%ebp),%edx
 8048ce9:	83 c4 fc             	add    $0xfffffffc,%esp
 8048cec:	8d 45 fc             	lea    -0x4(%ebp),%eax
 8048cef:	50                   	push   %eax
 8048cf0:	68 08 98 04 08       	push   $0x8049808
 8048cf5:	52                   	push   %edx
 8048cf6:	e8 65 fb ff ff       	call   8048860 <sscanf@plt>
 8048cfb:	83 c4 10             	add    $0x10,%esp
 8048cfe:	83 f8 01             	cmp    $0x1,%eax                              eax要等于1
 8048d01:	75 06                	jne    8048d09 <phase_4+0x29>
 8048d03:	83 7d fc 00          	cmpl   $0x0,-0x4(%ebp)                第一个数大于0
 8048d07:	7f 05                	jg     8048d0e <phase_4+0x2e>

 8048d09:	e8 ee 07 00 00       	call   80494fc <explode_bomb>

 8048d0e:	83 c4 f4             	add    $0xfffffff4,%esp
 8048d11:	8b 45 fc             	mov    -0x4(%ebp),%eax                  第一个数给eax
 8048d14:	50                   	push   %eax                             eax进栈
 8048d15:	e8 86 ff ff ff       	call   8048ca0 <func4>
 8048d1a:	83 c4 10             	add    $0x10,%esp
 8048d1d:	83 f8 37             	cmp    $0x37,%eax                      f(9)=0x37
 8048d20:	74 05                	je     8048d27 <phase_4+0x47>
 8048d22:	e8 d5 07 00 00       	call   80494fc <explode_bomb>
 8048d27:	89 ec                	mov    %ebp,%esp
 8048d29:	5d                   	pop    %ebp
 8048d2a:	c3                   	ret    
 8048d2b:	90                   	nop

08048ca0 <func4>:
 8048ca0:	55                   	push   %ebp
 8048ca1:	89 e5                	mov    %esp,%ebp
 8048ca3:	83 ec 10             	sub    $0x10,%esp
 8048ca6:	56                   	push   %esi
 8048ca7:	53                   	push   %ebx
 8048ca8:	8b 5d 08             	mov    0x8(%ebp),%ebx                 第一个数给ebx  
 8048cab:	83 fb 01             	cmp    $0x1,%ebx                      ebx<=1  返回
 8048cae:	7e 20                	jle    8048cd0 <func4+0x30>
 8048cb0:	83 c4 f4             	add    $0xfffffff4,%esp
 8048cb3:	8d 43 ff             	lea    -0x1(%ebx),%eax                eax=ebx-1
 8048cb6:	50                   	push   %eax
 8048cb7:	e8 e4 ff ff ff       	call   8048ca0 <func4>
 8048cbc:	89 c6                	mov    %eax,%esi
 8048cbe:	83 c4 f4             	add    $0xfffffff4,%esp
 8048cc1:	8d 43 fe             	lea    -0x2(%ebx),%eax
 8048cc4:	50                   	push   %eax
 8048cc5:	e8 d6 ff ff ff       	call   8048ca0 <func4>
 8048cca:	01 f0                	add    %esi,%eax                       f(n-1)+f(n-2)
 8048ccc:	eb 07                	jmp    8048cd5 <func4+0x35>
 8048cce:	89 f6                	mov    %esi,%esi
 8048cd0:	b8 01 00 00 00       	mov    $0x1,%eax                      f(0)=f(1)=1;
 8048cd5:	8d 65 e8             	lea    -0x18(%ebp),%esp
 8048cd8:	5b                   	pop    %ebx
 8048cd9:	5e                   	pop    %esi
 8048cda:	89 ec                	mov    %ebp,%esp
 8048cdc:	5d                   	pop    %ebp
 8048cdd:	c3                   	ret    
 8048cde:	89 f6                	mov    %esi,%esi

第四个炸弹的关键就是这个func4函数,发现函数中有两次调用了自身,显然是一个递归的过程,每次递归都会把寄存器%eax的值多减少一个1然后push作为参数,返回的时候将返回值存储在%eax中再将两次调用的合相加,因此得到递归公式f(n)=f(n-1)+f(n-2)

最后求f(多少)=0x37,慢慢推到 多少=9,就是最后的答案了

phase_5

08048d2c <phase_5>:
 8048d2c:	55                   	push   %ebp
 8048d2d:	89 e5                	mov    %esp,%ebp
 8048d2f:	83 ec 10             	sub    $0x10,%esp
 8048d32:	56                   	push   %esi
 8048d33:	53                   	push   %ebx
 8048d34:	8b 5d 08             	mov    0x8(%ebp),%ebx
 8048d37:	83 c4 f4             	add    $0xfffffff4,%esp
 8048d3a:	53                   	push   %ebx
 8048d3b:	e8 d8 02 00 00       	call   8049018 <string_length>
 8048d40:	83 c4 10             	add    $0x10,%esp
 8048d43:	83 f8 06             	cmp    $0x6,%eax                        长度为6
 8048d46:	74 05                	je     8048d4d <phase_5+0x21>
 8048d48:	e8 af 07 00 00       	call   80494fc <explode_bomb>
 8048d4d:	31 d2                	xor    %edx,%edx                      edx=0
 8048d4f:	8d 4d f8             	lea    -0x8(%ebp),%ecx
 8048d52:	be 20 b2 04 08       	mov    $0x804b220,%esi                 "isrveawhobpnutfg\260\001"
 8048d57:	8a 04 1a             	mov    (%edx,%ebx,1),%al               ebx是字符数组的首地址,取每个字符char c=a[i]
 8048d5a:	24 0f                	and    $0xf,%al                        c=c&0xf    
 8048d5c:	0f be c0             	movsbl %al,%eax                         
 8048d5f:	8a 04 30             	mov    (%eax,%esi,1),%al               pp[c]=b[a[0]&0xf]  *pp="giants"  
 8048d62:	88 04 0a             	mov    %al,(%edx,%ecx,1)                
 8048d65:	42                   	inc    %edx
 8048d66:	83 fa 05             	cmp    $0x5,%edx                                 for(i=0;i<=5;i++)
 8048d69:	7e ec                	jle    8048d57 <phase_5+0x2b>


 8048d6b:	c6 45 fe 00          	movb   $0x0,-0x2(%ebp)                     
 8048d6f:	83 c4 f8             	add    $0xfffffff8,%esp
 8048d72:	68 0b 98 04 08       	push   $0x804980b                     "giants"
 8048d77:	8d 45 f8             	lea    -0x8(%ebp),%eax
 8048d7a:	50                   	push   %eax
 8048d7b:	e8 b0 02 00 00       	call   8049030 <strings_not_equal>
 8048d80:	83 c4 10             	add    $0x10,%esp
 8048d83:	85 c0                	test   %eax,%eax
 8048d85:	74 05                	je     8048d8c <phase_5+0x60>
 8048d87:	e8 70 07 00 00       	call   80494fc <explode_bomb>
 8048d8c:	8d 65 e8             	lea    -0x18(%ebp),%esp
 8048d8f:	5b                   	pop    %ebx
 8048d90:	5e                   	pop    %esi
 8048d91:	89 ec                	mov    %ebp,%esp
 8048d93:	5d                   	pop    %ebp
 8048d94:	c3                   	ret    
 8048d95:	8d 76 00             	lea    0x0(%esi),%esi

<string_length>规定了字符串长度为6

又出现了strings_not_equal..所以我们找进栈的是什么,发现了一个固定的值0x804980b

p (char *) 0x804980b  之后发现是"giants"字符串

上面还有一个0x804b220,    "isrveawhobpnutfg\260\001"  ,一开始还以为搞错了。弄下去后发现这个字符串非常有用有木有!

又看到了一个以%edx为迭代量的循环,依旧假设我们的字符串为a[i]的形式,迭代中%cl保存了我们输入的字符串中的一个char类型,分析下看到我们的a[i]&0xf变成了那个奇怪的字符串的下标。。。。这个下标形成的新的字符串再去和“giants”比较,相同才能过关,然后按顺序在那个奇怪的字符串中找对应的g,i,a,n,t,s这几个字母。得到以下等式

a[0]&0xf=15   a[1]&0xf=0   a[2]&0xf=5  a[3]&0xf=11   a[4]&0xf=13  a[5]&0xf=1,然后a[0-5]就查ascii表随便取吧

我取了O@EKMA这6个字符。

继续继续

phase_6以及secret_phase

去你妹的!!一个早上+一个下午楞是没看懂 不看了!!

【上篇】
【下篇】

抱歉!评论已关闭.