1、Bomb Lab实验报告课程实验报告 课 程 名 称: 计算机系统原理实验 实 验 名 称: Bomb Lab 专 业 班 级: 姓 名: 学 号: 完 成 时 间: 2017.4.19 1、实验目的熟悉汇编程序,学习gdb调试工具,熟悉并掌握函数调用过程中的栈帧结构的变化。2、实验环境个人PC,Linux发行版本,终端,gdb调试工具。3、实验要求1.本次实验为熟悉汇编程序及其调试方法的实验。2.实验内容包含2个文件bomb(可执行文件)和bomb.c(c源文件)。3.使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。4.分析汇编代码,找到在每个phase程序段中,引导程
2、序跳转到“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,
3、phase_3,phase_4,phase_5,phase_6,因此可以对bomb文件反汇编得到汇编文本,结合汇编文本与bomb.c文本进一步分析。2.进入Ubuntu,将bom和bomb.c文档复制到主文件目录下,ctrl+alt+t打开终端,通过“objdump -d bomb bomb.s”命令将可执行文件反汇编成bomb.s文件,并且可以通过“gdb -q bomb”进行调试。3.将bomb.c复制成文本后打开bomb.c查看汇编代码并进一步分析。 (2)关卡分析1.phase_1phase_1汇编代码及注释如下:08048f61 : 8048f61: 55 push %ebp 804
4、8f62: 89 e5 mov %esp,%ebp 8048f64: 83 ec 18 sub $0x18,%esp #开辟一个24位的栈空间 8048f67: c7 44 24 04 5c a1 04 movl $0x804a15c,0x4(%esp) #将0x804a15c存到%eap+4的位置,x/s 0x804a15c 得到 We have to stand with our North Korean allies. 8048f6e: 08 8048f6f: 8b 45 08 mov 0x8(%ebp),%eax 8048f72: 89 04 24 mov %eax,(%esp) #将
5、%ebp+8处的值存到%esp 8048f75: e8 31 00 00 00 call 8048fab 8048f7a: 85 c0 test %eax,%eax 8048f7c: 74 05 je 8048f83 #%eax=0则跳出函数,否则跳到爆炸函数,可以看出,调用函数后如果两个字符串相等的话最后%eax会等于0 8048f7e: e8 4e 01 00 00 call 80490d1 8048f83: c9 leave 8048f84: c3 ret 8048f85: 90 nop 8048f86: 90 nop 8048f87: 90 nop 8048f88: 90 nop 80
6、48f89: 90 nop 8048f8a: 90 nop 8048f8b: 90 nop 8048f8c: 90 nop 8048f8d: 90 nop 8048f8e: 90 nop 8048f8f: 90 nop思路与分析: 通过call 8048fab 我们可以推断要求输入的是一串字符串,movl $0x804a15c,0x4(%esp)将地址0x804a15c存到%esp+4的位置,mov 0x8(%ebp),%eax 和 mov %eax,(%esp)将输入的字符串存到%esp中,call 8048fab 调用字符串比较函数,通过比较上面位置参数%esp+4与%esp对应的字符串是
7、否相等,将返回值存到%eax中,test %eax,%eax,je 8048f83 ,call 80490d1 ,判断如果两个字符串不相等则爆炸。由上面分析可知地址0x804a15c中存着正确的字符串,我们只要输入相同的字符串就可以通过关卡。进入gdb,通过命令x/s 0x804a15c查看该字符串为:We have to stand with our North Korean allies.所以phase_1的通关密码为:We have to stand with our North Korean allies.通过 r 命令运行程序,输入该字符串则通过第一关:结论与心得:通过分析汇编代码,
8、通过字符串比较函数 可以推测输入的是一串字符串,通过x/s以字符串的形式查看地址0x804a15c所对应的值,运行程序后输入该字符串即可通过关卡。字符串比较函数主要是通过将两个字符串进行比较,将结果存到%eax中,最后判断%eax的值。第一关相对比较简单,也比较好理解。2.phase_2phase_2汇编代码及注释如下:08048d6a : 8048d6a: 55 push %ebp 8048d6b: 89 e5 mov %esp,%ebp 8048d6d: 56 push %esi 8048d6e: 53 push %ebx 8048d6f: 83 ec 30 sub $0x30,%esp
9、8048d72: 8d 45 e0 lea -0x20(%ebp),%eax 8048d75: 89 44 24 04 mov %eax,0x4(%esp) #将第一个数字的地址放到%esp+4的位置 8048d79: 8b 45 08 mov 0x8(%ebp),%eax 8048d7c: 89 04 24 mov %eax,(%esp) 8048d7f: e8 87 03 00 00 call 804910b #读取六个数字 8048d84: 83 7d e0 00 cmpl $0x0,-0x20(%ebp) 8048d88: 75 06 jne 8048d90 #0和-0x20(%ebp
10、)比较,不相等就爆炸 8048d8a: 83 7d e4 01 cmpl $0x1,-0x1c(%ebp) 8048d8e: 74 05 je 8048d95 #1和-0x1c(%ebp)比较,相等就跳过爆炸 8048d90: e8 3c 03 00 00 call 80490d1 8048d95: 8d 5d e8 lea -0x18(%ebp),%ebx #将第三个数字的地址传到%ebx中,即现在%ebx中存着第三个数字的地址 8048d98: 8d 75 f8 lea -0x8(%ebp),%esi #将%ebx的地址传到%esi,%esi用于待会的判断结束条件,%ebx存的地址一直循环
11、加4,循环直到%ebx的下一个地址是%esi就结束】 8048d9b: 8b 43 fc mov -0x4(%ebx),%eax #将第二个数放到%eax寄存器中 8048d9e: 03 43 f8 add -0x8(%ebx),%eax #计算第二个数和第一个数的和 8048da1: 39 03 cmp %eax,(%ebx) 8048da3: 74 05 je 8048daa #前两个数的和与第三个数相比较,相等则跳过炸弹 8048da5: e8 27 03 00 00 call 80490d1 8048daa: 83 c3 04 add $0x4,%ebx #将%ebx的地址加4,现在%
12、ebx中存着第四个数字的地址 8048dad: 39 f3 cmp %esi,%ebx 8048daf: 75 ea jne 8048d9b #比较现在%esi和%ebx里面的值是否相等,不相等则循环,否则结束。其实两个寄存器中存的都是地址,为的是保证只输入6个数,因为当输入第7个数时,%ebx=%esi 8048db1: 83 c4 30 add $0x30,%esp 8048db4: 5b pop %ebx 8048db5: 5e pop %esi 8048db6: 5d pop %ebp #释放栈帧 8048db7: c3 ret思路与分析:通过call 804910b 我们可以推断出应
13、该是要输入6个数字。通过对汇编代码进行分析知道-0x20(%ebp)存着第一个数字,-0x1c(%ebp)存着第二个数字,依次类推。通过cmpl $0x0,-0x20(%ebp),jne 8048d90 和cmpl $0x1,-0x1c(%ebp),je 8048d95 知道第一个数字必须是0,第二个数字必须是1,否则就爆炸。命令lea -0x18(%ebp),%ebx初始化寄存器%ebx的值,将第三个数字的地址传到%ebx中.lea -0x8(%ebp),%esi将%ebx的地址传到%esi,%esi用于待会的判断结束条件,%ebx存的地址一直循环加4,循环直到%ebx的下一个地址是%esi
14、就结束,mov -0x4(%ebx),%eax将第二个数放到%eax寄存器中,add -0x8(%ebx),%eax计算第二个数和第一个数的和,cmp %eax,(%ebx),je 8048daa 前两个数的和与第三个数相比较,相等则跳过炸弹。add $0x4,%ebx将%ebx的地址加4,现在%ebx中存着第四个数字的地址,之后%ebx一直加4,知道循环完6个数字。通过上面的分析知道,输入的前两个数字为0和1,后面的数字等于前面两个数字的和。所以,这六个数字为Fibonacci数列的前六项。为0 1 1 2 3 5。输入这6个数字可通过phase_2.结论与心得:第二关需要弄懂栈帧结构的变化
15、,通过add $0x4,%ebx将%ebx的地址加4,然后判断前两个数字的和与当前位置的数是否相等。结合第一个和第二个数字是0和1知道结果为0 1 1 2 3 5。3.phase_3phase_3汇编代码及注释如下:08048ea1 : 8048ea1: 55 push %ebp 8048ea2: 89 e5 mov %esp,%ebp 8048ea4: 83 ec 28 sub $0x28,%esp 8048ea7: 8d 45 f0 lea -0x10(%ebp),%eax #第二个数的位置 8048eaa: 89 44 24 0c mov %eax,0xc(%esp) 8048eae:
16、8d 45 f4 lea -0xc(%ebp),%eax #第一个数的位置 8048eb1: 89 44 24 08 mov %eax,0x8(%esp) 8048eb5: c7 44 24 04 3e a2 04 movl $0x804a23e,0x4(%esp) #通过查看0x804a23e的内容,即x/s 0x804a23e,显示为%d %d,提示输入两个整型数 8048ebc: 08 8048ebd: 8b 45 08 mov 0x8(%ebp),%eax 8048ec0: 89 04 24 mov %eax,(%esp) 8048ec3: e8 78 f9 ff ff call 80
17、48840 #isoc99标准输入变量,应该是把输入的数字个数存在%eax里 8048ec8: 83 f8 01 cmp $0x1,%eax 8048ecb: 7f 05 jg 8048ed2 #至少输入2个数,否则爆炸 8048ecd: e8 ff 01 00 00 call 80490d1 8048ed2: 83 7d f4 07 cmpl $0x7,-0xc(%ebp) 8048ed6: 77 6b ja 8048f43 #第1个数大于7爆炸,所以,第一个数需要小于等于7 8048ed8: 8b 45 f4 mov -0xc(%ebp),%eax 将第一个数存到%eax中 8048edb
18、: ff 24 85 a0 a1 04 08 jmp *0x804a1a0(,%eax,4) #跳转至0x804a1a0+4*%eax(存放第一个数)中的内容所指的行数 p/x *0x804a1a0+4*%eax 8048ee2: b8 00 00 00 00 mov $0x0,%eax 8048ee7: eb 53 jmp 8048f3c 8048ee9: b8 00 00 00 00 mov $0x0,%eax 8048eee: 66 90 xchg %ax,%ax 8048ef0: eb 45 jmp 8048f37 8048ef2: b8 00 00 00 00 mov $0x0,%e
19、ax #第一个数等于5的时候跳到这里 8048ef7: eb 39 jmp 8048f32 8048ef9: b8 00 00 00 00 mov $0x0,%eax #第一个数等于4的时候跳到这里 8048efe: 66 90 xchg %ax,%ax 8048f00: eb 2b jmp 8048f2d 8048f02: b8 00 00 00 00 mov $0x0,%eax #第一个数等于4的时候跳到这里 8048f07: eb 1f jmp 8048f28 8048f09: b8 00 00 00 00 mov $0x0,%eax #第一个数等于2的时候跳到这里 8048f0e: 6
20、6 90 xchg %ax,%ax 8048f10: eb 11 jmp 8048f23 8048f12: b8 14 03 00 00 mov $0x314,%eax #第一个数为0的时候跳到这里(p/x *0x804a1a0)首先x=778,最后第二个数等于147 8048f17: eb 05 jmp 8048f1e #跳转到 8048f1e 这一行 8048f19: b8 00 00 00 00 mov $0x0,%eax #第一个数等于1的时候跳到这里 8048f1e: 2d 5a 03 00 00 sub $0x35a,%eax #x=x-858 8048f23: 05 ef 02
21、00 00 add $0x2ef,%eax #x=x+751 8048f28: 2d 16 02 00 00 sub $0x216,%eax #x=x-534 8048f2d: 05 16 02 00 00 add $0x216,%eax #x=x+534 8048f32: 2d 16 02 00 00 sub $0x216,%eax #x=x-534 8048f37: 05 16 02 00 00 add $0x216,%eax #x=x+534 8048f3c: 2d 16 02 00 00 sub $0x216,%eax #x=x-534 8048f41: eb 0a jmp 8048f
22、4d #跳转到 8048f4d 这一行 8048f43: e8 89 01 00 00 call 80490d1 8048f48: b8 00 00 00 00 mov $0x0,%eax 8048f4d: 83 7d f4 05 cmpl $0x5,-0xc(%ebp) 8048f51: 7f 05 jg 8048f58 #第一个数字需要小于等于5,否则爆炸 8048f53: 3b 45 f0 cmp -0x10(%ebp),%eax 8048f56: 74 05 je 8048f5d #0,147; 1 -641;2,217; 3,-534; 4,0; 5,-534 8048f58: e8
23、 74 01 00 00 call 80490d1 8048f5d: c9 leave 8048f5e: 66 90 xchg %ax,%ax 8048f60: c3 ret思路与分析:观察到指令movl $0x804a23e,0x4(%esp),通过查看0x804a23e的内容,即x/s 0x804a23e,显示为%d %d,提示输入两个整型数。call 8048840 ,调用isoc99标准输入变量,是把输入的数字个数存在%eax里返回。通过cmp $0x1,%eax和jg 8048ed2 知道至少输入2个数,否则爆炸。通过cmpl $0x7,-0xc(%ebp)和ja 8048f43 知
24、道第一个数字小于等于7,由cmpl $0x5,-0xc(%ebp)和jg 8048f58 知道输入的数字要小于等于5,所以输入的数字范围为0-5。jmp *0x804a1a0(,%eax,4)为switch分支结构,%eax存着输入的数字的值,当输入的数组是0的时候,查看*0x804a1a0的值,得到$1 = 0x8048f12,即跳转到0x8048f12处。当输入的数字为1-5时依次类推。得到的地址分别为:cmp -0x10(%ebp),%eax和je 8048f5d 即为判断经过一系列运算后求的值是否与正确的值相等。通过分析汇编代码,我们可以知道当输入不同的x值,等到的y值如下:当x=0时
25、,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所以可以输入六组数据:0 147;1 -641;2 217;3 -534;4 0;5 -534。随便输入一组都能通过炸弹。结论与心得:第三关主要用到了switch分支结构,根据输如的不同数字跳转到不
26、同位置进行不同的运算,最后得到结果。首先分析输入数字的范围,然后通过判断跳转的位置来准确计算。4.phase_4phase_4汇编代码及注释如下:08048e2e : 8048e2e: 55 push %ebp 8048e2f: 89 e5 mov %esp,%ebp 8048e31: 83 ec 28 sub $0x28,%esp #开辟栈空间 8048e34: 8d 45 f0 lea -0x10(%ebp),%eax #第二个数字 8048e37: 89 44 24 0c mov %eax,0xc(%esp) 8048e3b: 8d 45 f4 lea -0xc(%ebp),%eax #
27、第一个数字 8048e3e: 89 44 24 08 mov %eax,0x8(%esp) 8048e42: c7 44 24 04 3e a2 04 movl $0x804a23e,0x4(%esp) #输入x/s 0x804a23e 显示为 %d %d ,提示输入两个整型数字 8048e49: 08 8048e4a: 8b 45 08 mov 0x8(%ebp),%eax 8048e4d: 89 04 24 mov %eax,(%esp) 8048e50: e8 eb f9 ff ff call 8048840 #标准输入变量,将输入的数字个数存在%eax中 8048e55: 83 f8
28、02 cmp $0x2,%eax 8048e58: 75 0c jne 8048e66 #要求输入2个数字,即输入的数字个数不等于2则爆炸 8048e5a: 8b 45 f4 mov -0xc(%ebp),%eax #将第一个数放到%eax中 8048e5d: 85 c0 test %eax,%eax 8048e5f: 78 05 js 8048e66 #判断第一个数,如果是负数就爆炸,所以需要%eax=0 8048e61: 83 f8 0e cmp $0xe,%eax 8048e64: 7e 05 jle 8048e6b #比较第一个数和14(0xe)的大小,如果%eax=14,则继续执行,否则爆炸 8048e66: e8 66 02 00 00 call 80490d1 8048e6b: c7 44 24 08 0e 00 00 movl $0xe,0x8(%esp) #将0xe存到%esp+8 8048e72: 00 8048e73: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) #将0x0存到%esp+4 8048e7a: 00 8048e7b: 8b 45 f4 mov -0xc(%ebp),%eax 8048e7e: 89 04 2
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1