Bomb Lab实验报告_shalllab实验报告

2020-02-27 其他范文 下载本文

Bomb Lab实验报告由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“shalllab实验报告”。

课程实验报告

课 程 名 称:

计算机系统原理实验 实 验 名 称:

Bomb Lab 专 业 班 级: 姓

名:

号:

完 成 时 间:

2017.4.19

一、实验目的熟悉汇编程序,学习gdb调试工具,熟悉并掌握函数调用过程中的栈帧结构的变化。

二、实验环境

个人PC,Linux发行版本,终端,gdb调试工具。

三、实验要求

1.本次实验为熟悉汇编程序及其调试方法的实验。

2.实验内容包含2个文件bomb(可执行文件)和bomb.c(c源文件)。3.使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。

4.分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符通关。

5.本实验一共有7个关卡,包括6个普通关卡和1个隐藏关卡。要求至少通过6个普通关卡。

四、实验内容及操作步骤

(一)准备过程

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-d bomb > bomb.s”命令将可执行文件反汇编成bomb.s文件,并且可以通过“gdb-q bomb”进行调试。3.将bomb.c复制成文本后打开bomb.c查看汇编代码并进一步分析。

(二)关卡分析

1.phase_1 phase_1汇编代码及注释如下: 08048f61

: 8048f61: 55 8048f62: 89 e5 8048f64: 83 ec 18 位的栈空间

8048f67: c7 44 24 04 5c a1 04

push %ebp mov %esp,%ebp

sub $0x18,%esp #开辟一个2

4movl $0x804a15c,0x4(%esp)#将0x804a15c存到%eap+4的位置,x/s 0x804a15c 得到 “We have to stand with our North Korean allies.” 8048f6e: 08 8048f6f: 8b 45 08 8048f72: 89 04 24 处的值存到%esp 8048f75: e8 31 00 00 00 8048f7a: 85 c0 8048f7c: 74 05

test %eax,%eax

je 8048f83

call 8048fab mov 0x8(%ebp),%eax mov %eax,(%esp)

#将%ebp+8#%eax=0则跳出函数,否则跳到爆炸函数,可以看出,调用函数后如果两个字符串相等的话最后%eax会等于0 8048f7e: e8 4e 01 00 00 8048f83: c9 8048f84: c3 8048f85: 90 8048f86: 90 8048f87: 90

call 80490d1 leave ret nop nop nop 8048f88: 90 8048f89: 90 8048f8a: 90 8048f8b: 90 8048f8c: 90 8048f8d: 90 8048f8e: 90 8048f8f: 90

思路与分析:

nop nop nop nop nop nop nop nop 通过call 8048fab 我们可以推断要求输入的是一串字符串,movl $0x804a15c,0x4(%esp)将地址0x804a15c存到%esp+4的位置,mov 0x8(%ebp),%eax 和 mov %eax,(%esp)将输入的字符串存到%esp中,call 8048fab 调用字符串比较函数,通过比较上面位置参数%esp+4与%esp对应的字符串是否相等,将返回值存到%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 命令运行程序,输入该字符串则通过第一关:

结论与心得: 通过分析汇编代码,通过字符串比较函数 可以推测输入的是一串字符串,通过x/s以字符串的形式查看地址0x804a15c所对应的值,运行程序后输入该字符串即可通过关卡。字符串比较函数主要是通过将两个字符串进行比较,将结果存到%eax中,最后判断%eax的值。第一关相对比较简单,也比较好理解。

2.phase_2 phase_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 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)比较,不相等就爆炸 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存的地址一直循环加4,循环直到%ebx的下一个地址是%esi就结束】

8048d9b: 8b 43 fc 二个数放到%eax寄存器中

8048d9e: 03 43 f8 第二个数和第一个数的和

8048da1: 39 03 8048da3: 74 05

cmp %eax,(%ebx)

add-0x8(%ebx),%eax #计算mov-0x4(%ebx),%eax #将第je 8048daa

#前两个数的和与第三个数相比较,相等则跳过炸弹 8048da5: e8 27 03 00 00 8048daa: 83 c3 04

call 80490d1 add $0x4,%ebx #将%ebx的地址加4,现在%ebx中存着第四个数字的地址

8048dad: 39 f3 8048daf: 75 ea

cmp %esi,%ebx

jne 8048d9b

#比较现在%esi和%ebx里面的值是否相等,不相等则循环,否则结束。其实两个寄存器中存的都是地址,为的是保证只输入6个数,因为当输入第7个数时,%ebx=%esi 8048db1: 83 c4 30 8048db4: 5b 8048db5: 5e 8048db6: 5d 8048db7: c3

思路与分析:

通过call 804910b 我们可以推断出应该是要输入6个数字。通过对汇编代码进行分析知道-0x20(%ebp)存着第一个数字,-0x1c(%ebp)

add $0x30,%esp pop %ebx pop %esi pop %ebp ret

#释放栈帧 存着第二个数字,依次类推。通过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就结束,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.结论与心得:

第二关需要弄懂栈帧结构的变化,通过add $0x4,%ebx将%ebx的地址加4,然后判断前两个数字的和与当前位置的数是否相等。结合第一个和第二个数字是0和1知道结果为0 1 1 2 3 5。

3.phase_3 phase_3汇编代码及注释如下: 08048ea1

: 8048ea1: 55 8048ea2: 89 e5 8048ea4: 83 ec 28 8048ea7: 8d 45 f0 个数的位置

push %ebp mov %esp,%ebp sub $0x28,%esp

lea-0x10(%ebp),%eax #第二 8048eaa: 89 44 24 0c 8048eae: 8d 45 f4 个数的位置

8048eb1: 89 44 24 08 8048eb5: c7 44 24 04 3e a2 04

mov %eax,0xc(%esp)

lea-0xc(%ebp),%eax #第一

mov %eax,0x8(%esp)movl $0x804a23e,0x4(%esp)#通过查看0x804a23e的内容,即x/s 0x804a23e,显示为“%d %d”,提示输入两个整型数

8048ebc: 08 8048ebd: 8b 45 08 8048ec0: 89 04 24 8048ec3: e8 78 f9 ff ff 在%eax里

8048ec8: 83 f8 01 8048ecb: 7f 05 #至少输入2个数,否则爆炸 8048ecd: e8 ff 01 00 00 8048ed2: 83 7d f4 07 8048ed6: 77 6b

call 80490d1 cmpl $0x7,-0xc(%ebp)ja 8048f43

cmp $0x1,%eax

jg 8048ed2

mov 0x8(%ebp),%eax mov %eax,(%esp)call 8048840

#isoc99标准输入变量,应该是把输入的数字个数存#第1个数大于7爆炸,所以,第一个数需要小于等于7 8048ed8: 8b 45 f4

mov-0xc(%ebp),%eax 将第一个数存到%eax中

8048edb: ff 24 85 a0 a1 04 08

jmp *0x804a1a0(,%eax,4)

#p/x 跳转至0x804a1a0+4*%eax(存放第一个数)中的内容所指的行数 *0x804a1a0+4*%eax 8048ee2: b8 00 00 00 00 8048ee7: eb 53 8048ee9: b8 00 00 00 00 8048eee: 66 90

mov $0x0,%eax

jmp 8048f3c

mov $0x0,%eax xchg %ax,%ax 8048ef0: eb 45 8048ef2: b8 00 00 00 00 5的时候跳到这里

8048ef7: eb 39 8048ef9: b8 00 00 00 00 4的时候跳到这里

8048efe: 66 90 8048f00: eb 2b 8048f02: b8 00 00 00 00 4的时候跳到这里

8048f07: eb 1f 8048f09: b8 00 00 00 00 2的时候跳到这里

8048f0e: 66 90 8048f10: eb 11 8048f12: b8 14 03 00 00

jmp 8048f37

mov $0x0,%eax #第一个数等于

jmp 8048f32

mov $0x0,%eax #第一个数等于

xchg %ax,%ax

jmp 8048f2d

mov $0x0,%eax #第一个数等于

jmp 8048f28

mov $0x0,%eax #第一个数等于

xchg %ax,%ax

jmp 8048f23

mov $0x314,%eax

#第一个数为0的时候跳到这里(p/x *0x804a1a0)首先x=778,最后第二个数等于147 8048f17: eb 05 #跳转到 8048f1e 这一行

8048f19: b8 00 00 00 00 1的时候跳到这里

8048f1e: 2d 5a 03 00 00 8048f23: 05 ef 02 00 00 8048f28: 2d 16 02 00 00 8048f2d: 05 16 02 00 00 8048f32: 2d 16 02 00 00 8048f37: 05 16 02 00 00 8048f3c: 2d 16 02 00 00

sub $0x35a,%eax add $0x2ef,%eax sub $0x216,%eax add $0x216,%eax sub $0x216,%eax add $0x216,%eax sub $0x216,%eax

#x=x-858 #x=x+751 #x=x-534 #x=x+534 #x=x-534 #x=x+534 #x=x-534

mov $0x0,%eax #第一个数等于jmp 8048f1e

8048f41: eb 0a #跳转到 8048f4d 这一行

8048f43: e8 89 01 00 00 8048f48: b8 00 00 00 00 8048f4d: 83 7d f4 05 8048f51: 7f 05

jmp 8048f4d

call 80490d1 mov $0x0,%eax cmpl $0x5,-0xc(%ebp)jg 8048f58

#第一个数字需要小于等于5,否则爆炸 8048f53: 3b 45 f0 8048f56: 74 05

cmp-0x10(%ebp),%eax je 8048f5d

#0,147;1-641;2,217; 3,-534; 4,0; 5,-534

call 80490d1 leave xchg %ax,%ax ret 8048f58: e8 74 01 00 00 8048f5d: c9 8048f5e: 66 90 8048f60: c3

思路与分析:

观察到指令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

知道第一个数字小于等于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时,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分支结构,根据输如的不同数字跳转到不同位置进行不同的运算,最后得到结果。首先分析输入数字的范围,然后通过判断跳转的位置来准确计算。

4.phase_4 phase_4汇编代码及注释如下: 08048e2e

: 8048e2e: 55

push %ebp 8048e2f: 89 e5 8048e31: 83 ec 28 8048e34: 8d 45 f0 个数字

8048e37: 89 44 24 0c 8048e3b: 8d 45 f4 个数字

8048e3e: 89 44 24 08 8048e42: c7 44 24 04 3e a2 04 输入x/s 0x804a23e 显示为

8048e49: 08 8048e4a: 8b 45 08 8048e4d: 89 04 24 8048e50: e8 eb f9 ff ff

“%d %d”

mov %esp,%ebp

sub $0x28,%esp #开辟栈空间 lea-0x10(%ebp),%eax #第二

mov %eax,0xc(%esp)lea-0xc(%ebp),%eax #第一

mov %eax,0x8(%esp)movl $0x804a23e,0x4(%esp)#,提示输入两个整型数字

mov 0x8(%ebp),%eax mov %eax,(%esp)call 8048840

#标准输入变量,将输入的数字个数存在%eax中

cmp $0x2,%eax

jne 8048e66

8048e55: 83 f8 02 8048e58: 75 0c #要求输入2个数字,即输入的数字个数不等于2则爆炸 8048e5a: 8b 45 f4

mov-0xc(%ebp),%eax #将第一个数放到%eax中

8048e5d: 85 c0 8048e5f: 78 05

test %eax,%eax

js 8048e66

#判断第一个数,如果是负数就爆炸,所以需要%eax>=0 8048e61: 83 f8 0e 8048e64: 7e 05

cmp $0xe,%eax

jle 8048e6b

#比较第一个数和14(0xe)的大小,如果%eax

call 80490d1 movl $0xe,0x8(%esp)

#将0xe存到%esp+8 8048e72: 00 8048e73: c7 44 24 04 00 00 00 0x0存到%esp+4 8048e7a: 00 8048e7b: 8b 45 f4 8048e7e: 89 04 24 数存到%esp 8048e81: e8 da fc ff ff func4函数(递归函数)8048e86: 83 f8 01 y存放在%eax寄存器中

8048e89: 75 06 #y要等于1,否则爆炸

8048e8b: 83 7d f0 01 8048e8f: 74 0c #第二个数要等于1,否则爆炸 8048e91: 8d b4 26 00 00 00 00 8048e98: e8 34 02 00 00 8048e9d: c9 8048e9e: 66 90 8048ea0: c3

call 8048b60 知道要调用func4函数。

func4汇编代码及注释如下: 08048b60 : 8048b60: 55 8048b61: 89 e5 8048b63: 83 ec 18

push %ebp mov %esp,%ebp

sub $0x18,%esp #建立一个栈帧 lea 0x0(%esi,%eiz,1),%esi call 80490d1 leave xchg %ax,%ax ret

cmpl $0x1,-0x10(%ebp)je 8048e9d

jne 8048e91

cmp $0x1,%eax #函数的返回值call 8048b60 #调用mov-0xc(%ebp),%eax mov %eax,(%esp)

#将第一个

movl $0x0,0x4(%esp)

#将 8048b66: 89 5d f8 8048b69: 89 75 fc 8048b6c: 8b 55 08 #%edx->x 8048b6f: 8b 45 0c #%eax->y=0x0=0 8048b72: 8b 5d 10 #%ebx->z=0xe=14

func4(x,y,z)

mov %ebx,-0x8(%ebp)mov %esi,-0x4(%ebp)mov 0x8(%ebp),%edx

mov 0xc(%ebp),%eax

mov 0x10(%ebp),%ebx 8048b75: 89 d9 t的过程,#t=z 8048b77: 29 c1 8048b79: 89 ce 8048b7b: c1 ee 1f 逻辑右移31位

8048b7e: 8d 0c 0e #t=(z-y)>>31+(z-y)8048b81: d1 f9 #t=[(z-y)>>31+(z-y)]>>1 8048b83: 01 c1 #t=[(z-y)>>31+(z-y)]/2+y

=

mov %ebx,%ecx #计算临时变量

sub %eax,%ecx #t=z-y mov %ecx,%esi #t=z-y shr $0x1f,%esi #t=(z-y)>>31,lea(%esi,%ecx,1),%ecx

sar %ecx

add %eax,%ecx(14>>31+14)/2+0=7

cmp %edx,%ecx #将7和x(第 8048b85: 39 d1 一个数)比较,即7-x 8048b87: 7e 17 #当7

jle 8048ba0

否则继续执行下一条指令

sub $0x1,%ecx #t=t-1 8048b89: 83 e9 01 if(7>x)8048b8c: 89 4c 24 08 t-1移到0x8(%esp),z=t-1 8048b90: 89 44 24 04

mov %ecx,0x8(%esp)#将

mov %eax,0x4(%esp)#y 8048b94: 89 14 24 8048b97: e8 c4 ff ff ff 8048b9c: 01 c0 结果存放到%eax中

8048b9e: eb 20 结束

8048ba0: b8 00 00 00 00 跳转到这里,此时令y=0 8048ba5: 39 d1 8048ba7: 7d 17

mov %edx,(%esp)#x

call 8048b60 #递归 add %eax,%eax

#y=2*y,将

jmp 8048bc0

#mov $0x0,%eax #if(x>=7)时就

cmp %edx,%ecx

jge 8048bc0 #如果t>=x(在这种情况下只能x==t),则跳转到8048bc0,否则继续执行

8048ba9: 89 5c 24 08 8048bad: 83 c1 01 8048bb0: 89 4c 24 04 8048bb4: 89 14 24 8048bb7: e8 a4 ff ff ff 8048bbc: 8d 44 00 01 #y=z*y+1,将结果存到%eax中 8048bc0: 8b 5d f8 #if(t==x)跳转到这里

8048bc3: 8b 75 fc 8048bc6: 89 ec 8048bc8: 5d 8048bc9: c3

思路与分析:

首先分析phase_4汇编代码。movl $0x804a23e,0x4(%esp)输入x/s 0x804a23e 显示为 “%d %d”,提示输入两个整型数字。call 8048840

mov-0x4(%ebp),%esi mov %ebp,%esp pop %ebp ret

mov-0x8(%ebp),%ebxmov %ebx,0x8(%esp)add $0x1,%ecx #y=t+1 mov %ecx,0x4(%esp)mov %edx,(%esp)

#x

y=t+1 #z

call 8048b60 #递归 lea 0x1(%eax,%eax,1),%eax,cmp $0x2,%eax,jne 8048e66

任然要求输入2个数字。通过mov-0xc(%ebp),%eax,test %eax,%eax,js 8048e66

知道第一个数为非负数。由cmp $0xe,%eax和jle 8048e6b

又可以知道第一个数字要小于等于14。之后分析func4函数,分别用%esp,0x4(%esp),%0x8(%esp)传递三个参数,设为x,y,z。参数y存储在寄存器%eax中并作为最终的返回值,最终结果为1,也就是n的值;参数x和z存储于寄存器%edx和%ebx中,并通堆栈指针来保存或改变(配合其他指令)。在func4中进一步缩小了第一个数字的范围。现在需要第一个数字的范围为7-14。通过分析func4汇编代码,可以得到如下的c代码:

# #include # int x,y,z,ret; # int func4(){ # # # # # # # # # # # # # # # } # # int main(){ # for(x=0;x>31+(z-y))/2+y;if(t>x){

} else{

} y=0;if(t==x)return y;z=t-1;func4();y=z*y;

y=t+1; func4();y=2*y+1;# # # # # #

} y=0;z=0xe;ret=func4();if(ret==1)printf(“m=%d,n=%dn”,x,ret)# return 0;# } 第二个数必须为1。经过分析可以有三组数。分别是: 8 1;9 1;11 1。任意输入一组数就能通过关卡。

结论与心得:

这一关中在函数里调用了另外一个函数func4,func4函数中运用到了线性递归。通过分析汇编代码可以写出相应的c代码,通过分析第一个数范围在7-14,第二个数必须为1,结合c代码可以得出结果。

5.phase_5 phase_5汇编代码及注释如下: 08048db8

: 8048db8: 55 8048db9: 89 e5 8048dbb: 56 8048dbc: 53 8048dbd: 83 ec 20 8048dc0: 8d 45 f0 8048dc3: 89 44 24 0c 个数

push %ebp mov %esp,%ebp push %esi push %ebx

sub $0x20,%esp #开辟栈空间 lea-0x10(%ebp),%eax mov %eax,0xc(%esp)

#第二 8048dc7: 8d 45 f4 8048dca: 89 44 24 08 个数

8048dce: c7 44 24 04 3e a2 04 输入x/s 0x804a23e 显示为

8048dd5: 08 8048dd6: 8b 45 08 8048dd9: 89 04 24 8048ddc: e8 5f fa ff ff

“%d %d”

lea-0xc(%ebp),%eax mov %eax,0x8(%esp)

#第一

movl $0x804a23e,0x4(%esp)#,提示输入两个整型数字

mov 0x8(%ebp),%eax mov %eax,(%esp)call 8048840

#将输入的数字个数返回到%eax中

cmp $0x1,%eax

jg 8048deb

8048de1: 83 f8 01 8048de4: 7f 05 #若输入的数字个数大于1则跳转,否则爆炸,所以至少输入两个数字 8048de6: e8 e6 02 00 00 8048deb: 8b 45 f4 8048dee: 83 e0 0f

call 80490d1 mov-0xc(%ebp),%eax and $0xf,%eax #第一个数

“与” 0xf,这个操作可以只保留第一个数的二进制后四位(0“与”任何数都为0)

8048df1: 89 45 f4

mov %eax,-0xc(%ebp)#经过上面的操作后再把第一个数放回原来的位置(只保留二进制表示的后四位)

8048df4: 83 f8 0f 8048df7: 74 29

cmp $0xf,%eax

je 8048e22

#比较,如果第一个数和0xf(1111)相等则爆炸,说明第一个数的二进制后四位不能为“1111”,否则爆炸

8048df9: b9 00 00 00 00 用来累加%eax,初始化为0 8048dfe: ba 00 00 00 00 循环次数,初始化为0

mov $0x0,%edx #%edx=0

;

mov $0x0,%ecx #%ecx=0

; 8048e03: bb c0 a1 04 08 mov $0x804a1c0,%ebx # p *0x804a1c0=10,这个地址为数组的首地址,求的值为第一个元素的值,求数组元素:p *0x804a1c0@16={10, 2, 14, 7, 8, 12, 15, 11, 0, 4, 1, 13, 3, 9, 6, 5} 8048e08: 83 c2 01 从这里开始

8048e0b: 8b 04 83

mov(%ebx,%eax,4),%eaxadd $0x1,%edx #%edx=1,循环#%eax=(%ebx+4*%eax)=(0x804a1c0+4*%eax);%eax用来保存求出的数组中的某个值

8048e0e: 01 c1 #%ecx=%ecx+%eax 8048e10: 83 f8 0f 8048e13: 75 f3

cmp $0xf,%eax

jne 8048e08

add %eax,%ecx#如果此时%eax(此时的数组元素值)不等于15,则继续循环,否则执行下一语句

8048e15: 89 45 f4 在的元素值放回第一个数的位置???

8048e18: 83 fa 0f 8048e1b: 75 05

cmp $0xf,%edx

jne 8048e22

mov %eax,-0xc(%ebp)#将现#如果%edx不等于15,则爆炸,所以,要循环15次 8048e1d: 39 4d f0

cmp %ecx,-0x10(%ebp)

#累加的结果

8048e20: 74 05 #判断第二个数的值

8048e22: e8 aa 02 00 00 8048e27: 83 c4 20 8048e2a: 5b 8048e2b: 5e 8048e2c: 5d

call 80490d1 add $0x20,%esp #释放栈的操作 pop %ebx pop %esi pop %ebp

je 8048e27

8048e2d: c3

思路与分析:

ret movl $0x804a23e,0x4(%esp)仍然提示输入两个整型数字,and $0xf,%eax第一个数 “与” 0xf,这个操作可以只保留第一个数的二进制后四位(0“与”任何数都为0)。mov %eax,-0xc(%ebp)经过上面的操作后再把第一个数放回原来的位置(只保留二进制表示的后四位)。cmp $0xf,%eax和je 8048e22

比较,如果第一个数和0xf(1111)相等则爆炸,说明第一个数的二进制后四位不能为“1111”,否则爆炸。mov $0x804a1c0,%ebx这个地址为数组的首地址,求的值为第一个元素的值。求数组元素:p *0x804a1c0@16={10, 2, 14, 7, 8, 12, 15, 11, 0, 4, 1, 13, 3, 9, 6, 5}

通过分析汇编代码可以推出如下c代码:

# p *0x804a1c0@16={10, 2, 14, 7, 8, 12, 15, 11, 0, 4, 1, 13, 3, 9, 6, 5} # sum=0;# for(i=1;n!=15;i++){ # # # } # if(i==15)# return sum;n=a[n];sum+=n;n最后需要等于15,采用逆推的方法可以知道从开始到最后n的值分别为(因为开始循环之前取了一个n,所以总的有16个n):5,12,3,7,11,13,9,4,8,0,10,1,2,14,6,15、也就是说需要一开始传进去的值为5,循环15次后得到的元素值才为15。只要用户输入的第一位数的二进制的后四位是0101(5),则可以通过,所以第一个数有无穷多个。第二个数累加的结果为12+3+7+11+13+9+4+8+0+10+1+2+14+6+15=115。

所以两个数为 5 和 115。用户输入第一个数二进制下的后四位为0101(即第一个n=5),而之前位可以随意取值。因此有无数多的密码。如5 115;21 115等。随意输入一组即可通过关卡。

结论与心得:

这一关用到了循环链表,可以通过逆推的方法找到输入的第一个数字是什么,然后根据c代码确定累加的和。

6.phase_6 phase_6汇编代码及注释如下: 08048c89

: 8048c89: 55 8048c8a: 89 e5 8048c8c: 57 8048c8d: 56 8048c8e: 53 8048c8f: 83 ec 5c 间

8048c92: 8d 45 d0 8048c95: 89 44 24 04 8048c99: 8b 45 08 8048c9c: 89 04 24 8048c9f: e8 67 04 00 00

#输入六个数

mov $0x0,%esi #%esi=0

lea-0x30(%ebp),%eax mov %eax,0x4(%esp)mov 0x8(%ebp),%eax mov %eax,(%esp)call 804910b push %ebp mov %esp,%ebp push %edi push %esi push %ebx

sub $0x5c,%esp #开辟一个栈空 8048ca4: be 00 00 00 00 8048ca9: 8d 7d d0 lea-0x30(%ebp),%edi #指明的是当前数字,将第一个数的地址传递给%edi 8048cac: 8b 04 b7 将第一个数字给%eax,开始外层循环

sub $0x1,%eax #%eax--cmp $0x5,%eax

jbe 8048cbc

mov(%edi,%esi,4),%eax

# 8048caf: 83 e8 01 8048cb2: 83 f8 05 8048cb5: 76 05 #%eax小于等于5则跳过炸弹,说明当前数字要小于等于6,又因为是无符号的比较(jbe),所以还需要当前数字大于等于1,也就是当前数字只能取1,2,3,4,5,6 8048cb7: e8 15 04 00 00 8048cbc: 83 c6 01 #%esi=%esi+1=1 8048cbf: 83 fe 06 8048cc2: 74 22

cmp $0x6,%esi

je 8048ce6

call 80490d1 add $0x1,%esi#如果此时%esi等于6,则跳转到8048ce6,否则继续执行下一条指令 8048cc4: 8d 1c b7

lea(%edi,%esi,4),%ebx

#将当前数放到%ebx中

8048cc7: 89 75 b4 将%esi放到%ebp-4c中

8048cca: 8b 44 b7 fc

mov-0x4(%edi,%esi,4),%eaxmov %esi,-0x4c(%ebp)##将前一个数放到%eax中,开始内层循环 8048cce: 3b 03 8048cd0: 75 05

cmp(%ebx),%eax

jne 8048cd7

#比较当前数和前一个数,如果不相等则跳转到8048cd7,否则爆炸,所以前后两个数不能相等。

8048cd2: e8 fa 03 00 00 8048cd7: 83 45 b4 01 循环条件每次加1

call 80490d1 addl $0x1,-0x4c(%ebp)

# 8048cdb: 83 c3 04 到下一个数

8048cde: 83 7d b4 05 8048ce2: 7e e6

add $0x4,%ebx #地址加4,即

cmpl $0x5,-0x4c(%ebp)jle 8048cca

#小于等于5跳转到8048cca,继续内层循环,所以esi从0到5,需要循环6次,8048ce4: eb c6 #继续外层循环,跳到8048cac #从上面两个循环可以看出,外层循环要求输入的6个数要在0~6之间,内层循环要求两个相邻的数不能相同

8048ce6: bb 00 00 00 00 跳到此处,%ebx=0 8048ceb: 8d 7d d0 一个数的地址放到%edi中

8048cee: eb 16 #跳转到8048d06 8048cf0: 8b 52 08 数组第一个元素大于1,就跳转到这里

8048cf3: 83 c0 01 8048cf6: 39 c8 8048cf8: 75 f6 #如果%eax不等于%ecx,则继续循环 8048cfa: 89 54 b5 b8

mov %edx,-0x48(%ebp,%esi,4)add $0x1,%eax #%eax=1 cmp %ecx,%eax

jne 8048cf0

mov 0x8(%edx),%edx

#如果

jmp 8048d06

lea-0x30(%ebp),%edi #将第mov $0x0,%ebx #%esi等于6时jmp 8048cac

#如果数组第一个元素等于1,就跳转到这里, 8048cfe: 83 c3 01 8048d01: 83 fb 06 8048d04: 74 16

add $0x1,%ebx #%ebx=%ebx+1 cmp $0x6,%ebx

je 8048d1c

#如果%ebx=6,就跳转到8048d1c 8048d06: 89 de

mov %ebx,%esi #%esi=0 8048d08: 8b 0c 9f 将数组第一个元素放到%ecx中

8048d0b: ba c4 c0 04 08

mov(%edi,%ebx,4),%ecx

#mov $0x804c0c4,%edx #将地址0x804c0c4放到%edx中,p/x *0x804c0c4=0x1a7 8048d10: b8 01 00 00 00 8048d15: 83 f9 01 8048d18: 7f d6

mov $0x1,%eax #%eax=1 cmp $0x1,%ecx

jg 8048cf0

#如果数组第一个元素大于1,就跳转到8048cf0 8048d1a: eb de

jmp 8048cfa

#如果数组第一个元素等于1,就跳转到8048cfa 8048d1c: 8b 5d b8

mov-0x48(%ebp),%ebx #重新排列链表的值 #n[0] 8048d1f: 8b 45 bc 8048d22: 89 43 08 #n[0]+8=n[1] 8048d25: 8b 55 c0 8048d28: 89 50 08 #n[1]+8=n[2] 8048d2b: 8b 45 c4 8048d2e: 89 42 08 #n[2]+8=n[3] 8048d31: 8b 55 c8 8048d34: 89 50 08 #n[3]+8=n[4] 8048d37: 8b 45 cc 8048d3a: 89 42 08 #n[4]+8=n[5] 8048d3d: c7 40 08 00 00 00 00 表的值进行检测

movl $0x0,0x8(%eax)

#对链

mov-0x34(%ebp),%eax mov %eax,0x8(%edx)mov-0x38(%ebp),%edx mov %edx,0x8(%eax)mov-0x3c(%ebp),%eax mov %eax,0x8(%edx)mov-0x40(%ebp),%edx mov %edx,0x8(%eax)mov-0x44(%ebp),%eax mov %eax,0x8(%ebx)8048d44: be 00 00 00 00 8048d49: 8b 43 08 8048d4c: 8b 13 8048d4e: 3b 10 8048d50: 7d 05

mov $0x0,%esi mov 0x8(%ebx),%eax mov(%ebx),%edx cmp(%eax),%edx

jge 8048d57

#第二个元素大一第一个元素就跳过炸弹,所以需要降序排列 8048d52: e8 7a 03 00 00 8048d57: 8b 5b 08 8048d5a: 83 c6 01 8048d5d: 83 fe 05 8048d60: 75 e7

call 80490d1 mov 0x8(%ebx),%ebx add $0x1,%esi cmp $0x5,%esi

jne 8048d49

#数组中的每个元素都要满足降序排列 8048d62: 83 c4 5c 8048d65: 5b 8048d66: 5e 8048d67: 5f 8048d68: 5d 8048d69: c3

思路与分析:

call 804910b 指令提示输入6个数字。

add $0x5c,%esp #释放栈空间 pop %ebx pop %esi pop %edi pop %ebp ret mov(%edi,%esi,4),%eax #将第一个数字给%eax,开始外层循环

sub $0x1,%eax #%eax--cmp $0x5,%eax

jbe 8048cbc

8048caf: 83 e8 01 8048cb2: 83 f8 05 8048cb5: 76 05 #%eax小于等于5则跳过炸弹,说明当前数字要小于等于6,又因为是无符号的比较(jbe),所以还需要当前数字大于等于1,也就是当前数字只能取1,2,3,4,5,6 8048cb7: e8 15 04 00 00

call 80490d1 8048cbc: 83 c6 01 8048cbf: 83 fe 06 8048cc2: 74 22

add $0x1,%esi #%esi=%esi+1=1 cmp $0x6,%esi

je 8048ce6

#如果此时%esi等于6,则跳转到8048ce6,否则继续执行下一条指令 8048cc4: 8d 1c b7 前数放到%ebx中

8048cc7: 89 75 b4 到%ebp-4c中

8048cca: 8b 44 b7 fc

mov-0x4(%edi,%esi,4),%eax #mov %esi,-0x4c(%ebp)#将%esi放lea(%edi,%esi,4),%ebx

#将当将前一个数放到%eax中,开始内层循环 8048cce: 3b 03 8048cd0: 75 05

cmp(%ebx),%eax

jne 8048cd7

#比较当前数和前一个数,如果不相等则跳转到8048cd7,否则爆炸,所以前后两个数不能相等。

8048cd2: e8 fa 03 00 00 8048cd7: 83 45 b4 01 条件每次加1 8048cdb: 83 c3 04 一个数

8048cde: 83 7d b4 05 8048ce2: 7e e6

cmpl $0x5,-0x4c(%ebp)

jle 8048cca

#add $0x4,%ebx #地址加4,即到下call 80490d1 addl $0x1,-0x4c(%ebp)

#循环小于等于5跳转到8048cca,继续内层循环,所以esi从0到5,需要循环6次,8048ce4: eb c6 继续外层循环,跳到8048cac

这一段代码是一个嵌套的for循环,得出的结果是输入的6个数字为1-6之间的数字且相邻两个数字不能相等。

mov $0x0,%ebx #%esi等于6时跳到此处,%ebx=0

jmp 8048cac

# 8048ceb: 8d 7d d0 数的地址放到%edi中

8048cee: eb 16 跳转到8048d06 8048cf0: 8b 52 08 第一个元素大于1,就跳转到这里 8048cf3: 83 c0 01 8048cf6: 39 c8 8048cf8: 75 f6 如果%eax不等于%ecx,则继续循环 8048cfa: 89 54 b5 b8

lea-0x30(%ebp),%edi #将第一个

jmp 8048d06

#mov 0x8(%edx),%edx #如果数组

add $0x1,%eax #%eax=1 cmp %ecx,%eax

jne 8048cf0

#mov %edx,-0x48(%ebp,%esi,4)#如果数组第一个元素等于1,就跳转到这里, 8048cfe: 83 c3 01 8048d01: 83 fb 06 8048d04: 74 16 如果%ebx=6,就跳转到8048d1c 8048d06: 89 de 8048d08: 8b 0c 9f 组第一个元素放到%ecx中

8048d0b: ba c4 c0 04 08

mov $0x804c0c4,%edx #将地址mov %ebx,%esi #%esi=0 mov(%edi,%ebx,4),%ecx

#将数

add $0x1,%ebx #%ebx=%ebx+1 cmp $0x6,%ebx

je 8048d1c

#0x804c0c4放到%edx中,p/x *0x804c0c4=0x1a7 8048d10: b8 01 00 00 00 8048d15: 83 f9 01 8048d18: 7f d6

mov $0x1,%eax #%eax=1 cmp $0x1,%ecx

jg 8048cf0

#如果数组第一个元素大于1,就跳转到8048cf0 8048d1a: eb de

jmp 8048cfa

#如果数组第一个元素等于1,就跳转到8048cfa 这又是一个嵌套的for循环,根据用户输入的值来对链表的值进行排序,比如给出值 5 6 1 4 3 2,则将原来链表第 5个位置的值放到第1位,第6个位置的值放到第二位,依次类推。而下面检测链表值时,要求链表值按从大到小排列。通过指令查看链表的值为;#p/x *0x804c0c4=0x1a7 #p/x *0x804c0cc=0x804c0b8 #p/x *0x804c0b8=0x6c #p/x *0x804c0c0=0x804c0ac #p/x *0x804c0ac=0x155 #p/x *0x804c0b4=0x804c0a0 #p/x *0x804c0a0=0x187 #p/x *0x804c0a8=0x804c094 #p/x *0x804c094=0x3bd #p/x *0x804c09c=0x804c088 #p/x *0x804c088=0x255

所以对应关系为:1->0x1a7;2->0x6c;3->0x155;4->0x187;5->0x3bd;6->0x255。第二个数组按从大到小的顺序排列应该为:3bd 255 1a7 187 155 6c。所以,输入的数字应该为:5 6 1 4 3 2。输入这六个数字即可通过关卡。结论与心得:

这一关用到了排序与映射,首先确定输入的6个数字为1-6,然后将这6个数字与数组中的数字对应起来,根据数组中的数据应该降序排列确定输入数字的顺序即可。

通过全部关卡过程如下:

四、实验心得

这次实验phase_1至phase_3三关相对比较简单,也比较好理解。但phase_4至phase_6相对比较难,相应的c代码也不像前面三关一样简单易懂,更是加入了链表和映射等相关知识,着实花了不少功夫才弄懂。

通过这次试验,我对汇编代码有了进一步的了解,更加熟悉了汇编代码中各种指令的作用,我相信这样的一次实践对我今后学习理论课程以及更深入地理解计算机系统会很有帮助。

《Bomb Lab实验报告.docx》
将本文的Word文档下载,方便收藏和打印
推荐度:
Bomb Lab实验报告
点击下载文档
相关专题 shalllab实验报告 实验报告 Bomb Lab shalllab实验报告 实验报告 Bomb Lab
[其他范文]相关推荐
    [其他范文]热门文章
      下载全文