欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CSAPP:BombLab(深入了解计算机系统配套实验)

程序员文章站 2022-06-07 08:47:55
...

CSAPP:BombLab

新手小白,第一次写博客,算是记录一下做的一些有意思的东西,分享给大家。有一些理解不够深刻,甚至出错的地方,还请大家见谅,并帮我指正,谢谢!
这是一个《深入了解计算机系统》教学的配套实验,肝了一个下午加一整个晚上,总结了一下整个过程。这里我使用的是Ubuntu16.04的虚拟机。

实验原理

通过gdb对二进制文件进行反汇编,阅读相应的汇编代码,并使用gdb进行断点调试和内存读取,从而破译共七个炸弹,包括六个常规炸弹和一个隐藏炸弹。

实验过程

在Ubuntu终端打开gdb,输入命令objdump -d bomb>bomb1.asm,将二进制文件反汇编为汇编代码文件,然后输入gdb ./bomb命令,使用gdb打开二进制文件bomb。这样可以在阅读汇编代码的同时对程序进行调试。
在main函数的汇编代码段中,可以看到分别调用了<phase_1>、<phase_2>、<phase_3>、<phase_4>、<phase_5>、<phase_6>代码段,它们分别对应着各个炸弹的函数。我们只要对这些代码段进行分析就可以找到拆解炸弹的方法。

phase 1

phase 1很简短,其汇编代码:

0000000000400ee0 <phase_1>:
  400ee0:	48 83 ec 08          	sub    $0x8,%rsp
  400ee4:	be 00 24 40 00       	mov    $0x402400,%esi
//%esi中的地址为0x402400
  400ee9:	e8 4a 04 00 00       	callq  401338 <strings_not_equal>
//调用字符串比较,相同则eax为0
  400eee:	85 c0                	test   %eax,%eax
//是否相同
  400ef0:	74 05                	je     400ef7 <phase_1+0x17>
  400ef2:	e8 43 05 00 00       	callq  40143a <explode_bomb>
  400ef7:	48 83 c4 08          	add    $0x8,%rsp
  400efb:	c3                   	retq

其中引用了<strings_not _equal>代码段,从字面上看是比较字符串,其汇编代码如下:

0000000000401338 <strings_not_equal>:
  401338:	41 54                	push   %r12
  40133a:	55                   	push   %rbp
  40133b:	53                   	push   %rbx
  40133c:	48 89 fb             	mov    %rdi,%rbx
//输入内容的地址
  40133f:	48 89 f5             	mov    %rsi,%rbp
//%rbp指向%rsi答案中的内容
  401342:	e8 d4 ff ff ff       	callq  40131b <string_length>
  401347:	41 89 c4             	mov    %eax,%r12d
//输入共多少字符
  40134a:	48 89 ef             	mov    %rbp,%rdi
//答案字符地址
  40134d:	e8 c9 ff ff ff       	callq  40131b <string_length>
  401352:	ba 01 00 00 00       	mov    $0x1,%edx
//标记
  401357:	41 39 c4             	cmp    %eax,%r12d
//比较字符个数
  40135a:	75 3f                	jne    40139b <strings_not_equal+0x63>
  40135c:	0f b6 03             	movzbl (%rbx),%eax
//输入首字符
  40135f:	84 c0                	test   %al,%al
//为空则跳转
  401361:	74 25                	je     401388 <strings_not_equal+0x50>
  401363:	3a 45 00             	cmp    0x0(%rbp),%al
//比较第一个字符
  401366:	74 0a                	je     401372 <strings_not_equal+0x3a>
//一样则跳转(包括都为\0)
  401368:	eb 25                	jmp    40138f <strings_not_equal+0x57>
  40136a:	3a 45 00             	cmp    0x0(%rbp),%al
//比较当前字符
  40136d:	0f 1f 00             	nopl   (%rax)
  401370:	75 24                	jne    401396 <strings_not_equal+0x5e>
  401372:	48 83 c3 01          	add    $0x1,%rbx
//输入指针加一
  401376:	48 83 c5 01          	add    $0x1,%rbp
//答案指针加一
  40137a:	0f b6 03             	movzbl (%rbx),%eax
//使用当前字符
  40137d:	84 c0                	test   %al,%al
//输入内容当前字符是否为\0
  40137f:	75 e9             	jne    40136a <strings_not_equal+0x32>
//不为空则跳转
  401381:	ba 00 00 00 00       	mov    $0x0,%edx
//标记0,输入正确
  401386:	eb 13                	jmp    40139b <strings_not_equal+0x63>
  401388:	ba 00 00 00 00       	mov    $0x0,%edx
  40138d:	eb 0c                	jmp    40139b <strings_not_equal+0x63>
  40138f:	ba 01 00 00 00       	mov    $0x1,%edx
  401394:	eb 05                	jmp    40139b <strings_not_equal+0x63>
  401396:	ba 01 00 00 00       	mov    $0x1,%edx
  40139b:	89 d0                	mov    %edx,%eax
//%eax为0,输入正确
  40139d:	5b                   	pop    %rbx
  40139e:	5d                   	pop    %rbp
  40139f:	41 5c                	pop    %r12
  4013a1:	c3                   	retq

可以看到,<strings_not _equal>代码段是用作字符串的比较的,<phase_1>调用它从而将地址为0x402400的字符串与输入的字符串进行对比。如果相同则进入下一个炸弹的<phase_2>代码段,否则引爆炸弹。使用x/s 0x402400命令读取该地址处的字符串,得到:
CSAPP:BombLab(深入了解计算机系统配套实验)
第一个拆弹密码即为:Border relations with Canada have never been better.

phase 2

phase 2的汇编代码:

0000000000400efc <phase_2>:
  400efc:	55                   	push   %rbp
  400efd:	53                   	push   %rbx
  400efe:	48 83 ec 28        	sub    $0x28,%rsp
  400f02:	48 89 e6          	mov    %rsp,%rsi
  400f05:	e8 52 05 00 00     	callq  40145c <read_six_numbers>
//读六个数据
  400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)
//第一个数和1比较
  400f0e:	74 20                	je     400f30 <phase_2+0x34>
  400f10:	e8 25 05 00 00       	callq  40143a <explode_bomb>
//等于1跳转,否则爆炸
  400f15:	eb 19                	jmp    400f30 <phase_2+0x34>
  400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax
//将rbx-4地址处的值赋给eax
  400f1a:	01 c0                	add    %eax,%eax
//%eax=2*%eax
  400f1c:	39 03                	cmp    %eax,(%rbx)
//比较此时eax和rbx地址处的值。其中eax是ebx-4地址处的值,即将rbx地址处的值和前一个数的两倍比较
  400f1e:	74 05                	je     400f25 <phase_2+0x29>
//相等则跳转至rbx+4地址处
  400f20:	e8 15 05 00 00       	callq  40143a <explode_bomb>
  400f25:	48 83 c3 04          	add    $0x4,%rbx
//rbx+4
  400f29:	48 39 eb             	cmp    %rbp,%rbx
//rbp为六个数的下一个地址,判断是否比较完毕
  400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>
  400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>
  400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx
  400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp
  400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>
  400f3c:	48 83 c4 28          	add    $0x28,%rsp
  400f40:	5b                  	pop    %rbx
  400f41:	5d                  	pop    %rbp
  400f42:	c3                   	retq   

<read_six_numbers>代码段将读到的第一个数字的地址存在%rsp存储的地址中。而第一个数必须是1,根据循环可以知道下一个数是前一个数的两倍。因此,这六个数应该为:1 2 4 8 16 32。

phase 3

phase 3的汇编代码如下:

0000000000400f43 <phase_3>:
  400f43:	48 83 ec 18          	sub    $0x18,%rsp
  400f47:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  400f4c:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <aaa@qq.com>
//读取输入
  400f60:	83 f8 01             	cmp    $0x1,%eax
  400f63:	7f 05                	jg     400f6a <phase_3+0x27>
  400f65:	e8 d0 04 00 00       	callq  40143a <explode_bomb>
  400f6a:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp)
  400f6f:	77 3c                	ja     400fad <phase_3+0x6a>
//如果第一个数大于7,炸弹爆炸
  400f71:	8b 44 24 08          	mov    0x8(%rsp),%eax
  400f75:	ff 24 c5 70 24 40 00 	jmpq   *0x402470(,%rax,8)
  400f7c:	b8 cf 00 00 00       	mov    $0xcf,%eax
  400f81:	eb 3b                	jmp    400fbe <phase_3+0x7b>
  400f83:	b8 c3 02 00 00       	mov    $0x2c3,%eax
  400f88:	eb 34                	jmp    400fbe <phase_3+0x7b>
  400f8a:	b8 00 01 00 00       	mov    $0x100,%eax
  400f8f:	eb 2d                	jmp    400fbe <phase_3+0x7b>
  400f91:	b8 85 01 00 00       	mov    $0x185,%eax
  400f96:	eb 26                	jmp    400fbe <phase_3+0x7b>
  400f98:	b8 ce 00 00 00       	mov    $0xce,%eax
  400f9d:	eb 1f                	jmp    400fbe <phase_3+0x7b>
  400f9f:	b8 aa 02 00 00       	mov    $0x2aa,%eax
  400fa4:	eb 18                	jmp    400fbe <phase_3+0x7b>
  400fa6:	b8 47 01 00 00       	mov    $0x147,%eax
  400fab:	eb 11                	jmp    400fbe <phase_3+0x7b>
  400fad:	e8 88 04 00 00       	callq  40143a <explode_bomb>
  400fb2:	b8 00 00 00 00       	mov    $0x0,%eax
  400fb7:	eb 05                	jmp    400fbe <phase_3+0x7b>
  400fb9:	b8 37 01 00 00       	mov    $0x137,%eax
  400fbe:	3b 44 24 0c          	cmp    0xc(%rsp),%eax
  400fc2:	74 05                	je     400fc9 <phase_3+0x86>
  400fc4:	e8 71 04 00 00       	callq  40143a <explode_bomb>
  400fc9:	48 83 c4 18          	add    $0x18,%rsp
  400fcd:	c3                   	retq

在执行scanf之前,将0x4025cf存储进了esi寄存器中,先来读取一下地址0x4025cf中的内容。
CSAPP:BombLab(深入了解计算机系统配套实验)
可以判断,scanf读取的数据格式为两个整型值。
phase 3的汇编代码中间部分有很多jmp,并且都跟着一个赋值的操作,之后紧接着就与第二个输入的数进行比较。初步判断这是一个switch语句,每一个jmp是一个case。这里一共有七个jmp,并且输入的第一个值不能大于7,说明case语句应该有7条,这进一步验证了这个想法。
选取case 2语句,即第一个数为2,此时对应的第二个数应该为0x2c3,即707。输入2 707,炸弹成功解除。
但后来测试时发现输入1 207(0xcf)并不能成功解除炸弹,但输入0 207可以解除。进一步测试输入1 707仍不能解除炸弹。查找原因,发现没有弄清楚switch语句中跳转表的对应关系。可以看到switch查找表的存储位置为0x402470(jmpq *0x402470(,%rax,8)),使用p/x *0x402470 @16查看跳转表:
CSAPP:BombLab(深入了解计算机系统配套实验)
则对应的关系为:

case标号 跳转地址 %eax
0 0x400f7c 0xcf
1 0x400fb9 0x137
2 0x400f83 0x2c3
3 0x400f8a 0x100
4 0x400f91 0x185
5 0x400f98 0xce
6 0x400f9f 0x2aa
7 0x400fa6 0x147

这便解释了出现不对应现象的原因。

phase 4

phase 4的汇编代码如下:

000000000040100c <phase_4>:
  40100c:	48 83 ec 18          	sub    $0x18,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
//num2
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
//num1
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi
//%d %d
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  401024:	e8 c7 fb ff ff       	callq  400bf0 <aaa@qq.com>
  401029:	83 f8 02             	cmp    $0x2,%eax
  40102c:	75 07            	jne    401035 <phase_4+0x29>
//boom
  40102e:	83 7c 24 08 0e       	cmpl   $0xe,0x8(%rsp)
//num1应小于14
  401033:	76 05                	jbe    40103a <phase_4+0x2e>
  401035:	e8 00 04 00 00       	callq  40143a <explode_bomb>
  40103a:	ba 0e 00 00 00       	mov    $0xe,%edx
//%edx=14
  40103f:	be 00 00 00 00       	mov    $0x0,%esi
//%esi=0
  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi
  401048:	e8 81 ff ff ff          	callq  400fce <func4>
  40104d:	85 c0                	test   %eax,%eax
//func4的输出应为0
  40104f:	75 07                	jne    401058 <phase_4+0x4c>
  401051:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp)
//num2应为0
  401056:	74 05                	je     40105d <phase_4+0x51>
  401058:	e8 dd 03 00 00       	callq  40143a <explode_bomb>
  40105d:	48 83 c4 18          	add    $0x18,%rsp
  401061:	c3                   	retq

与三相同,这里读取的数据格式是两个整型,分别为num1和num2。这里应该引起重视的是代码段,要求其返回值为0。它的三个输入参数分别为%rdx、%edx和%esi,其汇编代码如下:

0000000000400fce <func4>:
  400fce:	48 83 ec 08          	sub    $0x8,%rsp
  400fd2:	89 d0                	mov    %edx,%eax
//x=14(edx) ,y=0(esi)
  400fd4:	29 f0                	sub    %esi,%eax
//x=x-y
  400fd6:	89 c1                	mov    %eax,%ecx
//c=x
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx
//右移31位
  400fdb:	01 c8                	add    %ecx,%eax
  400fdd:	d1 f8                	sar    %eax
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx
  400fe2:	39 f9                	cmp    %edi,%ecx
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401007:	48 83 c4 08          	add    $0x8,%rsp
  40100b:	c3                   	retq

写出对应的C代码:

int fun4(num, p, d)
{
	int a = (d – p + (d >= p) ? 0 : -1) / 2;
	int c = a;
	if (num > c)
	{
		d = c-1;
		int r1 = fun4(num, p, d);
		return r1 * 2;
	}
	else
	{
		if (c == num)
			return 0;
		else
		{
			p = c+1;
			int r2 = fun4(num, p, d);
			return (2 * r2 + 1);
		}
	}
}

要是返回值为0,则应有num=c。输入fun4的值中,num参数为num1,其值小于14;p=0,d=14。满足d>=p,此时相当于c=(d-p)/2=7。因此,num1=7(满足num1<14)。而num2必须为0(cmpl $0x0,0xc(%rsp)),因此第四个炸弹的密码为:7 0。

phase 5

先看phase 5的汇编代码:

0000000000401062 <phase_5>:
  401062:	53                   	push   %rbx
  401063:	48 83 ec 20          	sub    $0x20,%rsp
  401067:	48 89 fb             	mov    %rdi,%rbx
  40106a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  401071:	00 00 
  401073:	48 89 44 24 18       	mov    %rax,0x18(%rsp)
  401078:	31 c0                	xor    %eax,%eax
  40107a:	e8 9c 02 00 00       	callq  40131b <string_length>
  40107f:	83 f8 06             	cmp    $0x6,%eax
//string length=6
  401082:	74 4e                	je     4010d2 <phase_5+0x70>
  401084:	e8 b1 03 00 00       	callq  40143a <explode_bomb>
  401089:	eb 47                	jmp    4010d2 <phase_5+0x70>
  40108b:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx
//读入一个输入字符
  40108f:	88 0c 24             	mov    %cl,(%rsp)
//该输入字符后四位
  401092:	48 8b 14 24          	mov    (%rsp),%rdx
  401096:	83 e2 0f             	and    $0xf,%edx
//%edx=%dl只取后四位
  401099:	0f b6 92 b0 24 40 00 	movzbl 0x4024b0(%rdx),%edx
//maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?
//在这个字符串中用已输入字符的后四位为索引进行查找   9 15 14 5 6 7
  4010a0:	88 54 04 10          	mov    %dl,0x10(%rsp,%rax,1)
//从这里开始存放六个字符
  4010a4:	48 83 c0 01          	add    $0x1,%rax
//index++
  4010a8:	48 83 f8 06          	cmp    $0x6,%rax
//共6个
  4010ac:	75 dd                	jne    40108b <phase_5+0x29>
  4010ae:	c6 44 24 16 00       	movb   $0x0,0x16(%rsp)
  4010b3:	be 5e 24 40 00       	mov    $0x40245e,%esi
//flyers
  4010b8:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  4010bd:	e8 76 02 00 00       	callq  401338 <strings_not_equal>
  4010c2:	85 c0                	test   %eax,%eax
//字符串相同
  4010c4:	74 13                	je     4010d9 <phase_5+0x77>
  4010c6:	e8 6f 03 00 00       	callq  40143a <explode_bomb>
  4010cb:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  4010d0:	eb 07                	jmp    4010d9 <phase_5+0x77>
  4010d2:	b8 00 00 00 00       	mov    $0x0,%eax
  4010d7:	eb b2                	jmp    40108b <phase_5+0x29>
  4010d9:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  4010de:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4010e5:	00 00 
  4010e7:	74 05                	je     4010ee <phase_5+0x8c>
  4010e9:	e8 42 fa ff ff       	callq  400b30 <aaa@qq.com>
  4010ee:	48 83 c4 20          	add    $0x20,%rsp
  4010f2:	5b                   	pop    %rbx
  4010f3:	c3                   	retq

先用x/s指令看看汇编代码中出现的两个地址中存放了什么:
CSAPP:BombLab(深入了解计算机系统配套实验)
语言有些许嘲讽,这个炸弹的密码不是像第一个那样那么简单。但这句话里值得注意的是前面的一些乱码,也许其中有相关信息。
另一个:
CSAPP:BombLab(深入了解计算机系统配套实验)
得到这两个信息后,开始分析汇编代码。代码要求输入共六个字符,然后进入循环,每次取其中的一个字符并依此增加,直到六个字符都被取完。在取得一个字符之后,用这个字符的ASCII码的后四位作为索引,在第一个字符串即maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?中取得相应的字符。由于四位索引是0-16,故这里只能取到前面 的一串乱码maduiersnfotvbyl,正好16个字符,这印证了之前的想法。
在从这些乱码中去除相应字符后,将所有的字符与第二个字符串即flyers进行比较,它们二者应该相同。故可以反推,在乱码中取得字符的索引依次是:9、15、14、5、6、7。对应的二进制码为1001、1111、1110、0101、0110、0111。通过查找ASCII码表,可以确定这样一组字符(答案不唯一):IONUVW。输入后成功拆弹。

phase 6

phase 6的汇编代码为:

00000000004010f4 <phase_6>:
  4010f4:	41 56                	push   %r14
  4010f6:	41 55                	push   %r13
  4010f8:	41 54                	push   %r12
  4010fa:	55                   	push   %rbp
  4010fb:	53                   	push   %rbx
  4010fc:	48 83 ec 50          	sub    $0x50,%rsp
  401100:	49 89 e5             	mov    %rsp,%r13
  401103:	48 89 e6             	mov    %rsp,%rsi
  401106:	e8 51 03 00 00       	callq  40145c <read_six_numbers>
  40110b:	49 89 e6             	mov    %rsp,%r14
  40110e:	41 bc 00 00 00 00    	mov    $0x0,%r12d

  401114:	4c 89 ed             	mov    %r13,%rbp
  401117:	41 8b 45 00          	mov    0x0(%r13),%eax
  40111b:	83 e8 01             	sub    $0x1,%eax
  40111e:	83 f8 05             	cmp    $0x5,%eax
//num<=6
  401121:	76 05                	jbe    401128 <phase_6+0x34>
  401123:	e8 12 03 00 00       	callq  40143a <explode_bomb>
  401128:	41 83 c4 01          	add    $0x1,%r12d
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d
  401130:	74 21                	je     401153 <phase_6+0x5f>
//已读入六个数
  401132:	44 89 e3             	mov    %r12d,%ebx
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  40113b:	39 45 00             	cmp    %eax,0x0(%rbp)
  40113e:	75 05                	jne    401145 <phase_6+0x51>
//相邻两个num不等
  401140:	e8 f5 02 00 00       	callq  40143a <explode_bomb>
  401145:	83 c3 01             	add    $0x1,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>
//六个数字读取完毕
  40114d:	49 83 c5 04          	add    $0x4,%r13
//指向num的指针,依次+4
  401151:	eb c1                	jmp    401114 <phase_6+0x20>


  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi
  401158:	4c 89 f0             	mov    %r14,%rax
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx
  401160:	89 ca                	mov    %ecx,%edx
  401162:	2b 10                	sub    (%rax),%edx
//7-num
  401164:	89 10                	mov    %edx,(%rax)
  401166:	48 83 c0 04          	add    $0x4,%rax
  40116a:	48 39 f0             	cmp    %rsi,%rax
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>
//6个全部循环
  40116f:	be 00 00 00 00       	mov    $0x0,%esi
  401174:	eb 21                	jmp    401197 <phase_6+0xa3>
  401176:	48 8b 52 08          	mov    0x8(%rdx),%rdx   //0x6032d8
  40117a:	83 c0 01             	add    $0x1,%eax
  40117d:	39 c8                	cmp    %ecx,%eax
  40117f:	75 f5                	jne    401176 <phase_6+0x82>
  401181:	eb 05                	jmp    401188 <phase_6+0x94>
  401183:	ba d0 32 60 00       	mov    $0x6032d0,%edx
//L\001
  401188:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:	48 83 c6 04          	add    $0x4,%rsi
  401191:	48 83 fe 18          	cmp    $0x18,%rsi
  401195:	74 14                	je     4011ab <phase_6+0xb7>
//六个比较完毕则跳转
  401197:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx
  40119a:	83 f9 01             	cmp    $0x1,%ecx
  40119d:	7e e4                	jle    401183 <phase_6+0x8f>
  40119f:	b8 01 00 00 00       	mov    $0x1,%eax
  4011a4:	ba d0 32 60 00       	mov    $0x6032d0,%edx
//第一个结点的地址0x6032d0
//L\001
  4011a9:	eb cb                	jmp    401176 <phase_6+0x82>

  4011ab:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx
  4011b0:	48 8d 44 24 28       	lea    0x28(%rsp),%rax
  4011b5:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi
  4011ba:	48 89 d9             	mov    %rbx,%rcx
  4011bd:	48 8b 10             	mov    (%rax),%rdx
  4011c0:	48 89 51 08          	mov    %rdx,0x8(%rcx)
//newN放在(newN-1+8)
  4011c4:	48 83 c0 08          	add    $0x8,%rax
  4011c8:	48 39 f0             	cmp    %rsi,%rax
  4011cb:	74 05                	je     4011d2 <phase_6+0xde>
//六个数处理完毕
  4011cd:	48 89 d1             	mov    %rdx,%rcx
  4011d0:	eb eb                	jmp    4011bd <phase_6+0xc9>

  4011d2:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)
//(new6+8),链表尾指针为空
  4011d9:	00 
  4011da:	bd 05 00 00 00       	mov    $0x5,%ebp
//按照降序重建链表
  4011df:	48 8b 43 08          	mov    0x8(%rbx),%rax
//new2
  4011e3:	8b 00                	mov    (%rax),%eax
  4011e5:	39 03                	cmp    %eax,(%rbx)
//第一个数是否大于第二个数 
  4011e7:	7d 05                	jge    4011ee <phase_6+0xfa>
  4011e9:	e8 4c 02 00 00       	callq  40143a <explode_bomb>
  4011ee:	48 8b 5b 08          	mov    0x8(%rbx),%rbx
  4011f2:	83 ed 01             	sub    $0x1,%ebp
  4011f5:	75 e8                	jne    4011df <phase_6+0xeb>
  4011f7:	48 83 c4 50          	add    $0x50,%rsp
  4011fb:	5b                   	pop    %rbx
  4011fc:	5d                   	pop    %rbp
  4011fd:	41 5c                	pop    %r12
  4011ff:	41 5d                	pop    %r13
  401201:	41 5e                	pop    %r14
  401203:	c3                   	retq

从汇编代码中可以判断,这里访问了一个共有六个元素的链表,链表的首地址为0x6032d0,每个元素共有四个字节。先用p/x *0x6032d0 @24指令看看这个链表里储存的是什么。
CSAPP:BombLab(深入了解计算机系统配套实验)
链表中每个元素共四个字节,前两个字节用于储存数据,第三个字节存放着链表下一个元素的地址,最后一个字节均为0。可以看到第六个元素的地址字节存放的数据为0,说明该链表确实只有六个字节。其中第一个字节为需要排序的数,汇编语言将其从大到小降序排列,重新更改链表顺序,然后再按顺序读取第二个字节的数,与输入进行比较。但是输入的数据在比较之前进行了一步额外的处理,即:若输入的数为num,则将要与链表中的数据进行比较的数为temp=7-num。
由此可知道,重新排序后的链表中第二个字节的数据为:3、4、5、6、1、2。故输入的数应该为:4、3、2、1、6、5。

secret phase

在寻找第三个炸弹密码的那个尚不能解释的现象的原因时发现,在紧跟着<phase_6>后面的代码段之后有一个<secret_phase>代码段,这段代码好像一直没有被运行过。翻看汇编代码发现它也可以跳转至<explode_bomb>使炸弹爆炸。由于并不知道这段代码在哪里被调用,将所有的代码复制到编辑器中,全局查找“secret_phase”字样,发现在<phase_defused>中可以跳转至该代码段,为了找到避免炸弹爆炸的方法,需要进一步找出跳转条件。
CSAPP:BombLab(深入了解计算机系统配套实验)
<phase_defused>代码段如下:

00000000004015c4 <phase_defused>:
  4015c4:	48 83 ec 78          	sub    $0x78,%rsp
  4015c8:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  4015cf:	00 00 
  4015d1:	48 89 44 24 68       	mov    %rax,0x68(%rsp)
  4015d6:	31 c0                	xor    %eax,%eax
  4015d8:	83 3d 81 21 20 00 06 	cmpl   $0x6,0x202181(%rip)        # 603760 <num_input_strings>
//输入的字符串是否是六个
  4015df:	75 5e                	jne    40163f <phase_defused+0x7b>
//不等于则跳转
  4015e1:	4c 8d 44 24 10       	lea    0x10(%rsp),%r8
  4015e6:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  4015eb:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  4015f0:	be 19 26 40 00       	mov    $0x402619,%esi
//%d %d %s
  4015f5:	bf 70 38 60 00       	mov    $0x603870,%edi
//7 0
  4015fa:	e8 f1 f5 ff ff       	callq  400bf0 <aaa@qq.com>
  4015ff:	83 f8 03             	cmp    $0x3,%eax
//输入是否为3个
  401602:	75 31                	jne    401635 <phase_defused+0x71>
//不是则跳转
  401604:	be 22 26 40 00       	mov    $0x402622,%esi
//DrEvil
  401609:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  40160e:	e8 25 fd ff ff       	callq  401338 <strings_not_equal>
  401613:	85 c0                	test   %eax,%eax
//是否相同
  401615:	75 1e                	jne    401635 <phase_defused+0x71>
//不

//相同
  401617:	bf f8 24 40 00       	mov    $0x4024f8,%edi//Curses, you've found the secret phase!
  40161c:	e8 ef f4 ff ff       	callq  400b10 <aaa@qq.com>
  401621:	bf 20 25 40 00       	mov    $0x402520,%edi
//7 0
  401626:	e8 e5 f4 ff ff       	callq  400b10 <aaa@qq.com>
  40162b:	b8 00 00 00 00       	mov    $0x0,%eax
  401630:	e8 0d fc ff ff       	callq  401242 <secret_phase>

  401635:	bf 58 25 40 00       	mov    $0x402558,%edi
  40163a:	e8 d1 f4 ff ff       	callq  400b10 <aaa@qq.com>
  40163f:	48 8b 44 24 68       	mov    0x68(%rsp),%rax
  401644:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  40164b:	00 00 
  40164d:	74 05                	je     401654 <phase_defused+0x90>
  40164f:	e8 dc f4 ff ff       	callq  400b30 <aaa@qq.com>
  401654:	48 83 c4 78          	add    $0x78,%rsp
  401658:	c3                   	retq   
  401659:	90                   	nop
  40165a:	90                   	nop
  40165b:	90                   	nop
  40165c:	90                   	nop
  40165d:	90                   	nop
  40165e:	90                   	nop
  40165f:	90                   	nop

可以看到,<phase_defused>代码段在每次拆解炸弹成功后都被执行,判断是否已经输入了共六个字符串。如果已经输入了六个字符串(说明六个炸弹已经都被成功拆解),就进入代码段的主体部分。
可以看到紧接着,程序又读取了一次字符,但读取后判断是否是三个字符。不是就跳出<phase_defused>,说明这里应该读取共三个字符。但看之前的输入,并没有三个字符的情况。说明如果想打开这个隐藏炸弹的**过程,必须将某一个炸弹的密码改为3个字符(串)。而在<phase_defused>代码段读取这三个字符之前,代码已经设置了字符读取的地址:0x603870(mov $0x603870,%edi),我们在这里设置断点,将之前的正确答案都输入后,使用x/s 0x603870指令看看读取的到底是之前输入的哪一个字符串。
CSAPP:BombLab(深入了解计算机系统配套实验)
由此我们可以判断,需要在第四个炸弹的**密码后添加一个字符(串)才能开启隐藏炸弹。为了知道第三个输入是什么类型,使用x/s 0x402619查看0x402619地址中的内容(mov $0x402619,%esi):
CSAPP:BombLab(深入了解计算机系统配套实验)
第三个输入应为字符串。而接着又进行了一次字符串比较,被比较的字符串的地址位于0x402622,查看0x402622处的内容:
CSAPP:BombLab(深入了解计算机系统配套实验)
在第四个炸弹密码后加入DrEvil后,成功进入隐藏炸弹secret phase:
CSAPP:BombLab(深入了解计算机系统配套实验)
<secret_phase>代码如下:

0000000000401242 <secret_phase>:
  401242:	53                   	push   %rbx
  401243:	e8 56 02 00 00       	callq  40149e <read_line>
  401248:	ba 0a 00 00 00       	mov    $0xa,%edx
  40124d:	be 00 00 00 00       	mov    $0x0,%esi
  401252:	48 89 c7             	mov    %rax,%rdi
  401255:	e8 76 f9 ff ff       	callq  400bd0 <aaa@qq.com>
  40125a:	48 89 c3             	mov    %rax,%rbx
  40125d:	8d 40 ff             	lea    -0x1(%rax),%eax
  401260:	3d e8 03 00 00       	cmp    $0x3e8,%eax
//1000<=%eax
  401265:	76 05                	jbe    40126c <secret_phase+0x2a>
  401267:	e8 ce 01 00 00       	callq  40143a <explode_bomb>
  40126c:	89 de                	mov    %ebx,%esi
  40126e:	bf f0 30 60 00       	mov    $0x6030f0,%edi
//address:0x24 36
  401273:	e8 8c ff ff ff       	callq  401204 <fun7>
  401278:	83 f8 02             	cmp    $0x2,%eax
//return 2
  40127b:	74 05                	je     401282 <secret_phase+0x40>
  40127d:	e8 b8 01 00 00       	callq  40143a <explode_bomb>
  401282:	bf 38 24 40 00       	mov    $0x402438,%edi
  401287:	e8 84 f8 ff ff       	callq  400b10 <aaa@qq.com>
  40128c:	e8 33 03 00 00       	callq  4015c4 <phase_defused>
  401291:	5b                   	pop    %rbx
  401292:	c3                   	retq   
  401293:	90                   	nop
  401294:	90                   	nop
  401295:	90                   	nop
  401296:	90                   	nop
  401297:	90                   	nop
  401298:	90                   	nop
  401299:	90                   	nop
  40129a:	90                   	nop
  40129b:	90                   	nop
  40129c:	90                   	nop
  40129d:	90                   	nop
  40129e:	90                   	nop
  40129f:	90                   	nop

其中代码如下:

0000000000401204 <fun7>:
  401204:	48 83 ec 08          	sub    $0x8,%rsp
  401208:	48 85 ff             	test   %rdi,%rdi
  40120b:	74 2b                	je     401238 <fun7+0x34>
  40120d:	8b 17                	mov    (%rdi),%edx   36
  40120f:	39 f2                	cmp    %esi,%edx
  401211:	7e 0d                	jle    401220 <fun7+0x1c>
  401213:	48 8b 7f 08          	mov    0x8(%rdi),%rdi
  401217:	e8 e8 ff ff ff       	callq  401204 <fun7>
  40121c:	01 c0                	add    %eax,%eax
  40121e:	eb 1d                	jmp    40123d <fun7+0x39>
  401220:	b8 00 00 00 00       	mov    $0x0,%eax
  401225:	39 f2                	cmp    %esi,%edx
  401227:	74 14                	je     40123d <fun7+0x39>
  401229:	48 8b 7f 10          	mov    0x10(%rdi),%rdi
  40122d:	e8 d2 ff ff ff       	callq  401204 <fun7>
  401232:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401236:	eb 05                	jmp    40123d <fun7+0x39>
  401238:	b8 ff ff ff ff       	mov    $0xffffffff,%eax
  40123d:	48 83 c4 08          	add    $0x8,%rsp
  401241:	c3                   	retq

将改写为C代码:

int fun7(num, *p)
{
	int temp = *p;
	if(num < temp)
	{
		p=p + 8;
		int r1 = fun7(num, *p);
		return 2 * r1;
	}
	else
	{
		if(num == temp)
			return 0;
		else
		{
			p = p + 16;
			int r2 = fun7(num, *p);
			return 2 * r2 + 1;
		}
	}
}

要求fun7的返回值为2。fun7递归的底层应该是返回0,我们由此往前推,只有在第三步num==temp返回0,第二步num>temp返回20+1=1,第三部num<temp返回21=2,fun7最终的返回值才为2。也就是说,最开始输入的参数*p所指向的内存中的值应该大于输入的num,内存增加8个字节后其中的值应该小于输入的num,再增加16和字节后其中的值应该等于输入的num。而初次输入的地址的值为:0x6030f0,使用p/x *0x6030f0 @25指令读取包括该地址在内及后续的24个字节的数据,得到:
CSAPP:BombLab(深入了解计算机系统配套实验)
可以看到增加8个字节再增加16个字节后地址中存储的值为0x16即22。若输入的num为22(0x16),0x16<0x24,0x16>0x8,均满足条件,故22应为输入的数字。输入22后,隐藏炸弹也被拆除。
CSAPP:BombLab(深入了解计算机系统配套实验)
至此,所有的炸弹都已被拆除了。

相关标签: 反汇编