jjzjj

《深入理解计算机系统》Lab2-Bomblab

hnu后湖十级爱好者 2023-10-19 原文

前言

这篇文章主要记录了我做bomblab的过程,希望能给你一些灵感


一.实验基本内容与要求

本次实验为熟悉汇编程序及其调试方法的实验。
实验内容包含2个文件:bomb(可执行文件)和bomb.c(c源文件)。
实验主题内容为:
程序运行在linux环境中。程序运行中有6个关卡(6个phase),每个phase需要用户在终端上输入特定的字符或者数字才能通关,否则会引爆炸弹!那么如何才能知道输入什么内容呢?这需要你使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。然后分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符通关。

实验需要用到gdb工具,可到网上查找gdb使用方法和参数。

二.准备工作

1.打开bomb.c文件

发现main函数依次调用了phase_1~phase_6六个函数,但函数的具体代码被隐藏。可以知道从命令行输入的内容必须和phase函数里面的一样,否则炸弹爆炸。

2.反汇编可执行文件bomb

objdump -d bomb > bomb.asm

这样就可以再bomb.asm文件里面看到整个文件(主要是phase函数)的汇编代码啦

3.执行bomb文件

随意输入123,提示爆炸,表示输入错误。接下来就深入各个phase函数去看看怎么拆炸弹吧

三.拆解炸弹

(1)phase_1

1.汇编代码

2.汇编分析

   0x08048b93 <+3>:		movl   $0x804a204,0x4(%esp)  //将地址$0x804a204里面的值传到了esp+4处,疑似参数准备
   0x08048b9b <+11>:	mov    0x20(%esp),%eax
   0x08048b9f <+15>:	mov    %eax,(%esp)  //参数准备:将esp+20里面的值放到栈顶
   0x08048ba2 <+18>:	call   0x80490ca <strings_not_equal> //调用函数,大概可以推测功能是判断字符串是否相等
   0x08048ba7 <+23>:	test   %eax,%eax //判断函数返回值是否为0,并设置标志位zf
   0x08048ba9 <+25>:	je     0x8048bb0 <phase_1+32> //zf=0则跳转,越过调用爆炸函数
   0x08048bab <+27>:	call   0x80491d5 <explode_bomb>
   0x08048bb0 <+32>:	add    $0x1c,%esp

补充:

3.调试

进入函数strings_not_equal看看情况

可以看到phase_1函数给strings_not_equal函数传了两个参数。

故可以确定0x804a204里面的值就是参数

查看,疑似发现第一关密码:And they have no disregard for human life.

4.运行测试


通过第一关啦!

(2)phase_2

1.汇编代码

2.汇编分析

 8048bb9:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048bbd:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048bc1:	8b 44 24 40          	mov    0x40(%esp),%eax //参数准备
 8048bc5:	89 04 24             	mov    %eax,(%esp)  //参数准备
 8048bc8:	e8 2f 06 00 00       	call   80491fc <read_six_numbers> //调用函数,猜测这关要求输入6个数

3.调试

进入read_six_numbers看看

结合函数名以及与5相比较,可以推测这个函数的作用是判断输入数字个数是否为6,即输入应该是6个数字

再继续分析调用完read_six_numbers后的汇编代码

4.继续phase_2汇编分析

 8048bcd:	83 7c 24 18 01       	cmpl   $0x1,0x18(%esp) //比较1和esp+24(第一个数)
 8048bd2:	74 1e                	je     8048bf2 <phase_2+0x3e> //相等则跳转到1
 8048bd4:	e8 fc 05 00 00       	call   80491d5 <explode_bomb> //不相等则爆炸
 8048bd9:	eb 17                	jmp    8048bf2 <phase_2+0x3e>
 //跳转2:8048bdb:	8b 43 fc          mov    -0x4(%ebx),%eax //eax=ebx-4
 8048bde:	01 c0                	add    %eax,%eax  //eax=eax+eax 翻倍
 8048be0:	39 03                	cmp    %eax,(%ebx) //比较
 8048be2:	74 05                	je     8048be9 <phase_2+0x35>//相等则跳转到3
 8048be4:	e8 ec 05 00 00       	call   80491d5 <explode_bomb>//否则爆炸
 //跳转3:8048be9:	83 c3 04          add    $0x4,%ebx //ebx=ebx+4
 8048bec:	39 f3                	cmp    %esi,%ebx  //比较esi和ebx
 8048bee:	75 eb                	jne    8048bdb <phase_2+0x27> //不相等则跳转到2
 8048bf0:	eb 0a                	jmp    8048bfc <phase_2+0x48> //无条件结束
 //跳转1::8048bf2:	8d 5c 24 1c   lea    0x1c(%esp),%ebx //ebx=esp+28
 8048bf6:	8d 74 24 30          	lea    0x30(%esp),%esi //esi=esp+48
 8048bfa:	eb df                	jmp    8048bdb <phase_2+0x27> //跳转到2,执行循环
 8048bfc:	83 c4 34             	add    $0x34,%esp

转换为伪代码

if(esp+24==1) 
{
 ebx=esp+28;
 esi=esp+48;
}

 8048bcd
eax=ebx-4=esp+24;
eax=2*eax //翻倍
if(eax==ebx)
{
ebx=ebx+4=esp+28+4; //下一位
if(esi!=ebx) goto  8048bcd; //(48-28)/4=5 循环5次
else 结束
}
else 爆炸

一开始就和1想比较,相等才继续执行,说明输入的第一个数字是1

分析后面的过程可以知道,这个循环执行了五次,每次把前面的数翻了一倍,如果后一个数不等于前一个数的两倍则爆炸

故第二关的密码是:1 2 4 8 16 32

5.测试运行

顺利通过!

(3)phase_3

1.汇编代码

2.汇编分析

 08048c02 <phase_3>:
 8048c02:	83 ec 3c             	sub    $0x3c,%esp
 8048c05:	8d 44 24 2c          	lea    0x2c(%esp),%eax
 8048c09:	89 44 24 10          	mov    %eax,0x10(%esp) //esp+10=esp+2c
 8048c0d:	8d 44 24 27          	lea    0x27(%esp),%eax
 8048c11:	89 44 24 0c          	mov    %eax,0xc(%esp) //esp+c=esp+27
 8048c15:	8d 44 24 28          	lea    0x28(%esp),%eax
 8048c19:	89 44 24 08          	mov    %eax,0x8(%esp)  //esp+8=esp+28
 8048c1d:	c7 44 24 04 56 a2 04 	movl   $0x804a256,0x4(%esp) //esp+4=0x804a256里存的值
 8048c24:	08 
 8048c25:	8b 44 24 40          	mov    0x40(%esp),%eax 
 8048c29:	89 04 24             	mov    %eax,(%esp)  //esp=esp+40
 8048c2c:	e8 2f fc ff ff       	call   8048860 <__isoc99_sscanf@plt>
 8048c31:	83 f8 02             	cmp    $0x2,%eax
 8048c34:	7f 05                	jg     8048c3b <phase_3+0x39> //函数返回值>2则跳转到1
 8048c36:	e8 9a 05 00 00       	call   80491d5 <explode_bomb>//否则爆炸
 
 

可以确定输入为:整数+字符+整数

再看isoc99_sscanf@plt函数返回值需要大于2才不会引发爆炸,故推测isoc99_sscanf@plt函数的功能就是判断输入字符/数字个数是否符合要求

 跳转1:8048c3b:	83 7c 24 28 07       	cmpl   $0x7,0x28(%esp)
 8048c40:	0f 87 fc 00 00 00    	ja     8048d42 <phase_3+0x140> //esp+28>7,则跳转到2爆炸
 8048c46:	8b 44 24 28          	mov    0x28(%esp),%eax
 8048c4a:	ff 24 85 60 a2 04 08 	jmp    *0x804a260(,%eax,4)//switch语句 
 跳转表 *0x804a260 + 4 * %eax   *0x804a260 = 0x0804c51 
   

由cmpl $0x7,0x28(%esp) 可知输入的i的一个数要小于7,由ja可知这是一个无符号数,故第一个数的范围是[0,7].

读取0x804a260里面的内容,可知当eax=0时就是跳转到了下一行继续执行。 对应汇编指令为mov $0x69,所以第二个ascll码为0x69,即字符’i’ . 下一条汇编语句为cmpl $0x358,0x2c(%esp),所以第三个数为0x358,即856

故答案应该为:0 i 856

 8048c51:	b8 69 00 00 00       	mov    $0x69,%eax
 8048c56:	81 7c 24 2c 58 03 00 	cmpl   $0x358,0x2c(%esp) 
 8048c5d:	00 
 8048c5e:	0f 84 e8 00 00 00    	je     8048d4c <phase_3+0x14a> //esp+2c=0x358,则跳转到3
 8048c64:	e8 6c 05 00 00       	call   80491d5 <explode_bomb>
...
 跳转3:8048d4c:	3a 44 24 27          	cmp    0x27(%esp),%al 
 8048d50:	74 05                	je     8048d57 <phase_3+0x155> //al=esp+27 则结束
 8048d52:	e8 7e 04 00 00       	call   80491d5 <explode_bomb>
 8048d57:	83 c4 3c             	add    $0x3c,%esp
 8048d5a:	c3                   	ret  

5.测试运行

(4)phase_4

1.汇编代码

2.汇编分析

08048da5 <phase_4>:
 8048da5:	83 ec 2c             	sub    $0x2c,%esp
 8048da8:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048dac:	89 44 24 0c          	mov    %eax,0xc(%esp) //esp+c=esp+18(输入2)
 8048db0:	8d 44 24 1c          	lea    0x1c(%esp),%eax
 8048db4:	89 44 24 08          	mov    %eax,0x8(%esp) //esp+8=esp+1c(输入1)
 8048db8:	c7 44 24 04 cf a3 04 	movl   $0x804a3cf,0x4(%esp) //esp+4=0x804a3cf的值
 8048dbf:	08 
 8048dc0:	8b 44 24 30          	mov    0x30(%esp),%eax
 8048dc4:	89 04 24             	mov    %eax,(%esp) //esp=esp+30
 8048dc7:	e8 94 fa ff ff       	call   8048860 <__isoc99_sscanf@plt> //和上一题相同 函数作用是判断输入个数
 8048dcc:	83 f8 02             	cmp    $0x2,%eax 
 8048dcf:	75 0c                	jne    8048ddd <phase_4+0x38>//返回值!=2则跳转到1 爆炸
 8048dd1:	8b 44 24 18          	mov    0x18(%esp),%eax //eax=esp+18(输入2)
 8048dd5:	83 e8 02             	sub    $0x2,%eax  //eax=eax-2
 8048dd8:	83 f8 02             	cmp    $0x2,%eax
 8048ddb:	76 05                	jbe    8048de2 <phase_4+0x3d>//eax<=2则跳转到2,否则爆炸
 //跳转1:8048ddd:	e8 f3 03 00 00    call   80491d5 <explode_bomb>
 //跳转2:8048de2:	8b 44 24 18       mov    0x18(%esp),%eax //eax=esp+18
 8048de6:	89 44 24 04          	mov    %eax,0x4(%esp) //esp+4=esp+18(输入2)
 8048dea:	c7 04 24 07 00 00 00 	movl   $0x7,(%esp) //esp=7
 8048df1:	e8 65 ff ff ff       	call   8048d5b <func4> //func4(7,输入2)
 8048df6:	3b 44 24 1c          	cmp    0x1c(%esp),%eax /比较返回值和esp+1c(输入1)
 8048dfa:	74 05                	je     8048e01 <phase_4+0x5c> //相等则结束
 8048dfc:	e8 d4 03 00 00       	call   80491d5 <explode_bomb>
 8048e01:	83 c4 2c             	add    $0x2c,%esp
 8048e04:	c3                   	ret    


3.调试


可知,输入为两个整数

输入2-2<=2,故输入2<=4,又因为使用jbe,说明是无符号数,故输入2>=2.故输入2的范围是[2,3,4]

深入func4看看情况


可以知道 edi=0,esi=0

(gdb) disas func4
Dump of assembler code for function func4:
   0x08048d5b <+0>:	push   %edi
   0x08048d5c <+1>:	push   %esi
   0x08048d5d <+2>:	push   %ebx
   0x08048d5e <+3>:	sub    $0x10,%esp
   0x08048d61 <+6>:	mov    0x20(%esp),%ebx //ebx=7
   0x08048d65 <+10>:	mov    0x24(%esp),%esi //esi=输入2=3
   0x08048d69 <+14>:	test   %ebx,%ebx  //判断ebx是否为0,并设置标志位zf,返回0
   0x08048d6b <+16>:	jle    0x8048d99 <func4+62> //ebx为0 则跳转到1
   0x08048d6d <+18>:	mov    %esi,%eax //eax=esi=3
   0x08048d6f <+20>:	cmp    $0x1,%ebx 
   0x08048d72 <+23>:	je     0x8048d9e <func4+67>//ebx=1则跳转到2 函数返回esi(第二个输入)
   0x08048d74 <+25>:	mov    %esi,0x4(%esp) esp+4=esi=输入2=3
   0x08048d78 <+29>:	lea    -0x1(%ebx),%eax eax=6
   0x08048d7b <+32>:	mov    %eax,(%esp) esp=6
   0x08048d7e <+35>:	call   0x8048d5b <func4> //递归调用func(6,3)=60
   0x08048d83 <+40>:	lea    (%eax,%esi,1),%edi //edi=eax+esi=63
   0x08048d86 <+43>:	mov    %esi,0x4(%esp) //esp+4=esi
   0x08048d8a <+47>:	sub    $0x2,%ebx //ebx=ebx-2=5
   0x08048d8d <+50>:	mov    %ebx,(%esp) esp=5
   0x08048d90 <+53>:	call   0x8048d5b <func4>  //func4(5,3)=36
   0x08048d95 <+58>:	add    %edi,%eax //eax=eax+edi=99
   0x08048d97 <+60>:	jmp    0x8048d9e <func4+67>
   跳转1:0x08048d99 <+62>:	mov    $0x0,%eax //设置返回值为0
   跳转2:0x08048d9e <+67>:	add    $0x10,%esp //结束
   0x08048da1 <+70>:	pop    %ebx
   0x08048da2 <+71>:	pop    %esi
   0x08048da3 <+72>:	pop    %edi
   0x08048da4 <+73>:	ret    

ps:上面//后的具体数值都是单步调试查看寄存器和内存地址所得

转换位伪代码

func4(int a,int b)
{
	if(a==0) return 0;
	if(a==1) return b;
	a=a-2;
	return func4(a-1,7)+func(a-2,esi);
}

phase_4中调用:func4(7,第二个输入)

当第二个输入为3时,返回值为99,故其中一个答案为:99 3(还有另外两个答案 x 2,x 4)

5.测试运行

(5)phase_5

1.汇编代码

2.汇编分析

   Dump of assembler code for function phase_5:
   0x08048e05 <+0>:	    sub    $0x2c,%esp
   0x08048e08 <+3>:	    lea    0x1c(%esp),%eax
   0x08048e0c <+7>:	    mov    %eax,0xc(%esp) //esp+c=esp+1c
   0x08048e10 <+11>:	lea    0x18(%esp),%eax
   0x08048e14 <+15>:	mov    %eax,0x8(%esp)  //esp+8=esp+18
   0x08048e18 <+19>:	movl   $0x804a3cf,0x4(%esp)  //esp+4=0x804a3cf的值
   0x08048e20 <+27>:	mov    0x30(%esp),%eax  
   0x08048e24 <+31>:	mov    %eax,(%esp)  //esp=esp+30(输入)
   0x08048e27 <+34>:	call   0x8048860 <__isoc99_sscanf@plt> //判断输入数字个数
   0x08048e2c <+39>:	cmp    $0x1,%eax
   0x08048e2f <+42>:	jg     0x8048e36 <phase_5+49>
   0x08048e31 <+44>:	call   0x80491d5 <explode_bomb>
   0x08048e36 <+49>:	mov    0x18(%esp),%eax //eax=esp+18(输入1)
   0x08048e3a <+53>:	and    $0xf,%eax  //eax&11111111 只保留后4位二进制数值
   0x08048e3d <+56>:	mov    %eax,0x18(%esp) //esp+18=eax=清除后的结果
   0x08048e41 <+60>:	cmp    $0xf,%eax
   0x08048e44 <+63>:	je     0x8048e70 <phase_5+107> //eax=f(全1)则跳转到1爆炸
   0x08048e46 <+65>:	mov    $0x0,%ecx //ecx=0
   0x08048e4b <+70>:	mov    $0x0,%edx //edx=0
   //跳转2:0x08048e50 <+75>:	add    $0x1,%edx  //edx=edx+1;
   0x08048e53 <+78>:	mov    0x804a280(,%eax,4),%eax //eax=804a280+4*eax里的值
   0x08048e5a <+85>:	add    %eax,%ecx //ecx=ecx+eax;
   0x08048e5c <+87>:	cmp    $0xf,%eax 
   0x08048e5f <+90>:	jne    0x8048e50 <phase_5+75> //eax!=f则跳转到2 while循环
   0x08048e61 <+92>:	mov    %eax,0x18(%esp) //esp+18=f
   0x08048e65 <+96>:	cmp    $0xf,%edx
   0x08048e68 <+99>:	jne    0x8048e70 <phase_5+107> //edx!=f则跳转到1爆炸
   0x08048e6a <+101>:	cmp    0x1c(%esp),%ecx
   0x08048e6e <+105>:	je     0x8048e75 <phase_5+112> //ecx=esp+1c=输入2则拆弹成功
   //跳转1:0x08048e70 <+107>:	call   0x80491d5 <explode_bomb>
   0x08048e75 <+112>:	add    $0x2c,%esp
   0x08048e78 <+115>:	ret 


3.调试


可知:输入为两个整数

输入1不能为15也不能为0xnnnnnnnf

这一段的伪代码为

ecx=0;
edx=0;
while(eax!=f)
{
edx++;
eax=0x804a280+4*eax //eax=a[eax]
ecx=ecx+eax
}
esp+18=f;
if(edx!=f) 爆炸

可知,while需要执行15次,才能不引起爆炸

查看0x804a280处的值,可以发现,这是一个数组。a[6]=f

逆推15次得到第一个输入的值

次数eax
156
1414
132
121
1110
100
98
84
79
613
511
47
33
212
15

故第一个输入可以为5. ecx的值为所有的eax累加

可以得知,第二个输入的值要等于此时%ecx里面的值,才能成功破解密码

输入:5,3.进行单步调试,看看此时%ecx值值为多少

故答案应该为:5,115

4测试运行

成功

(6)phase_6

1.汇编代码

Dump of assembler code for function phase_6:
=> 0x08048e79 <+0>:	push   %esi
   0x08048e7a <+1>:	push   %ebx
   0x08048e7b <+2>:	sub    $0x44,%esp
   0x08048e7e <+5>:	lea    0x10(%esp),%eax
   0x08048e82 <+9>:	mov    %eax,0x4(%esp) //esp+4=esp+10
   0x08048e86 <+13>:	mov    0x50(%esp),%eax
   0x08048e8a <+17>:	mov    %eax,(%esp) //esp=esp+50(输入数组a的首地址)
   0x08048e8d <+20>:	call   0x80491fc <read_six_numbers>
   0x08048e92 <+25>:	mov    $0x0,%esi //esi=0
   //跳转4:0x08048e97 <+30>:	mov    0x10(%esp,%esi,4),%eax //eax=(esp+esi*4)+10(a[esi])
   0x08048e9b <+34>:	sub    $0x1,%eax //eax=eax-1
   0x08048e9e <+37>:	cmp    $0x5,%eax 
   0x08048ea1 <+40>:	jbe    0x8048ea8 <phase_6+47> //0<=eax<=5则跳转到1(无符号数)
   0x08048ea3 <+42>:	call   0x80491d5 <explode_bomb>
   //跳转1:0x08048ea8 <+47>:	add    $0x1,%esi //esi=esi+1=1
   0x08048eab <+50>:	cmp    $0x6,%esi  
   0x08048eae <+53>:	je     0x8048ecb <phase_6+82> //esi=6则跳转到2
   0x08048eb0 <+55>:	mov    %esi,%ebx  //ebx=esi
   //跳转3:0x08048eb2 <+57>:	mov    0x10(%esp,%ebx,4),%eax //eax=a[ebx]
   0x08048eb6 <+61>:	cmp    %eax,0xc(%esp,%esi,4)   
   0x08048eba <+65>:	jne    0x8048ec1 <phase_6+72>  //a[esi+1]!=a[ebx] 则跳转到5,否则爆炸
   0x08048ebc <+67>:	call   0x80491d5 <explode_bomb>
   //跳转5:0x08048ec1 <+72>:	add    $0x1,%ebx //ebx=ebx+1
   0x08048ec4 <+75>:	cmp    $0x5,%ebx
   0x08048ec7 <+78>:	jle    0x8048eb2 <phase_6+57> //0<=ebx<=5 则跳转到3
   0x08048ec9 <+80>:	jmp    0x8048e97 <phase_6+30> //无条件跳转到4
    //阶段1:利用2层for玄幻,保证任意两个相邻数都不相等,且输入的每个元素都属于[1,6] 
    
   //跳转2:0x08048ecb <+82>:	lea    0x10(%esp),%eax //eax=esp+10=a[0]
   0x08048ecf <+86>:	lea    0x28(%esp),%ebx  //ebx=esp+28
   0x08048ed3 <+90>:	mov    $0x7,%ecx       //ecx=7
   //跳转6:0x08048ed8 <+95>:	mov    %ecx,%edx       //edx=ecx=7
   0x08048eda <+97>:	sub    (%eax),%edx     //edx=edx-(eax)=7-(eax)
   0x08048edc <+99>:	mov    %edx,(%eax)		//(eax)=edx=7-(eax)=7-输入1
   0x08048ede <+101>:	add    $0x4,%eax       //eax=eax+4
   0x08048ee1 <+104>:	cmp    %ebx,%eax       
   0x08048ee3 <+106>:	jne    0x8048ed8 <phase_6+95> //eax!=ebx则跳转到6
 //遍历修改输入的每一个数  使得a[i]=7-a[i];
   
   0x08048ee5 <+108>:	mov    $0x0,%ebx   //ebx=0
   0x08048eea <+113>:	jmp    0x8048f09 <phase_6+144> //跳转1
   //跳转3:0x08048eec <+115>:	mov    0x8(%edx),%edx //edx=edx+8
   0x08048eef <+118>:	add    $0x1,%eax //eax++
   0x08048ef2 <+121>:	cmp    %ecx,%eax
   0x08048ef4 <+123>:	jne    0x8048eec <phase_6+115> //eax!=ecx跳转到3
   0x08048ef6 <+125>:	jmp    0x8048efd <phase_6+132> //跳转到4 
   //跳转2:0x08048ef8 <+127>:	mov    $0x804c13c,%edx //edx=链表第一个值
   //跳转4:0x08048efd <+132>:	mov    %edx,0x28(%esp,%esi,4) 
   0x08048f01 <+136>:	add    $0x1,%ebx //ebx++
---Type <return> to continue, or q <return> to quit---
   0x08048f04 <+139>:	cmp    $0x6,%ebx 
   0x08048f07 <+142>:	je     0x8048f20 <phase_6+167> ebx=6则跳转到5
   //跳转1:0x08048f09 <+144>:	mov    %ebx,%esi //esi=ebx=0
   0x08048f0b <+146>:	mov    0x10(%esp,%ebx,4),%ecx //ecx=a[ebx]=a[0]
   0x08048f0f <+150>:	cmp    $0x1,%ecx 
   0x08048f12 <+153>:	jle    0x8048ef8 <phase_6+127> //0<=a[ebx]<=1则跳转到2
   0x08048f14 <+155>:	mov    $0x1,%eax //eax=1
   0x08048f19 <+160>:	mov    $0x804c13c,%edx //经查看,此处存了一个链表
   0x08048f1e <+165>:	jmp    0x8048eec <phase_6+115> //跳转到3
   阶段2:仍然是一个两层循环,目的在于将我们从链表中取到的结点地址放入栈中保存
   
   跳转5:0x08048f20 <+167>:	mov    0x28(%esp),%ebx //ebx=esp+28(第一个节点地址)
   0x08048f24 <+171>:	lea    0x2c(%esp),%eax  //eax=esp+2c(第二个节点地址)
   0x08048f28 <+175>:	lea    0x40(%esp),%esi  //esi=esp+40 用于链表越界检查
   0x08048f2c <+179>:	mov    %ebx,%ecx //ecx=ebx(第一个节点地址)
   0x08048f2e <+181>:	mov    (%eax),%edx //edx=第二个节点
   0x08048f30 <+183>:	mov    %edx,0x8(%ecx) ecx+8=edx
   0x08048f33 <+186>:	add    $0x4,%eax eax=eax+4 //用于找下一个节点
   0x08048f36 <+189>:	cmp    %esi,%eax 
   0x08048f38 <+191>:	je     0x8048f3e <phase_6+197>
   0x08048f3a <+193>:	mov    %edx,%ecx //
   0x08048f3c <+195>:	jmp    0x8048f2e <phase_6+181>
   阶段3:经过循环 六个结点又依此串联重组起来
   
   0x08048f3e <+197>:	movl   $0x0,0x8(%edx)
   0x08048f45 <+204>:	mov    $0x5,%esi
   0x08048f4a <+209>:	mov    0x8(%ebx),%eax
   0x08048f4d <+212>:	mov    (%eax),%eax
   0x08048f4f <+214>:	cmp    %eax,(%ebx)
   0x08048f51 <+216>:	jge    0x8048f58 <phase_6+223> //前一个节点》>=后一个节点 则不爆炸
   0x08048f53 <+218>:	call   0x80491d5 <explode_bomb>
   0x08048f58 <+223>:	mov    0x8(%ebx),%ebx
   0x08048f5b <+226>:	sub    $0x1,%esi
   0x08048f5e <+229>:	jne    0x8048f4a <phase_6+209>
   阶段4:判断结点保存的六个数中相邻的数是不是都比后面一个数大,也就是非递增的
   
   0x08048f60 <+231>:	add    $0x44,%esp
   0x08048f63 <+234>:	pop    %ebx
   0x08048f64 <+235>:	pop    %esi
   0x08048f65 <+236>:	ret    
End of assembler dump.


2.分段分析


调用了phase_2使用过的read_six_numbers函数,可知输入为6个数字


0<=a[0]-1<=5 故:1<=a[0]<=6,后面又发生了循环,可以知道输入的每个数都属于[0,6]

双层for循环,任意两个数不相等


发现了一个链表

分析完阶段4,去看节点里面都存了些什么值

node1-node6:275->39d->301->1c4->27e->30c

故应依次取:2,6,3,5,1,4个节点

又因为:

故答案为:5,1,4,2,6,3

4.测试运行

终于做完全部了 第6个好难555

四.答案

phase_1And they have no disregard for human life.
phase_21 2 4 8 16 32
phase_30 i 856
phase_499 3
phase_55 115
phase_65 1 4 2 6 3

尾言

初识汇编,被各种循环折磨得头晕目眩
如果发现文章有问题,拜请指正

最后,想对做这个实验的你说:看晕了就歇歇再看,保持头脑清醒,坚持就是胜利

有关《深入理解计算机系统》Lab2-Bomblab的更多相关文章

  1. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  2. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  3. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  4. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  5. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  6. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  7. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  10. ruby - 使用 Ruby,计算 n x m 数组的每一列中有多少个 true 的简单方法是什么? - 2

    给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in

随机推荐