logo资料库

二进制拆弹实验报告(内含详细过程分析,系统级编程课程实验).docx

第1页 / 共19页
第2页 / 共19页
第3页 / 共19页
第4页 / 共19页
第5页 / 共19页
第6页 / 共19页
第7页 / 共19页
第8页 / 共19页
资料共19页,剩余部分请下载后查看
系统级编程实验——二进制拆弹 一, 前言 实验环境:window7 工具:objdump.exe,gdb.exe 材料:bomb.exe 准备:在 cmd.exe 中用 objdump.exe 反汇编 bomb.exe 并将反汇编的内容保存到一个 txt 文件里面,后面分析会用到。我的实验目录结构是 D:/test,所以在实验室只需 cd 到这个文 件夹里面即可对 objdump.exe,gdb.exe,bomb.exe 进行操作。 关键操作:调试时常用的操作有 设断点 break phase_1 r 运行 单步执行 s 查看寄存器 info reg 查看某个内存内容 x/2xh x/1sb x/1xb 等。 二, 拆弹分析 查看文件 boom.c, main 函数里面的内容用文字描述就是从屏幕读取一行字符串,将 字符串传入 phase_x 处理,说明是否爆炸由 phase_x 函数决定,phase_x 函数需要重点分析。 反汇编的 main 函数也是如此,代码如下 读取 phase_1 40175b: 401762: 401767: 40176c: 401770: 401774: 401777: 40177c: 读取 phase_2 401781: 401788: 40178d: 401792: 401796: 40179a: 40179d: 4017a2: c7 04 24 dc 60 40 00 e8 89 28 00 00 e8 53 07 00 00 89 44 24 1c 8b 44 24 1c 89 04 24 e8 ca 00 00 00 e8 4d 08 00 00 c7 04 24 08 61 40 00 e8 63 28 00 00 e8 2d 07 00 00 89 44 24 1c 8b 44 24 1c 89 04 24 e8 c8 00 00 00 e8 27 08 00 00 读取 phase_3 4017a7: 4017ae: 4017b3: 4017b8: 4017bc: c7 04 24 31 61 40 00 e8 3d 28 00 00 e8 07 07 00 00 89 44 24 1c 8b 44 24 1c movl call call mov mov mov call call movl call call mov mov mov call call movl call call mov mov $0x4060dc,(%esp) 403ff0 <_puts> 401ebf <_read_line> %eax,0x1c(%esp) 0x1c(%esp),%eax %eax,(%esp) 401846 <_phase_1> 401fce <_phase_defused> $0x406108,(%esp) 403ff0 <_puts> 401ebf <_read_line> %eax,0x1c(%esp) 0x1c(%esp),%eax %eax,(%esp) 40186a <_phase_2> 401fce <_phase_defused> $0x406131,(%esp) 403ff0 <_puts> 401ebf <_read_line> %eax,0x1c(%esp) 0x1c(%esp),%eax
4017c0: 4017c3: 4017c8: 89 04 24 e8 fd 00 00 00 e8 01 08 00 00 读取 phase_4 4017cd: 4017d4: 4017d9: 4017de: 4017e2: 4017e6: 4017e9: 4017ee: c7 04 24 4f 61 40 00 e8 17 28 00 00 e8 e1 06 00 00 89 44 24 1c 8b 44 24 1c 89 04 24 e8 37 02 00 00 e8 db 07 00 00 读取 phase_5 call c7 04 24 60 61 40 00 e8 f1 27 00 00 4017f3: 4017fa: 4017ff:e8 bb 06 00 00 401804: 89 44 24 1c 8b 44 24 1c 401808: 89 04 24 40180c: 40180f: e8 59 02 00 00 e8 b5 07 00 00 401814: 读取 pahse_6 401819: 401820: 401825: 40182a: 40182e: 401832: 401835: 40183a: c7 04 24 84 61 40 00 e8 cb 27 00 00 e8 95 06 00 00 89 44 24 1c 8b 44 24 1c 89 04 24 e8 a5 02 00 00 e8 8f 07 00 00 mov call call movl call call mov mov mov call call %eax,(%esp) 4018c5 <_phase_3> 401fce <_phase_defused> $0x40614f,(%esp) 403ff0 <_puts> 401ebf <_read_line> %eax,0x1c(%esp) 0x1c(%esp),%eax %eax,(%esp) 401a25 <_phase_4> 401fce <_phase_defused> movl call $0x406160,(%esp) 403ff0 <_puts> 401ebf <_read_line> mov mov mov call call movl call call mov mov mov call call %eax,0x1c(%esp) 0x1c(%esp),%eax %eax,(%esp) 401a6d <_phase_5> 401fce <_phase_defused> $0x406184,(%esp) 403ff0 <_puts> 401ebf <_read_line> %eax,0x1c(%esp) 0x1c(%esp),%eax %eax,(%esp) 401adf <_phase_6> 401fce <_phase_defused> 一, 第一颗:第一颗比较简单,就是将你输入的字符串与程序自带的字符串相比较, 如果相等则拆弹成功,不相等则调用炸弹函数。 00401846 <_phase_1>: 401846: 401847: 401849: 40184c: 401853: 401854: 401857: 40185a: 40185f: 401861: 401863: 55 89 e5 83 ec 18 c7 44 24 04 a2 61 40 00 8b 45 08 89 04 24 e8 53 05 00 00 85 c0 74 05 e8 3c 07 00 00 push mov sub movl mov mov call test je call %ebp %esp,%ebp $0x18,%esp $0x4061a2,0x4(%esp) 0x8(%ebp),%eax %eax,(%esp) 401db2 <_strings_not_equal> %eax,%eax 401868 <_phase_1+0x22> 401fa4 <_explode_bomb>
在刚进入这个 phase_1 时,传给 phase_1 的参数放在 phase_1 的 0x(8%ebp)里面 c7 44 24 04 a2 61 40 的, 40184c: 401854: 8b 45 08 401857: 89 04 24 40185a: e8 53 05 00 00 movl mov mov call $0x4061a2,0x4(%esp) 0x8(%ebp),%eax %eax,(%esp) 401db2 <_strings_not_equal> 参数几经周转最终存放到(%esp),程序自带的字符串首地址$0x4061a2 放在 4(%esp),调用 call 401db2 <_strings_not_equal>字符串比较函数比较输入的字符串 与程序自带的字符串,如果不相等则调用炸弹函数。因此需要输入的字符串就是 0x4061a2 处的字符串 所以猜测第一个钥匙就是 Public speaking is very easy. 输入看看 第一个炸弹拆弹成功。 二, 第二颗,第二颗比较麻烦,花了我很多时间才把代码看懂,尽管在网上看了些 参考 0040186a <_phase_2>: 55 40186a: 89 e5 40186b: 83 ec 38 40186d: 8d 45 dc 401870: 89 44 24 04 401873: 8b 45 08 401877: 89 04 24 40187a: e8 9d 04 00 00 40187d: 8b 45 dc 401882: 83 f8 01 401885: 74 05 401888: 40188a: e8 15 07 00 00 40188f:c7 45 f4 01 00 00 00 401896: 401899: 40189c: 4018a0: 4018a3: 8b 45 f4 83 e8 01 8b 44 85 dc 8b 55 f4 83 c2 01 push mov sub lea mov mov mov call mov cmp je call movl mov sub mov mov add %ebp %esp,%ebp $0x38,%esp -0x24(%ebp),%eax %eax,0x4(%esp) 0x8(%ebp),%eax %eax,(%esp) 401d1f <_read_six_numbers> -0x24(%ebp),%eax $0x1,%eax 40188f <_phase_2+0x25> 401fa4 <_explode_bomb> $0x1,-0xc(%ebp) -0xc(%ebp),%eax $0x1,%eax -0x24(%ebp,%eax,4),%eax -0xc(%ebp),%edx $0x1,%edx
4018a6: 4018a9: 4018ac: 4018b0: 4018b2: 4018b4: 4018b9: 4018bd: 4018c1: 4018c3: 4018c4: 0f af d0 8b 45 f4 8b 44 85 dc 39 c2 74 05 e8 eb 06 00 00 83 45 f4 01 83 7d f4 05 7e d3 c9 c3 %eax,%edx -0xc(%ebp),%eax -0x24(%ebp,%eax,4),%eax %eax,%edx 4018b9 <_phase_2+0x4f> 401fa4 <_explode_bomb> $0x1,-0xc(%ebp) $0x5,-0xc(%ebp) 401896 <_phase_2+0x2c> imul mov mov cmp je call addl cmpl jle leave ret 上面是 phase_2 的反汇编代码,下面代码的意思是将-0x24(%ebp)处的地址存放到 0x4(%esp)中,将 0x8(%ebp)处的内容放到(%esp)中,然后调用 read_six _numbers 401870: 401873: 401877: 40187a: 40187d: 8d 45 dc 89 44 24 04 8b 45 08 89 04 24 e8 9d 04 00 00 lea mov mov mov call -0x24(%ebp),%eax %eax,0x4(%esp) 0x8(%ebp),%eax %eax,(%esp) 401d1f <_read_six_numbers> 因为看到 read_six_numbers 函数所以推测拆弹钥匙是 6 个数字,所以随便输入 6 个数字,调 试,phase_2 的 EBP 值是 0x28fec8, 那么 0x8(%ebp)的值是 0x28fed0,看看 0x28fed0 里面是什 么 0x8(%ebp)里面明显存放的是输入的字符串的首地址,这在调用 read_six_numbers 之前将其 放到(%esp)里面。 40187d: 401882: 401885: e8 9d 04 00 00 8b 45 dc 83 f8 01 call mov cmp 401d1f <_read_six_numbers> -0x24(%ebp),%eax $0x1,%eax 这里调用 read_six_numbers 函数后就直接从-0x24(%ebp)里面取内容跟 1 作比较,根 据上面-0x24(%ebp)处的地址存放到 0x4(%esp)中,可以猜出将我输入的字符串中的 数 字 通 过 read_six_numers 函 数 提 取 出 来 放 到 了 -0x24(%ebp) 处 , -0x24(%ebp)=0x28fea4 验证一下, 果然,就是输入的那几个数字。
401885: 83 f8 01 401888: 74 05 40188a: e8 15 07 00 00 cmp $0x1,%eax je 40188f <_phase_2+0x25> call 401fa4 <_explode_bomb> 这一段是判断第一个数字如果不等于 1 那么调用炸弹, c7 45 f4 01 00 00 00 40188f: 401896: 8b 45 f4 401899: 83 e8 01 40189c: 8b 44 85 dc 4018a0: 8b 55 f4 4018a3: 83 c2 01 4018a6: 0f af d0 4018a9: 8b 45 f4 4018ac: 8b 44 85 dc 4018b0: 39 c2 4018b2: 74 05 movl mov sub mov mov add imul mov mov $0x1,-0xc(%ebp) -0xc(%ebp),%eax $0x1,%eax -0x24(%ebp,%eax,4),%eax -0xc(%ebp),%edx $0x1,%edx %eax,%edx -0xc(%ebp),%eax -0x24(%ebp,%eax,4),%eax cmp je %eax,%edx 4018b9 <_phase_2+0x4f> 4018b4: e8 eb 06 00 00 call 401fa4 <_explode_bomb> 4018b9: 83 45 f4 01 4018bd: 83 7d f4 05 4018c1: 7e d3 addl cmpl $0x1,-0xc(%ebp) $0x5,-0xc(%ebp) jle 401896 <_phase_2+0x2c> 上面这一段的意思用我自己的话描述就是假设输入的 6 个数为 a1,a2,a3,a4,a5,a6. 他们必须满足关系 a1*2=a2 a2*3=a3; a3*4=a4 a4*5=a5 a5*6=a6 否则就会爆炸 而上面规定 a1 必须等于 1,所以一次算出 6 个数分别是 1,2,6,24,120,720 输入试试看, 成功。 三, 第三颗,第三颗是一个 switch 结构,看代码。汉字是我标注的。 004018c5 <_phase_3>: 4018c5: 4018c6: 4018c8: 55 89 e5 83 ec 38 push mov sub %ebp %esp,%ebp $0x38,%esp
停 1 8d 45 f0 89 44 24 10 8d 45 ef 89 44 24 0c 8d 45 e8 89 44 24 08 c7 44 24 04 c0 61 40 00 8b 45 08 89 04 24 e8 05 27 00 00 4018cb: 4018ce: 4018d2: 4018d5: 4018d9: 4018dc: 4018e0: 4018e7: 4018e8: 4018eb: 4018ee: 4018f3:83 f8 02 4018f6:7f 05 lea mov lea mov lea mov movl mov mov call cmp jg -0x10(%ebp),%eax %eax,0x10(%esp) -0x11(%ebp),%eax %eax,0xc(%esp) -0x18(%ebp),%eax %eax,0x8(%esp) $0x4061c0,0x4(%esp) 0x8(%ebp),%eax %eax,(%esp) 403ff8 <_sscanf> $0x2,%eax 4018fd <_phase_3+0x38> 满 足 此 条件 4018f8:e8 a7 06 00 00 call 401fa4 <_explode_bomb> 停 2 4018fd:8b 45 e8 401900: 401903: 83 f8 07 0f 87 c9 00 00 00 条会爆炸 401909: 401910: 8b 04 85 cc 61 40 00 ff e0 mov cmp ja mov jmp -0x18(%ebp),%eax $0x7,%eax 4019d2 <_phase_3+0x10d>执行此 0x4061cc(,%eax,4),%eax *%eax case 1: 401912: 401916: 401919: 40191e: 401920: 401925: 40192a: case 2: c6 45 f7 71 8b 45 f0 3d 09 03 00 00 74 0a e8 7f 06 00 00 e9 b1 00 00 00 e9 ac 00 00 00 40192f:c6 45 f7 62 401933: 401936: 40193b: 40193d: 401942: 401947: 8b 45 f0 3d d6 00 00 00 74 0a e8 62 06 00 00 e9 94 00 00 00 e9 8f 00 00 00 case 3: 40194c: 401950: 401953: 401958: c6 45 f7 62 8b 45 f0 3d f3 02 00 00 74 07 movb mov cmp $0x71,-0x9(%ebp) -0x10(%ebp),%eax $0x309,%eax je 40192a <_phase_3+0x65> call jmp jmp 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> movb mov cmp $0x62,-0x9(%ebp) -0x10(%ebp),%eax $0xd6,%eax je 401947 <_phase_3+0x82> call jmp jmp 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> movb mov cmp $0x62,-0x9(%ebp) -0x10(%ebp),%eax $0x2f3,%eax je 401961 <_phase_3+0x9c>
e8 45 06 00 00 40195a: 40195f:eb 7a 401961: eb 78 case 4: 401963: 401967: 40196a: 40196f:74 07 401971: 401976: 401978: c6 45 f7 6b 8b 45 f0 3d fb 00 00 00 e8 2e 06 00 00 eb 63 eb 61 case 5: 40197a: 40197e: 401981: 401986: 401988: 40198d: 40198f:eb 4a c6 45 f7 6f 8b 45 f0 3d a0 00 00 00 74 07 e8 17 06 00 00 eb 4c case 6: c6 45 f7 74 8b 45 f0 3d ca 01 00 00 74 07 401991: 401995: 401998: 40199d: 40199f:e8 00 06 00 00 4019a4: 4019a6: eb 35 eb 33 case 7: 4019a8: c6 45 f7 76 4019ac: 8b 45 f0 4019af:3d 0c 03 00 00 4019b4: 4019b6: 74 05 e8 e9 05 00 00 case 8: c6 45 f7 62 4019bb: 4019bf:8b 45 f0 4019c2: 4019c7: 4019c9: 4019ce: 4019d0: 4019d2: 4019d6: 3d 0c 02 00 00 74 07 e8 d6 05 00 00 eb 0b eb 09 c6 45 f7 78 e8 c9 05 00 00 call jmp jmp 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> movb mov cmp je call jmp jmp movb mov cmp je call jmp jmp movb mov cmp je call jmp jmp movb mov cmp je call movb mov cmp je call jmp jmp movb call $0x6b,-0x9(%ebp) -0x10(%ebp),%eax $0xfb,%eax 401978 <_phase_3+0xb3> 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> $0x6f,-0x9(%ebp) -0x10(%ebp),%eax $0xa0,%eax 40198f <_phase_3+0xca> 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> $0x74,-0x9(%ebp) -0x10(%ebp),%eax $0x1ca,%eax 4019a6 <_phase_3+0xe1> 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> $0x76,-0x9(%ebp) -0x10(%ebp),%eax $0x30c,%eax 4019bb <_phase_3+0xf6> 401fa4 <_explode_bomb> $0x62,-0x9(%ebp) -0x10(%ebp),%eax $0x20c,%eax 4019d0 <_phase_3+0x10b> 401fa4 <_explode_bomb> 4019db <_phase_3+0x116> 4019db <_phase_3+0x116> $0x78,-0x9(%ebp) 401fa4 <_explode_bomb>
0f b6 45 ef 4019db: 4019df:3a 45 f7 4019e2: 4019e4: 74 05 e8 bb 05 00 00 movzbl -0x11(%ebp),%eax -0x9(%ebp),%al cmp 4019e9 <_phase_3+0x124> je call 401fa4 <_explode_bomb> 4019e9: 4019ea: c9 c3 leave ret Phase_3 的 开 头 跟 上 phase_1,phase_2 一 样 , 都 是 把 我 输 入 的 字 符 串 放 到 0x8(%ebp)里面, 4018cb: 4018ce: 4018d2: 4018d5: 4018d9: 4018dc: 4018e0: 4018e7: 4018e8: 4018eb: 4018ee: 8d 45 f0 89 44 24 10 8d 45 ef 89 44 24 0c 8d 45 e8 89 44 24 08 c7 44 24 04 c0 61 40 00 8b 45 08 89 04 24 e8 05 27 00 00 lea mov lea mov lea mov movl mov mov call -0x10(%ebp),%eax %eax,0x10(%esp) -0x11(%ebp),%eax %eax,0xc(%esp) -0x18(%ebp),%eax %eax,0x8(%esp) $0x4061c0,0x4(%esp) 0x8(%ebp),%eax %eax,(%esp) 403ff8 <_sscanf> 上面这一段的意思就是将-0x10(%ebp)的地址存放到 0x10(%esp)中,-0x11(%ebp) 的地址放到 0xc(%esp)中,将-0x18(%ebp)的地址放到 0x8(%esp)中,上面黄色字体 0x4061c0 不知道是什么,查看一下, 这是 C 语言的输入格式控制,表示输入的内容是数字 字符 数字,所以根据前 面的经验,可以猜测读取的内容分别放到了-0x10(%ebp),-0x11(%ebp),-0x18(%ebp) 里面,查看这三个地址中的内容, 十六进制的 0xfb 就是 251,输入的第三个数字,0x28feb0 处是第一个数字 3, 0x28feb7 处的 0x6b,其实就 k 的数字表示 107,107 转换为十六进制就是 0x6b。接着 往后看, 83 f8 02 7f 05 e8 a7 06 00 00 4018f3: 4018f6: 4018f8: 这里的%eax 里面的值是 3 怎么放进去的我也没想清楚,说明就是用第一个数 字与 0x2 作比较,看样子如果不大于 2 就会爆炸所以得出结论第一个数字必须大于 2.再往后 就跳到了 0x4018fd 了, $0x2,%eax 4018fd <_phase_3+0x38> 401fa4 <_explode_bomb> cmp jg call
分享到:
收藏