logo资料库

CSAPP bomblab实验报告.pdf

第1页 / 共14页
第2页 / 共14页
第3页 / 共14页
第4页 / 共14页
第5页 / 共14页
第6页 / 共14页
第7页 / 共14页
第8页 / 共14页
资料共14页,剩余部分请下载后查看
进制炸弹实验报告 登录putty服务器后,首先运行静态分析工具OBJDUMP 来获得程序的反汇编版本bomb.txt, 用 notepad++ 打开便可通过汇编代码来分析程序。 运行gdb bomb,开始进行动态调试。 首先找到explode_bomb的地址0x80492ab, 在爆炸函数的的入口设置断点,输入break *0x80492ab 这样就可以避免调试过程中各种原因引起的爆炸。 首先来看 phase1 的代码: 08048f19 : 8048f19: 55 push %ebp 8048f1a: 89 e5 mov %esp,%ebp 8048f1c: 83 ec 08 sub $0x8,%esp 8048f1f: c7 44 24 04 ec 98 04 movl $0x80498ec,0x4(%esp) 8048f26: 08 8048f27: 8b 45 08 mov 0x8(%ebp),%eax 8048f2a: 89 04 24 mov %eax,(%esp) 8048f2d: e8 39 00 00 00 call 8048f6b 8048f32: 85 c0 test %eax,%eax 8048f34: 74 05 je 8048f3b 8048f36: e8 70 03 00 00 call 80492ab
8048f3b: c9 leave 8048f3c: 8d 74 26 00 lea 0x0(%esi),%esi 8048f40: c3 ret 注意 strings_not_equal 这个函数,从字面上可以猜想地理解为:把输入的字符串和内存 某处字符串相比较,不相等的时候函数返回值的为 1。再看接下来两句: test %eax,%eax je 8048f3b Test 是把两个操作数进行与运算,而通常这两个操作数是一样的,此操作的意义就在于影 响标志位,当%eax 为 0 时,零标志位置 1,否则零标志为 0。而从 je 指令可以知道当%eax 为 0 时程序会跳过接下来一句对爆炸函数的引用,所以我们的目标就是要是 %eax 即 strings_not_equal 的返回值为 0,即要是输入的字符串与内存某处的存放的字符串相等。 于是现在的关键就是找出那个字符串是放在内存的哪个地方。其实非常明显,$0x80498ec 这 个地址在程序里实在太显眼,用 x/s 0x80498ec 命令一查,果然那里存放有一句话:"The future will be better tomorrow." 输入进去之后出现如下提示开始第二个炸弹: 然后来看 phase2: 08048eb9 : 8048eb9: 55 push %ebp 8048eba: 89 e5 mov %esp,%ebp 8048ebc: 56 push %esi 8048ebd: 53 push %ebx 8048ebe: 83 ec 30 sub $0x30,%esp 8048ec1: 8d 45 e0 lea -0x20(%ebp),%eax 8048ec4: 89 44 24 04 mov %eax,0x4(%esp) 8048ec8: 8b 45 08 mov 0x8(%ebp),%eax 8048ecb: 89 04 24 mov %eax,(%esp) 8048ece: e8 1a 04 00 00 call 80492ed 8048ed3: 83 7d e0 01 cmpl $0x1,-0x20(%ebp) 8048ed7: 74 29 je 8048f02 8048ed9: e8 cd 03 00 00 call 80492ab 8048ede: 66 90 xchg %ax,%ax 8048ee0: eb 20 jmp 8048f02 8048ee2: 89 da mov %ebx,%edx 8048ee4: 83 c3 01 add $0x1,%ebx 8048ee7: 89 d8 mov %ebx,%eax 8048ee9: 0f af 44 96 fc imul -0x4(%esi,%edx,4),%eax
8048eee: 39 04 96 cmp %eax,(%esi,%edx,4) 8048ef1: 74 05 je 8048ef8 8048ef3: e8 b3 03 00 00 call 80492ab 8048ef8: 83 fb 06 cmp $0x6,%ebx 8048efb: 75 e5 jne 8048ee2 8048efd: 8d 76 00 lea 0x0(%esi),%esi 8048f00: eb 10 jmp 8048f12 8048f02: bb 01 00 00 00 mov $0x1,%ebx 8048f07: 8d 75 e0 lea -0x20(%ebp),%esi 8048f0a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi 8048f10: eb d0 jmp 8048ee2 8048f12: 83 c4 30 add $0x30,%esp 8048f15: 5b pop %ebx 8048f16: 5e pop %esi 8048f17: 5d pop %ebp 8048f18: c3 ret 分析解答: 注意到 read_six_numbers 这个函数,同样顾名思义我先猜他为输入 6 个数字。暂且不看 read_six_numbers 函数的内容,先注意 8048ed3 这句,cmpl 显然是要引起我高度注意的, 因为比较的结果往往直接关系到爆不爆的问题。这条指令的内容很明确,就是看 -0x20(%ebp) 处的数字是否为 1,不是的话就会调用爆炸函数。于是我非常坚定地认为 1 便是我该输入的 第一个数字,而输入的数字是存放在 -0x20(%ebp) 开始的地址处的。 接着看下去: 8048ee9: 0f af 44 96 fc imul -0x4(%esi,%edx,4),%eax 8048eee: 39 04 96 cmp %eax,(%esi,%edx,4) 及 8048f07: 8d 75 e0 lea -0x20(%ebp),%esi 8048ee9 这句中的 -0x4(%esi,%edx,4) 这个存储器操作数稍作思考便可以知道其实就是 -0x20(%ebp),即是我们要输入的第一个数字,因为此时%eax 为 2。所以这句是将第一个数 字乘以 2 放入%eax。8048eee 中将 %eax 和 (%esi,%edx,4)进行比较,相等则继续运行, 很容易看出(%esi,%edx,4)即-0x1c(%ebp)是我们输入第 2 个数字的地方。 8048ef8 和 8048efb 两句告诉我们从%ebx 等于 1 到 5 进行以上操作,即后面一个数字由 前面一个数字乘以%eax 得到,而每次的乘数%eax 为%ebx 加 1,即乘数分别为 2,3,4,5, 6,所以可以确定这六个数字分别为 1,2,3,4,5,6 的阶乘,即 1 2 6 24 120 720。 于是输入,果然:That's number 2. Keep going!
08048e11 : 8048e11: 55 push %ebp 8048e12: 89 e5 mov %esp,%ebp 8048e14: 83 ec 28 sub $0x28,%esp 8048e17: 8d 45 f8 lea -0x8(%ebp),%eax 8048e1a: 89 44 24 0c mov %eax,0xc(%esp) 8048e1e: 8d 45 fc lea -0x4(%ebp),%eax 8048e21: 89 44 24 08 mov %eax,0x8(%esp) 8048e25: c7 44 24 04 eb 9a 04 movl $0x8049aeb,0x4(%esp) 8048e2c: 08 8048e2d: 8b 45 08 mov 0x8(%ebp),%eax 8048e30: 89 04 24 mov %eax,(%esp) 8048e33: e8 44 fb ff ff call 804897c 8048e38: 83 f8 01 cmp $0x1,%eax 8048e3b: 7f 05 jg 8048e42 8048e3d: e8 69 04 00 00 call 80492ab 8048e42: 83 7d fc 07 cmpl $0x7,-0x4(%ebp) 8048e46: 66 90 xchg %ax,%ax 8048e48: 77 50 ja 8048e9a 8048e4a: 8b 45 fc mov -0x4(%ebp),%eax 8048e4d: 8d 76 00 lea 0x0(%esi),%esi 8048e50: ff 24 85 20 99 04 08 jmp *0x8049920(,%eax,4) 8048e57: b8 10 01 00 00 mov $0x110,%eax 8048e5c: 8d 74 26 00 lea 0x0(%esi),%esi 8048e60: eb 48 jmp 8048eaa 8048e62: b8 83 01 00 00 mov $0x183,%eax 8048e67: 90 nop 8048e68: eb 40 jmp 8048eaa 8048e6a: b8 ab 02 00 00 mov $0x2ab,%eax 8048e6f: 90 nop 8048e70: eb 38 jmp 8048eaa 8048e72: b8 24 03 00 00 mov $0x324,%eax 8048e77: 90 nop 8048e78: eb 30 jmp 8048eaa 8048e7a: b8 7a 02 00 00 mov $0x27a,%eax 8048e7f: 90 nop 8048e80: eb 28 jmp 8048eaa 8048e82: b8 37 01 00 00 mov $0x137,%eax 8048e87: 90 nop 8048e88: eb 20 jmp 8048eaa 8048e8a: b8 ed 02 00 00 mov $0x2ed,%eax 8048e8f: 90 nop 8048e90: eb 18 jmp 8048eaa 8048e92: b8 6b 03 00 00 mov $0x36b,%eax
8048e97: 90 nop 8048e98: eb 10 jmp 8048eaa 8048e9a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi 8048ea0: e8 06 04 00 00 call 80492ab 8048ea5: b8 00 00 00 00 mov $0x0,%eax 8048eaa: 3b 45 f8 cmp -0x8(%ebp),%eax 8048ead: 8d 76 00 lea 0x0(%esi),%esi 8048eb0: 74 05 je 8048eb7 8048eb2: e8 f4 03 00 00 call 80492ab 8048eb7: c9 leave 8048eb8: c3 ret 分析解答: Bomb3 的代码就比较长了,先抓住重点:jmp *0x8049920(,%eax,4)这句话容易让人联想到 switch 语句。再翻翻书,发现这段代码就是一个跳转表结构。从语句上便可以看出备选的 跳转地址存放在 0x8049920 开始的地址处,通过%eax 的值来选择。通过打印 0x8049920 处 的 16 进制数可以确认: switch 转换表是这样的: 0x08049920 0x8048e62 0x8048e57 0x8048e6a 0x8048e72 0x8048e7a 0x8048e82 0x8048e8a 0x8048e92 可以看到这 8 个 16 进制数正好是程序中的 8 个地址(都用黑体标出),对应于%eax 为 0 到 7 时的跳转地址。由于
cmp $0x1,%eax jg 8048e42 两句限定了%eax 大于 1,所以我取%eax 为 2,然后查表到 0x8048e6a 处。由: 8048e57: b8 10 01 00 00 mov $0x110,%eax 8048e6a: b8 ab 02 00 00 mov $0x2ab,%eax 容易得出对应于 1 结果为 272,对应于 2 结果为 683。 于是输入:1 272 2 683 果然 Halfway there! 当然对应于不同的输入个数,有不同的答案。 接下来是第四个炸弹: 08048dbf : 8048dbf: 55 push %ebp 8048dc0: 89 e5 mov %esp,%ebp 8048dc2: 83 ec 28 sub $0x28,%esp 8048dc5: 8d 45 fc lea -0x4(%ebp),%eax 8048dc8: 89 44 24 08 mov %eax,0x8(%esp) 8048dcc: c7 44 24 04 ee 9a 04 movl $0x8049aee,0x4(%esp) 8048dd3: 08 8048dd4: 8b 45 08 mov 0x8(%ebp),%eax 8048dd7: 89 04 24 mov %eax,(%esp) 8048dda: e8 9d fb ff ff call 804897c 8048ddf: 83 f8 01 cmp $0x1,%eax 8048de2: 75 06 jne 8048dea 8048de4: 83 7d fc 00 cmpl $0x0,-0x4(%ebp) 8048de8: 7f 0b jg 8048df5 8048dea: 8d b6 00 00 00 00 lea 0x0(%esi),%esi 8048df0: e8 b6 04 00 00 call 80492ab 8048df5: 8b 45 fc mov -0x4(%ebp),%eax 8048df8: 89 04 24 mov %eax,(%esp) 8048dfb: e8 d0 fd ff ff call 8048bd0 8048e00: 83 f8 37 cmp $0x37,%eax 8048e03: 74 05 je 8048e0a 8048e05: e8 a1 04 00 00 call 80492ab 8048e0a: c9 leave 8048e0b: 90 nop 8048e0c: 8d 74 26 00 lea 0x0(%esi),%esi
8048e10: c3 ret 相关函数 func4: 08048bd0 : 8048bd0: 55 push %ebp 8048bd1: 89 e5 mov %esp,%ebp 8048bd3: 83 ec 18 sub $0x18,%esp 8048bd6: 89 5d f8 mov %ebx,-0x8(%ebp) 8048bd9: 89 75 fc mov %esi,-0x4(%ebp) 8048bdc: 8b 75 08 mov 0x8(%ebp),%esi 8048bdf: b8 01 00 00 00 mov $0x1,%eax 8048be4: 83 fe 01 cmp $0x1,%esi 8048be7: 7e 1a jle 8048c03 8048be9: 8d 46 ff lea -0x1(%esi),%eax 8048bec: 89 04 24 mov %eax,(%esp) 8048bef: e8 dc ff ff ff call 8048bd0 8048bf4: 89 c3 mov %eax,%ebx 8048bf6: 8d 46 fe lea -0x2(%esi),%eax 8048bf9: 89 04 24 mov %eax,(%esp) 8048bfc: e8 cf ff ff ff call 8048bd0 8048c01: 01 d8 add %ebx,%eax 8048c03: 8b 5d f8 mov -0x8(%ebp),%ebx 8048c06: 8b 75 fc mov -0x4(%ebp),%esi 8048c09: 89 ec mov %ebp,%esp 8048c0b: 5d pop %ebp 8048c0c: c3 ret 分析解答: 首先要研究下 func4 的功能。 容易看出是一个递归函数。lea -0x1(%esi),%eax 是得到%esi-1 的值然后调用 func4,同 样 lea -0x2(%esi),%eax 是得到%esi-2 的值然后调用 func4,add %ebx,%eax 即是将 f (%esi-1)的返回值(在%ebx 里面)与 f(%esi-2)的返回值(在%eax 里面)相加放在%eax 中作为 func4 的返回值,很明显这是一个斐波那契数列的函数。 细节研究可知: func4(0) = 1,func4(1) = 1; func4(2) = func4(1) + func4(0) = 2; func4(3) = func4(2) + func4(1) = 3; func4(4) = func4(3) + func4(2) = 5; ... func4(9) = func4(8) + func4(7) = 55; 明白了 func4 的意思,我直插 phase4 的心脏: cmp $0x37,%eax je 8048e0a 很清楚,当%eax 等于 0x37 的时候就可以过关了。%eax 就是 call 8048bd0 后的返
回值!调用的函数参数就是我们输入的数字。把斐波那契数列一排,0x37 对应的序号为 9, 输入,果然:So you got that one. Try this one. 第五个 bomb: 08048d6e : 8048d6e: 55 push %ebp 8048d6f: 89 e5 mov %esp,%ebp 8048d71: 57 push %edi 8048d72: 56 push %esi 8048d73: 53 push %ebx 8048d74: 83 ec 0c sub $0xc,%esp 8048d77: 8b 75 08 mov 0x8(%ebp),%esi 8048d7a: 89 34 24 mov %esi,(%esp) 8048d7d: e8 ce 01 00 00 call 8048f50 8048d82: 83 f8 06 cmp $0x6,%eax 8048d85: 74 05 je 8048d8c 8048d87: e8 1f 05 00 00 call 80492ab 8048d8c: ba 00 00 00 00 mov $0x0,%edx 8048d91: b9 00 00 00 00 mov $0x0,%ecx 8048d96: bb 40 99 04 08 mov $0x8049940,%ebx 8048d9b: 0f be 04 16 movsbl (%esi,%edx,1),%eax 8048d9f: 83 e0 0f and $0xf,%eax 8048da2: 03 0c 83 add (%ebx,%eax,4),%ecx 8048da5: 83 c2 01 add $0x1,%edx 8048da8: 83 fa 06 cmp $0x6,%edx 8048dab: 75 ee jne 8048d9b 8048dad: 83 f9 1b cmp $0x1b,%ecx 8048db0: 74 05 je 8048db7 8048db2: e8 f4 04 00 00 call 80492ab 8048db7: 83 c4 0c add $0xc,%esp 8048dba: 5b pop %ebx 8048dbb: 5e pop %esi 8048dbc: 5f pop %edi 8048dbd: 5d pop %ebp 8048dbe: c3 ret 分析解答: 首先,call 8048f50 和 cmp $0x6,%eax 两句告诉我们要输入的是 6 个字 符。在指令 movsbl (%esi,%edx,1),%eax 中,%esi 为 6 个字符的起始地址,通过循环增 加%edx 的值来依次将这 6 个字符的 ASCII 码传给%eax 进行下一步操作。
分享到:
收藏