Bomb Lab实验报告.docx
《Bomb Lab实验报告.docx》由会员分享,可在线阅读,更多相关《Bomb Lab实验报告.docx(22页珍藏版)》请在冰豆网上搜索。
BombLab实验报告
课程实验报告
课程名称:
计算机系统原理实验
实验名称:
BombLab
专业班级:
姓名:
学号:
完成时间:
2017.4.19
1、实验目的
熟悉汇编程序,学习gdb调试工具,熟悉并掌握函数调用过程中的栈帧结构的变化。
2、实验环境
个人PC,Linux发行版本,终端,gdb调试工具。
3、实验要求
1.本次实验为熟悉汇编程序及其调试方法的实验。
2.实验内容包含2个文件bomb(可执行文件)和bomb.c(c源文件)。
3.使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。
4.分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符通关。
5.本实验一共有7个关卡,包括6个普通关卡和1个隐藏关卡。
要求至少通过6个普通关卡。
4、实验内容及操作步骤
(1)准备过程
1.解压文件夹得到“bomb”,“bomb.c”,“README-bomblab.txt”以及“实验基本内容与要求.txt”等文档。
查看“实验基本内容与要求.txt”了解实验内容与要求后打开bomb.c文件,编译发现不能通过,代码不完整,所以bomb.c文件只能用来作为参考。
查看bomb.c文件发现控制密码正确的6个函数分别为phase_1,phase_2,phase_3,phase_4,phase_5,phase_6,因此可以对bomb文件反汇编得到汇编文本,结合汇编文本与bomb.c文本进一步分析。
2.进入Ubuntu,将bom和bomb.c文档复制到主文件目录下,ctrl+alt+t打开终端,通过“objdump-dbomb>bomb.s”命令将可执行文件反汇编成bomb.s文件,并且可以通过“gdb-qbomb”进行调试。
3.将bomb.c复制成文本后打开bomb.c查看汇编代码并进一步分析。
(2)关卡分析
1.phase_1
phase_1汇编代码及注释如下:
08048f61:
8048f61:
55push%ebp
8048f62:
89e5mov%esp,%ebp
8048f64:
83ec18sub$0x18,%esp#开辟一个24位的栈空间
8048f67:
c74424045ca104movl$0x804a15c,0x4(%esp)#将0x804a15c存到%eap+4的位置,x/s0x804a15c得到"WehavetostandwithourNorthKoreanallies."
8048f6e:
08
8048f6f:
8b4508mov0x8(%ebp),%eax
8048f72:
890424mov%eax,(%esp)#将%ebp+8处的值存到%esp
8048f75:
e831000000call8048fab
8048f7a:
85c0test%eax,%eax
8048f7c:
7405je8048f83#%eax=0则跳出函数,否则跳到爆炸函数,可以看出,调用函数后如果两个字符串相等的话最后%eax会等于0
8048f7e:
e84e010000call80490d1
8048f83:
c9leave
8048f84:
c3ret
8048f85:
90nop
8048f86:
90nop
8048f87:
90nop
8048f88:
90nop
8048f89:
90nop
8048f8a:
90nop
8048f8b:
90nop
8048f8c:
90nop
8048f8d:
90nop
8048f8e:
90nop
8048f8f:
90nop
思路与分析:
通过call8048fab我们可以推断要求输入的是一串字符串,movl$0x804a15c,0x4(%esp)将地址0x804a15c存到%esp+4的位置,mov0x8(%ebp),%eax和mov%eax,(%esp)将输入的字符串存到%esp中,call8048fab调用字符串比较函数,通过比较上面位置参数%esp+4与%esp对应的字符串是否相等,将返回值存到%eax中,test%eax,%eax,je8048f83,call80490d1,判断如果两个字符串不相等则爆炸。
由上面分析可知地址0x804a15c中存着正确的字符串,我们只要输入相同的字符串就可以通过关卡。
进入gdb,通过命令x/s0x804a15c查看该字符串为:
"WehavetostandwithourNorthKoreanallies."
所以phase_1的通关密码为:
"WehavetostandwithourNorthKoreanallies."通过r命令运行程序,输入该字符串则通过第一关:
结论与心得:
通过分析汇编代码,通过字符串比较函数可以推测输入的是一串字符串,通过x/s以字符串的形式查看地址0x804a15c所对应的值,运行程序后输入该字符串即可通过关卡。
字符串比较函数主要是通过将两个字符串进行比较,将结果存到%eax中,最后判断%eax的值。
第一关相对比较简单,也比较好理解。
2.phase_2
phase_2汇编代码及注释如下:
08048d6a:
8048d6a:
55push%ebp
8048d6b:
89e5mov%esp,%ebp
8048d6d:
56push%esi
8048d6e:
53push%ebx
8048d6f:
83ec30sub$0x30,%esp
8048d72:
8d45e0lea-0x20(%ebp),%eax
8048d75:
89442404mov%eax,0x4(%esp)#将第一个数字的地址放到%esp+4的位置
8048d79:
8b4508mov0x8(%ebp),%eax
8048d7c:
890424mov%eax,(%esp)
8048d7f:
e887030000call804910b#读取六个数字
8048d84:
837de000cmpl$0x0,-0x20(%ebp)
8048d88:
7506jne8048d90#0和-0x20(%ebp)比较,不相等就爆炸
8048d8a:
837de401cmpl$0x1,-0x1c(%ebp)
8048d8e:
7405je8048d95#1和-0x1c(%ebp)比较,相等就跳过爆炸
8048d90:
e83c030000call80490d1
8048d95:
8d5de8lea-0x18(%ebp),%ebx#将第三个数字的地址传到%ebx中,即现在%ebx中存着第三个数字的地址
8048d98:
8d75f8lea-0x8(%ebp),%esi#将%ebx的地址传到%esi,%esi用于待会的判断结束条件,%ebx存的地址一直循环加4,循环直到%ebx的下一个地址是%esi就结束】
8048d9b:
8b43fcmov-0x4(%ebx),%eax#将第二个数放到%eax寄存器中
8048d9e:
0343f8add-0x8(%ebx),%eax#计算第二个数和第一个数的和
8048da1:
3903cmp%eax,(%ebx)
8048da3:
7405je8048daa#前两个数的和与第三个数相比较,相等则跳过炸弹
8048da5:
e827030000call80490d1
8048daa:
83c304add$0x4,%ebx#将%ebx的地址加4,现在%ebx中存着第四个数字的地址
8048dad:
39f3cmp%esi,%ebx
8048daf:
75eajne8048d9b#比较现在%esi和%ebx里面的值是否相等,不相等则循环,否则结束。
其实两个寄存器中存的都是地址,为的是保证只输入6个数,因为当输入第7个数时,%ebx=%esi
8048db1:
83c430add$0x30,%esp
8048db4:
5bpop%ebx
8048db5:
5epop%esi
8048db6:
5dpop%ebp#释放栈帧
8048db7:
c3ret
思路与分析:
通过call804910b我们可以推断出应该是要输入6个数字。
通过对汇编代码进行分析知道-0x20(%ebp)存着第一个数字,-0x1c(%ebp)存着第二个数字,依次类推。
通过cmpl$0x0,-0x20(%ebp),jne8048d90和cmpl$0x1,-0x1c(%ebp),je8048d95知道第一个数字必须是0,第二个数字必须是1,否则就爆炸。
命令lea-0x18(%ebp),%ebx初始化寄存器%ebx的值,将第三个数字的地址传到%ebx中.lea-0x8(%ebp),%esi将%ebx的地址传到%esi,%esi用于待会的判断结束条件,%ebx存的地址一直循环加4,循环直到%ebx的下一个地址是%esi就结束,mov-0x4(%ebx),%eax将第二个数放到%eax寄存器中,add-0x8(%ebx),%eax计算第二个数和第一个数的和,cmp%eax,(%ebx),je8048daa前两个数的和与第三个数相比较,相等则跳过炸弹。
add$0x4,%ebx将%ebx的地址加4,现在%ebx中存着第四个数字的地址,之后%ebx一直加4,知道循环完6个数字。
通过上面的分析知道,输入的前两个数字为0和1,后面的数字等于前面两个数字的和。
所以,这六个数字为Fibonacci数列的前六项。
为011235。
输入这6个数字可通过phase_2.
结论与心得:
第二关需要弄懂栈帧结构的变化,通过add$0x4,%ebx将%ebx的地址加4,然后判断前两个数字的和与当前位置的数是否相等。
结合第一个和第二个数字是0和1知道结果为011235。
3.phase_3
phase_3汇编代码及注释如下:
08048ea1:
8048ea1:
55push%ebp
8048ea2:
89e5mov%esp,%ebp
8048ea4:
83ec28sub$0x28,%esp
8048ea7:
8d45f0lea-0x10(%ebp),%eax#第二个数的位置
8048eaa:
8944240cmov%eax,0xc(%esp)
8048eae:
8d45f4lea-0xc(%ebp),%eax#第一个数的位置
8048eb1:
89442408mov%eax,0x8(%esp)
8048eb5:
c74424043ea204movl$0x804a23e,0x4(%esp)#通过查看0x804a23e的内容,即x/s0x804a23e,显示为"%d%d",提示输入两个整型数
8048ebc:
08
8048ebd:
8b4508mov0x8(%ebp),%eax
8048ec0:
890424mov%eax,(%esp)
8048ec3:
e878f9ffffcall8048840<__isoc99_sscanf@plt>#isoc99标准输入变量,应该是把输入的数字个数存在%eax里
8048ec8:
83f801cmp$0x1,%eax
8048ecb:
7f05jg8048ed2#至少输入2个数,否则爆炸
8048ecd:
e8ff010000call80490d1
8048ed2:
837df407cmpl$0x7,-0xc(%ebp)
8048ed6:
776bja8048f43#第1个数大于7爆炸,所以,第一个数需要小于等于7
8048ed8:
8b45f4mov-0xc(%ebp),%eax将第一个数存到%eax中
8048edb:
ff2485a0a10408jmp*0x804a1a0(,%eax,4)#跳转至0x804a1a0+4*%eax(存放第一个数)中的内容所指的行数p/x*0x804a1a0+4*%eax
8048ee2:
b800000000mov$0x0,%eax
8048ee7:
eb53jmp8048f3c
8048ee9:
b800000000mov$0x0,%eax
8048eee:
6690xchg%ax,%ax
8048ef0:
eb45jmp8048f37
8048ef2:
b800000000mov$0x0,%eax#第一个数等于5的时候跳到这里
8048ef7:
eb39jmp8048f32
8048ef9:
b800000000mov$0x0,%eax#第一个数等于4的时候跳到这里
8048efe:
6690xchg%ax,%ax
8048f00:
eb2bjmp8048f2d
8048f02:
b800000000mov$0x0,%eax#第一个数等于4的时候跳到这里
8048f07:
eb1fjmp8048f28
8048f09:
b800000000mov$0x0,%eax#第一个数等于2的时候跳到这里
8048f0e:
6690xchg%ax,%ax
8048f10:
eb11jmp8048f23
8048f12:
b814030000mov$0x314,%eax#第一个数为0的时候跳到这里(p/x*0x804a1a0)首先x=778,最后第二个数等于147
8048f17:
eb05jmp8048f1e#跳转到8048f1e这一行
8048f19:
b800000000mov$0x0,%eax#第一个数等于1的时候跳到这里
8048f1e:
2d5a030000sub$0x35a,%eax#x=x-858
8048f23:
05ef020000add$0x2ef,%eax#x=x+751
8048f28:
2d16020000sub$0x216,%eax#x=x-534
8048f2d:
0516020000add$0x216,%eax#x=x+534
8048f32:
2d16020000sub$0x216,%eax#x=x-534
8048f37:
0516020000add$0x216,%eax#x=x+534
8048f3c:
2d16020000sub$0x216,%eax#x=x-534
8048f41:
eb0ajmp8048f4d#跳转到8048f4d这一行
8048f43:
e889010000call80490d1
8048f48:
b800000000mov$0x0,%eax
8048f4d:
837df405cmpl$0x5,-0xc(%ebp)
8048f51:
7f05jg8048f58#第一个数字需要小于等于5,否则爆炸
8048f53:
3b45f0cmp-0x10(%ebp),%eax
8048f56:
7405je8048f5d#0,147;1-641;2,217;3,-534;4,0;5,-534
8048f58:
e874010000call80490d1
8048f5d:
c9leave
8048f5e:
6690xchg%ax,%ax
8048f60:
c3ret
思路与分析:
观察到指令movl$0x804a23e,0x4(%esp),通过查看0x804a23e的内容,即x/s0x804a23e,显示为"%d%d",提示输入两个整型数。
call8048840<__isoc99_sscanf@plt>,调用isoc99标准输入变量,是把输入的数字个数存在%eax里返回。
通过cmp$0x1,%eax和jg8048ed2知道至少输入2个数,否则爆炸。
通过cmpl$0x7,-0xc(%ebp)和ja8048f43知道第一个数字小于等于7,由cmpl$0x5,-0xc(%ebp)和jg8048f58知道输入的数字要小于等于5,所以输入的数字范围为0-5。
jmp*0x804a1a0(,%eax,4)为switch分支结构,%eax存着输入的数字的值,当输入的数组是0的时候,,查看*0x804a1a0的值,得到$1=0x8048f12,即跳转到0x8048f12处。
当输入的数字为1-5时依次类推。
得到的地址分别为:
cmp-0x10(%ebp),%eax和je8048f5d即为判断经过一系列运算后求的值是否与正确的值相等。
通过分析汇编代码,我们可以知道当输入不同的x值,等到的y值如下:
当x=0时,y=788-858+751-534+534-534+534-534=147
当x=1时,y=-858+751-534+534-534+534-534=-641
当x=2时,y=751-534+534-534+534-534=217
当x=3时,x=-534+534-534+534-534=-534
当x=4时,x=534-534+534-534=0
当x=5时,x=-534+534-534=-534
所以可以输入六组数据:
0147;1-641;2217;3-534;40;5-534。
随便输入一组都能通过炸弹。
结论与心得:
第三关主要用到了switch分支结构,根据输如的不同数字跳转到不同位置进行不同的运算,最后得到结果。
首先分析输入数字的范围,然后通过判断跳转的位置来准确计算。
4.phase_4
phase_4汇编代码及注释如下:
08048e2e:
8048e2e:
55push%ebp
8048e2f:
89e5mov%esp,%ebp
8048e31:
83ec28sub$0x28,%esp#开辟栈空间
8048e34:
8d45f0lea-0x10(%ebp),%eax#第二个数字
8048e37:
8944240cmov%eax,0xc(%esp)
8048e3b:
8d45f4lea-0xc(%ebp),%eax#第一个数字
8048e3e:
89442408mov%eax,0x8(%esp)
8048e42:
c74424043ea204movl$0x804a23e,0x4(%esp)#输入x/s0x804a23e显示为"%d%d",提示输入两个整型数字
8048e49:
08
8048e4a:
8b4508mov0x8(%ebp),%eax
8048e4d:
890424mov%eax,(%esp)
8048e50:
e8ebf9ffffcall8048840<__isoc99_sscanf@plt>#标准输入变量,将输入的数字个数存在%eax中
8048e55:
83f802cmp$0x2,%eax
8048e58:
750cjne8048e66#要求输入2个数字,即输入的数字个数不等于2则爆炸
8048e5a:
8b45f4mov-0xc(%ebp),%eax#将第一个数放到%eax中
8048e5d:
85c0test%eax,%eax
8048e5f:
7805js8048e66#判断第一个数,如果是负数就爆炸,所以需要%eax>=0
8048e61:
83f80ecmp$0xe,%eax
8048e64:
7e05jle8048e6b#比较第一个数和14(0xe)的大小,如果%eax<=14,则继续执行,否则爆炸
8048e66:
e866020000call80490d1
8048e6b:
c74424080e0000movl$0xe,0x8(%esp)#将0xe存到%esp+8
8048e72:
00
8048e73:
c7442404000000movl$0x0,0x4(%esp)#将0x0存到%esp+4
8048e7a:
00
8048e7b:
8b45f4mov-0xc(%ebp),%eax
8048e7e:
89042