这个题的本质是让通过gdb和objdump的工具的使用,以及对汇编代码的理解找到程序在栈中已存在的数据或者汇编代码本身的代码逻辑。从而根据固有信息确定输入,使得炸弹得以解除。这个实验有6道关卡和一道隐藏关卡。由于时间原因,我并没有想方法找出隐藏关,只是把固有的6道关卡做完了。下面说一下解题步骤。
由于炸弹爆炸是要扣分的,所以最开始需要做的任务是在炸弹爆炸函数的入口设置一个断点。这样一来当发现运行到这个断点之后就可以重新开始gdb的运行,使得爆炸函数得不到运行。由于是只有通过前一关后才能做后一关所以当做到后面几关的时候,要把前几关的答案放在一个文档里,然后运行gdb时指定这个文件,就会自动通过前几关。
关于gdb的使用可以看我的另一篇文章。
上代码:
08048b90 <phase_1>: 8048b90: 55 push %ebp 8048b91: 89 e5 mov %esp,%ebp 8048b93: 83 ec 18 sub $0x18,%esp 8048b96: c7 44 24 04 e4 a2 04 movl $0x804a2e4,0x4(%esp) 8048b9d: 08 8048b9e: 8b 45 08 mov 0x8(%ebp),%eax 8048ba1: 89 04 24 mov %eax,(%esp) 8048ba4: e8 a2 04 00 00 call 804904b <strings_not_equal> 8048ba9: 85 c0 test %eax,%eax 8048bab: 74 05 je 8048bb2 <phase_1+0x22> 8048bad: e8 86 07 00 00 call 8049338 <explode_bomb> 8048bb2: c9 leave 8048bb3: c3 ret
以上是通过用objdump工具反汇编bomb可执行程序后得到的汇编代码文件中第一关的代码。这个代码的意义非常简单。通读下来发现首先确定栈的大小。然后为函数strings_not_equal准备参数。参数总共有两个一个是用户自己输入的字符串。由于是字符串,肯定不是直接把字符串本身放在运行占空间里的,所以通过ebp寄存器可以找到存放字符串的内存地址。同理,很自然的可以知道0x804a2e4即是程序本身的一段字符串。通过匹配字符串,便可以把炸弹解开。因此此题的目的便是把字符串找出来,因此便用到了gdb工具。
首先,用p/x *(int *)0x804a2e4便可以得到一个地址。假设地址为ooxx,那么要想查看这段地址存放的字符串内容便可以通过x/s ooxx既可以得到字符串的内容。我的答案是:There are rumors on the internets.每个人的答案都不一样。哈哈。下面来看第二题。
上代码:
08048bb4 <phase_2>: 8048bb4: 55 push %ebp 8048bb5: 89 e5 mov %esp,%ebp 8048bb7: 56 push %esi 8048bb8: 53 push %ebx 8048bb9: 83 ec 30 sub $0x30,%esp 8048bbc: 8d 45 e0 lea -0x20(%ebp),%eax 8048bbf: 89 44 24 04 mov %eax,0x4(%esp) 8048bc3: 8b 45 08 mov 0x8(%ebp),%eax 8048bc6: 89 04 24 mov %eax,(%esp) 8048bc9: e8 d2 08 00 00 call 80494a0 <read_six_numbers> 8048bce: 83 7d e0 01 cmpl $0x1,-0x20(%ebp) 8048bd2: 74 05 je 8048bd9 <phase_2+0x25> 8048bd4: e8 5f 07 00 00 call 8049338 <explode_bomb> 8048bd9: 8d 5d e4 lea -0x1c(%ebp),%ebx 8048bdc: 8d 75 f8 lea -0x8(%ebp),%esi 8048bdf: 8b 43 fc mov -0x4(%ebx),%eax 8048be2: 01 c0 add %eax,%eax 8048be4: 39 03 cmp %eax,(%ebx) 8048be6: 74 05 je 8048bed <phase_2+0x39> 8048be8: e8 4b 07 00 00 call 8049338 <explode_bomb> 8048bed: 83 c3 04 add $0x4,%ebx 8048bf0: 39 f3 cmp %esi,%ebx 8048bf2: 75 eb jne 8048bdf <phase_2+0x2b> 8048bf4: 83 c4 30 add $0x30,%esp 8048bf7: 5b pop %ebx 8048bf8: 5e pop %esi 8048bf9: 5d pop %ebp 8048bfa: c3 ret
首先可以看到这道题调用一个函数。函数名叫输入6个数。很明显,这六个书会以次放在ebp-0x20到ebp-0x8的空间内。然后再从以下的代码逻辑可以看出这6个数得满足一种关系:等比为2的等比数列。并且首元素为1.因此答案就明了了为:1 2 4 8 16 32.下面来看第三关。
上代码:
08048bfb <phase_3>: 8048bfb: 55 push %ebp 8048bfc: 89 e5 mov %esp,%ebp 8048bfe: 83 ec 28 sub $0x28,%esp 8048c01: 8d 45 f0 lea -0x10(%ebp),%eax 8048c04: 89 44 24 0c mov %eax,0xc(%esp) 8048c08: 8d 45 f4 lea -0xc(%ebp),%eax 8048c0b: 89 44 24 08 mov %eax,0x8(%esp) 8048c0f: c7 44 24 04 25 a6 04 movl $0x804a625,0x4(%esp) 8048c16: 08 8048c17: 8b 45 08 mov 0x8(%ebp),%eax 8048c1a: 89 04 24 mov %eax,(%esp) 8048c1d: e8 be fb ff ff call 80487e0 <__isoc99_sscanf@plt> 8048c22: 83 f8 01 cmp $0x1,%eax 8048c25: 7f 05 jg 8048c2c <phase_3+0x31> 8048c27: e8 0c 07 00 00 call 8049338 <explode_bomb> 8048c2c: 83 7d f4 07 cmpl $0x7,-0xc(%ebp) 8048c30: 77 65 ja 8048c97 <phase_3+0x9c> 8048c32: 8b 45 f4 mov -0xc(%ebp),%eax 8048c35: ff 24 85 40 a3 04 08 jmp *0x804a340(,%eax,4) 8048c3c: b8 00 00 00 00 mov $0x0,%eax 8048c41: eb 05 jmp 8048c48 <phase_3+0x4d> 8048c43: b8 56 00 00 00 mov $0x56,%eax 8048c48: 2d 0f 02 00 00 sub $0x20f,%eax 8048c4d: eb 05 jmp 8048c54 <phase_3+0x59> 8048c4f: b8 00 00 00 00 mov $0x0,%eax 8048c54: 05 a9 03 00 00 add $0x3a9,%eax 8048c59: eb 05 jmp 8048c60 <phase_3+0x65> 8048c5b: b8 00 00 00 00 mov $0x0,%eax 8048c60: 2d e5 00 00 00 sub $0xe5,%eax 8048c65: eb 05 jmp 8048c6c <phase_3+0x71> 8048c67: b8 00 00 00 00 mov $0x0,%eax 8048c6c: 05 e5 00 00 00 add $0xe5,%eax 8048c71: eb 05 jmp 8048c78 <phase_3+0x7d> 8048c73: b8 00 00 00 00 mov $0x0,%eax 8048c78: 2d e5 00 00 00 sub $0xe5,%eax 8048c7d: eb 05 jmp 8048c84 <phase_3+0x89> 8048c7f: b8 00 00 00 00 mov $0x0,%eax 8048c84: 05 e5 00 00 00 add $0xe5,%eax 8048c89: eb 05 jmp 8048c90 <phase_3+0x95> 8048c8b: b8 00 00 00 00 mov $0x0,%eax 8048c90: 2d e5 00 00 00 sub $0xe5,%eax 8048c95: eb 0a jmp 8048ca1 <phase_3+0xa6> 8048c97: e8 9c 06 00 00 call 8049338 <explode_bomb> 8048c9c: b8 00 00 00 00 mov $0x0,%eax 8048ca1: 83 7d f4 05 cmpl $0x5,-0xc(%ebp) 8048ca5: 7f 05 jg 8048cac <phase_3+0xb1> 8048ca7: 3b 45 f0 cmp -0x10(%ebp),%eax 8048caa: 74 05 je 8048cb1 <phase_3+0xb6> 8048cac: e8 87 06 00 00 call 8049338 <explode_bomb> 8048cb1: c9 leave 8048cb2: c3 ret
有没有被这段代码吓到?确实有点长。依然可以看到这个题会调用一个函数,这个函数是sscanf,如果对这个函数有所了解的话,可以从它下面的一个比较看出这个函数要求输入两个变量,那么这两个变量是什么类型的呢?可以从movl $0x804a625,0x4(%esp)这句里找到信息。很明显这是个非常突兀的地址,那么这个地址是干嘛的,首先可以肯定它是sscanf函数的参数,联想到sscanf的参数,可以这段地址的内容便是变量的类型。通过x/s 0x804a625便可以得到"%d %d"这个字符串。同样从开始代码的调动,仍然可以清晰的确定这是有接受两个参数。从后面的代码逻辑可以看出,要根据第一个参数的具体值跳到不同的地址,来执行命令。而且第一个参数要小于7.可以分别假设第一个参数等于0到6,然后可以看出根据这个分支选择可以确定eax的大小,然后第二个参数等eax的值即可。而且又可以从后面的代码看出第一个参数要小于5所以只有0到4可以选择,然后假设第一个参数为4那么eax在运算后为0,因此第二个参数为0便是一个解。(可以看出这题没有唯一解)
上代码:
08048d19 <phase_4>: 8048d19: 55 push %ebp 8048d1a: 89 e5 mov %esp,%ebp 8048d1c: 83 ec 28 sub $0x28,%esp 8048d1f: 8d 45 f0 lea -0x10(%ebp),%eax 8048d22: 89 44 24 0c mov %eax,0xc(%esp) 8048d26: 8d 45 f4 lea -0xc(%ebp),%eax 8048d29: 89 44 24 08 mov %eax,0x8(%esp) 8048d2d: c7 44 24 04 25 a6 04 movl $0x804a625,0x4(%esp) 8048d34: 08 8048d35: 8b 45 08 mov 0x8(%ebp),%eax 8048d38: 89 04 24 mov %eax,(%esp) 8048d3b: e8 a0 fa ff ff call 80487e0 <__isoc99_sscanf@plt> 8048d40: 83 f8 02 cmp $0x2,%eax 8048d43: 75 0c jne 8048d51 <phase_4+0x38> 8048d45: 8b 45 f4 mov -0xc(%ebp),%eax 8048d48: 85 c0 test %eax,%eax 8048d4a: 78 05 js 8048d51 <phase_4+0x38> 8048d4c: 83 f8 0e cmp $0xe,%eax 8048d4f: 7e 05 jle 8048d56 <phase_4+0x3d> 8048d51: e8 e2 05 00 00 call 8049338 <explode_bomb> 8048d56: c7 44 24 08 0e 00 00 movl $0xe,0x8(%esp) 8048d5d: 00 8048d5e: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) 8048d65: 00 8048d66: 8b 45 f4 mov -0xc(%ebp),%eax 8048d69: 89 04 24 mov %eax,(%esp) 8048d6c: e8 42 ff ff ff call 8048cb3 <func4> 8048d71: 83 f8 25 cmp $0x25,%eax 8048d74: 75 06 jne 8048d7c <phase_4+0x63> 8048d76: 83 7d f0 25 cmpl $0x25,-0x10(%ebp) 8048d7a: 74 05 je 8048d81 <phase_4+0x68> 8048d7c: e8 b7 05 00 00 call 8049338 <explode_bomb> 8048d81: c9 leave 8048d82: c3 ret
看到代码里的
call 80487e0 __isoc99_sscanf@plt cmp $0x2,%eax
就明白了要输入两个数,然后拿出输入的第一个数(mov -0xc(%ebp),%eax)首先看看其是不是负数,如果是负数,bomb!!然后将其与14进行比较,如果它比14大,则bomb!!然后将第一个参数,0,和14分别作为第1,2,3个参数传递给func4,然后调用func4.这个函数的返回值是37.因此我们要做的就是,使得输入的值传递给func4,然后让其返回37即可。下面来看看func4函数。依然上代码:
08048cb3 <func4>: 8048cb3: 55 push %ebp 8048cb4: 89 e5 mov %esp,%ebp 8048cb6: 83 ec 18 sub $0x18,%esp 8048cb9: 89 5d f8 mov %ebx,-0x8(%ebp) 8048cbc: 89 75 fc mov %esi,-0x4(%ebp) 8048cbf: 8b 45 08 mov 0x8(%ebp),%eax 8048cc2: 8b 55 0c mov 0xc(%ebp),%edx 8048cc5: 8b 75 10 mov 0x10(%ebp),%esi 8048cc8: 89 f1 mov %esi,%ecx 8048cca: 29 d1 sub %edx,%ecx 8048ccc: 89 cb mov %ecx,%ebx 8048cce: c1 eb 1f shr $0x1f,%ebx 8048cd1: 8d 0c 0b lea (%ebx,%ecx,1),%ecx 8048cd4: d1 f9 sar %ecx 8048cd6: 8d 1c 11 lea (%ecx,%edx,1),%ebx 8048cd9: 39 c3 cmp %eax,%ebx 8048cdb: 7e 17 jle 8048cf4 <func4+0x41> 8048cdd: 8d 4b ff lea -0x1(%ebx),%ecx 8048ce0: 89 4c 24 08 mov %ecx,0x8(%esp) 8048ce4: 89 54 24 04 mov %edx,0x4(%esp) 8048ce8: 89 04 24 mov %eax,(%esp) 8048ceb: e8 c3 ff ff ff call 8048cb3 <func4> 8048cf0: 01 c3 add %eax,%ebx 8048cf2: eb 19 jmp 8048d0d <func4+0x5a> 8048cf4: 39 c3 cmp %eax,%ebx 8048cf6: 7d 15 jge 8048d0d <func4+0x5a> 8048cf8: 89 74 24 08 mov %esi,0x8(%esp) 8048cfc: 8d 53 01 lea 0x1(%ebx),%edx 8048cff: 89 54 24 04 mov %edx,0x4(%esp) 8048d03: 89 04 24 mov %eax,(%esp) 8048d06: e8 a8 ff ff ff call 8048cb3 <func4> 8048d0b: 01 c3 add %eax,%ebx 8048d0d: 89 d8 mov %ebx,%eax 8048d0f: 8b 5d f8 mov -0x8(%ebp),%ebx 8048d12: 8b 75 fc mov -0x4(%ebp),%esi 8048d15: 89 ec mov %ebp,%esp 8048d17: 5d pop %ebp 8048d18: c3 ret
一看到这个函数里面有func4,心理就紧张了,这是要递归啊。对于这部分,有的同学是用c写了一段代码,模拟这个逻辑,把题给结出来的,我是拿笔算加推理得出的。对于此,不管你认为怎么样,我反正认为是没有必要,这个递归逻辑不复杂。
下面就来剖析func4,这个函数在确定栈之后,首先取出来传递给它的参数,依次放在eax,edx,esi.中,从一个jle和一个jge可以看出,这个递归函数跳出的条件根据func4的第二个参数和第二个参数进过种种运算的结果等于第一个参数即可。注意在递归过程中第一个参数是不变的,最后返回值是经过运算后的ebx加上第一个参数。其中根据传进参数的大小,可以大致算出如果第一个参数如果等于7,则结果明显小于37,所以选比7大的数。所以第一递归会走jge这条路,因此新的参数为输入的第一个数,8,14.然后重新调用函数。可以自己画出每次递归传进的参数图。稍微对比下可以发现传入的数为10即可满足题意.
然后继续看phase_4函数,最后有这句话 cmpl $0x25,-0x10(%ebp)可以看出只要第二个参数为37即可满足。第二个参数的要求就这么简单。是不是很无语?
因此这道题的答案为4 37.
上代码:
08048d83 <phase_5>: 8048d83: 55 push %ebp 8048d84: 89 e5 mov %esp,%ebp 8048d86: 83 ec 28 sub $0x28,%esp 8048d89: 8d 45 f0 lea -0x10(%ebp),%eax 8048d8c: 89 44 24 0c mov %eax,0xc(%esp) 8048d90: 8d 45 f4 lea -0xc(%ebp),%eax 8048d93: 89 44 24 08 mov %eax,0x8(%esp) 8048d97: c7 44 24 04 25 a6 04 movl $0x804a625,0x4(%esp) 8048d9e: 08 8048d9f: 8b 45 08 mov 0x8(%ebp),%eax 8048da2: 89 04 24 mov %eax,(%esp) 8048da5: e8 36 fa ff ff call 80487e0 <__isoc99_sscanf@plt> 8048daa: 83 f8 01 cmp $0x1,%eax 8048dad: 7f 05 jg 8048db4 <phase_5+0x31> 8048daf: e8 84 05 00 00 call 8049338 <explode_bomb> 8048db4: 8b 45 f4 mov -0xc(%ebp),%eax 8048db7: 83 e0 0f and $0xf,%eax 8048dba: 89 45 f4 mov %eax,-0xc(%ebp) 8048dbd: 83 f8 0f cmp $0xf,%eax 8048dc0: 74 28 je 8048dea <phase_5+0x67> 8048dc2: b9 00 00 00 00 mov $0x0,%ecx 8048dc7: ba 00 00 00 00 mov $0x0,%edx 8048dcc: 83 c2 01 add $0x1,%edx 8048dcf: 8b 04 85 60 a3 04 08 mov 0x804a360(,%eax,4),%eax 8048dd6: 01 c1 add %eax,%ecx 8048dd8: 83 f8 0f cmp $0xf,%eax 8048ddb: 75 ef jne 8048dcc <phase_5+0x49> 8048ddd: 89 45 f4 mov %eax,-0xc(%ebp) 8048de0: 83 fa 0f cmp $0xf,%edx 8048de3: 75 05 jne 8048dea <phase_5+0x67> 8048de5: 3b 4d f0 cmp -0x10(%ebp),%ecx 8048de8: 74 05 je 8048def <phase_5+0x6c> 8048dea: e8 49 05 00 00 call 8049338 <explode_bomb> 8048def: c9 leave 8048df0: c3 ret
首先,看到这题不是递归,代码又这么短,心理就有种蔑视这道题的感觉。首先可以看到需要输入两个数,否则bomb。然后就对第一个数进行操作了,首先取其后四位,如果其后四位全为1则爆炸。然后看到mov $0x0,%ecx mov $0x0,%edx就可以知道下面是个循环,edx为循环变量。这个循环里会根据eax,以其为索引找以地址0x804a360开头的数组中的值。然后求和。最后和等于输入的第二个参数即可。可以通过p/x *(int *)(0x804a360)@16得到这个数组,然后拼凑即可。我选则的值为4 115.
上代码:
08048df1 <phase_6>: 8048df1: 55 push %ebp 8048df2: 89 e5 mov %esp,%ebp 8048df4: 56 push %esi 8048df5: 53 push %ebx 8048df6: 83 ec 40 sub $0x40,%esp 8048df9: 8d 45 e0 lea -0x20(%ebp),%eax 8048dfc: 89 44 24 04 mov %eax,0x4(%esp) 8048e00: 8b 45 08 mov 0x8(%ebp),%eax 8048e03: 89 04 24 mov %eax,(%esp) 8048e06: e8 95 06 00 00 call 80494a0 <read_six_numbers> 8048e0b: be 00 00 00 00 mov $0x0,%esi 8048e10: 8b 44 b5 e0 mov -0x20(%ebp,%esi,4),%eax 8048e14: 83 e8 01 sub $0x1,%eax 8048e17: 83 f8 05 cmp $0x5,%eax 8048e1a: 76 05 jbe 8048e21 <phase_6+0x30> 8048e1c: e8 17 05 00 00 call 8049338 <explode_bomb> 8048e21: 83 c6 01 add $0x1,%esi 8048e24: 83 fe 06 cmp $0x6,%esi 8048e27: 74 1b je 8048e44 <phase_6+0x53> 8048e29: 89 f3 mov %esi,%ebx 8048e2b: 8b 44 9d e0 mov -0x20(%ebp,%ebx,4),%eax 8048e2f: 39 44 b5 dc cmp %eax,-0x24(%ebp,%esi,4) 8048e33: 75 05 jne 8048e3a <phase_6+0x49> 8048e35: e8 fe 04 00 00 call 8049338 <explode_bomb> 8048e3a: 83 c3 01 add $0x1,%ebx 8048e3d: 83 fb 05 cmp $0x5,%ebx 8048e40: 7e e9 jle 8048e2b <phase_6+0x3a> 8048e42: eb cc jmp 8048e10 <phase_6+0x1f> 8048e44: 8d 55 e0 lea -0x20(%ebp),%edx 8048e47: 8d 45 f8 lea -0x8(%ebp),%eax 8048e4a: bb 07 00 00 00 mov $0x7,%ebx 8048e4f: 89 d9 mov %ebx,%ecx 8048e51: 2b 0a sub (%edx),%ecx 8048e53: 89 0a mov %ecx,(%edx) 8048e55: 83 c2 04 add $0x4,%edx 8048e58: 39 c2 cmp %eax,%edx 8048e5a: 75 f3 jne 8048e4f <phase_6+0x5e> 8048e5c: bb 00 00 00 00 mov $0x0,%ebx 8048e61: eb 16 jmp 8048e79 <phase_6+0x88> 8048e63: 8b 52 08 mov 0x8(%edx),%edx 8048e66: 83 c0 01 add $0x1,%eax 8048e69: 39 c8 cmp %ecx,%eax 8048e6b: 75 f6 jne 8048e63 <phase_6+0x72> 8048e6d: 89 54 b5 c8 mov %edx,-0x38(%ebp,%esi,4) 8048e71: 83 c3 01 add $0x1,%ebx 8048e74: 83 fb 06 cmp $0x6,%ebx 8048e77: 74 17 je 8048e90 <phase_6+0x9f> 8048e79: 89 de mov %ebx,%esi 8048e7b: 8b 4c 9d e0 mov -0x20(%ebp,%ebx,4),%ecx 8048e7f: b8 01 00 00 00 mov $0x1,%eax 8048e84: ba fc c4 04 08 mov $0x804c4fc,%edx 8048e89: 83 f9 01 cmp $0x1,%ecx 8048e8c: 7f d5 jg 8048e63 <phase_6+0x72> 8048e8e: eb dd jmp 8048e6d <phase_6+0x7c> 8048e90: 8b 5d c8 mov -0x38(%ebp),%ebx 8048e93: 8b 45 cc mov -0x34(%ebp),%eax 8048e96: 89 43 08 mov %eax,0x8(%ebx) 8048e99: 8b 55 d0 mov -0x30(%ebp),%edx 8048e9c: 89 50 08 mov %edx,0x8(%eax) 8048e9f: 8b 45 d4 mov -0x2c(%ebp),%eax 8048ea2: 89 42 08 mov %eax,0x8(%edx) 8048ea5: 8b 55 d8 mov -0x28(%ebp),%edx 8048ea8: 89 50 08 mov %edx,0x8(%eax) 8048eab: 8b 45 dc mov -0x24(%ebp),%eax 8048eae: 89 42 08 mov %eax,0x8(%edx) 8048eb1: c7 40 08 00 00 00 00 movl $0x0,0x8(%eax) 8048eb8: be 00 00 00 00 mov $0x0,%esi 8048ebd: 8b 43 08 mov 0x8(%ebx),%eax 8048ec0: 8b 10 mov (%eax),%edx 8048ec2: 39 13 cmp %edx,(%ebx) 8048ec4: 7d 05 jge 8048ecb <phase_6+0xda> 8048ec6: e8 6d 04 00 00 call 8049338 <explode_bomb> 8048ecb: 8b 5b 08 mov 0x8(%ebx),%ebx 8048ece: 83 c6 01 add $0x1,%esi 8048ed1: 83 fe 05 cmp $0x5,%esi 8048ed4: 75 e7 jne 8048ebd <phase_6+0xcc> 8048ed6: 83 c4 40 add $0x40,%esp 8048ed9: 5b pop %ebx 8048eda: 5e pop %esi 8048edb: 5d pop %ebp 8048edc: c3 ret
这道题,很长,很烦,很无聊,会有大段的代码在那把数据映射来映射去,很多人在这上面有些晕。首先分析一下,怎么映射的,大家画出图,一看便知。首先对六个数进行判断,每个数都不能大于六。无语了,总过个整数,还都不大于六,就是个随机排列呗。而且代码下面的逻辑是首先分别用7减这6个数,将这个6个数“调转个头”。然后对这后来的六个数就开始大量的映射了。映射来映射去最后根据后来的六个数找内存某块地址的6个值,这6个值必须是递增的。所以根据这可以确定后来的6个值为2 6 3 4 5 1。反过来答案就为 5 1 4 3 2 6 。
第七道关卡:secret_phase
首先在objdumb bomb>assemble.然后搜索secret_phase可以发现在phase_defused会调用这个函数。而这个函数在正常情况下是不会调用到的,怎么办??怎么让代码运行到这一段??可以设置在phase_defused这函数的入口处设置断点,然后每解开一个炸弹都会在这个断点处停止。然后操作技巧如下:
首先,上代码:这个是phase_defused的代码
80494f1: 55 push %ebp 80494f2: 89 e5 mov %esp,%ebp 80494f4: 81 ec 88 00 00 00 sub $0x88,%esp 80494fa: 65 a1 14 00 00 00 mov %gs:0x14,%eax 8049500: 89 45 f4 mov %eax,-0xc(%ebp) 8049503: 31 c0 xor %eax,%eax 8049505: c7 04 24 01 00 00 00 movl $0x1,(%esp) 804950c: e8 21 fd ff ff call 8049232 <send_msg> 8049511: 83 3d ec c7 04 08 06 cmpl $0x6,0x804c7ec 8049518: 75 7a jne 8049594 <phase_defused+0xa3> 804951a: 8d 45 a4 lea -0x5c(%ebp),%eax 804951d: 89 44 24 10 mov %eax,0x10(%esp) 8049521: 8d 45 9c lea -0x64(%ebp),%eax 8049524: 89 44 24 0c mov %eax,0xc(%esp) 8049528: 8d 45 a0 lea -0x60(%ebp),%eax 804952b: 89 44 24 08 mov %eax,0x8(%esp) 804952f: c7 44 24 04 2b a6 04 movl $0x804a62b,0x4(%esp) 8049536: 08 8049537: c7 04 24 f0 c8 04 08 movl $0x804c8f0,(%esp) 804953e: e8 9d f2 ff ff call 80487e0 <__isoc99_sscanf@plt> 8049543: 83 f8 03 cmp $0x3,%eax 8049546: 75 34 jne 804957c <phase_defused+0x8b> 8049548: c7 44 24 04 34 a6 04 movl $0x804a634,0x4(%esp) 804954f: 08 8049550: 8d 45 a4 lea -0x5c(%ebp),%eax 8049553: 89 04 24 mov %eax,(%esp) 8049556: e8 f0 fa ff ff call 804904b <strings_not_equal> 804955b: 85 c0 test %eax,%eax 804955d: 75 1d jne 804957c <phase_defused+0x8b> 804955f: c7 04 24 90 a4 04 08 movl $0x804a490,(%esp) 8049566: e8 b5 f3 ff ff call 8048920 <puts@plt> 804956b: c7 04 24 b8 a4 04 08 movl $0x804a4b8,(%esp) 8049572: e8 a9 f3 ff ff call 8048920 <puts@plt> 8049577: e8 b2 f9 ff ff call 8048f2e <secret_phase> 804957c: c7 04 24 f0 a4 04 08 movl $0x804a4f0,(%esp) 8049583: e8 98 f3 ff ff call 8048920 <puts@plt> 8049588: c7 04 24 1c a5 04 08 movl $0x804a51c,(%esp) 804958f: e8 8c f3 ff ff call 8048920 <puts@plt> 8049594: 8b 45 f4 mov -0xc(%ebp),%eax 8049597: 65 33 05 14 00 00 00 xor %gs:0x14,%eax 804959e: 74 05 je 80495a5 <phase_defused+0xb4> 80495a0: e8 4b f3 ff ff call 80488f0 <__stack_chk_fail@plt> 80495a5: c9 leave 80495a6: c3 ret
可以在80495a0: e8 4b f3 ff ff call 80488f0 __stack_chk_fail@plt设置断点,然后jump ×8049577,这样就会强行跳到隐藏关卡执行代码。下面上隐藏关的代码:
08048f2e <secret_phase>: 8048f2e: 55 push %ebp 8048f2f: 89 e5 mov %esp,%ebp 8048f31: 53 push %ebx 8048f32: 83 ec 14 sub $0x14,%esp 8048f35: e8 40 04 00 00 call 804937a <read_line> 8048f3a: c7 44 24 08 0a 00 00 movl $0xa,0x8(%esp) 8048f41: 00 8048f42: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) 8048f49: 00 8048f4a: 89 04 24 mov %eax,(%esp) 8048f4d: e8 0e f9 ff ff call 8048860 <strtol@plt> 8048f52: 89 c3 mov %eax,%ebx 8048f54: 8d 40 ff lea -0x1(%eax),%eax 8048f57: 3d e8 03 00 00 cmp $0x3e8,%eax 8048f5c: 76 05 jbe 8048f63 <secret_phase+0x35> 8048f5e: e8 d5 03 00 00 call 8049338 <explode_bomb> 8048f63: 89 5c 24 04 mov %ebx,0x4(%esp) 8048f67: c7 04 24 b0 c5 04 08 movl $0x804c5b0,(%esp) 8048f6e: e8 6a ff ff ff call 8048edd <fun7> 8048f73: 83 f8 01 cmp $0x1,%eax 8048f76: 74 05 je 8048f7d <secret_phase+0x4f> 8048f78: e8 bb 03 00 00 call 8049338 <explode_bomb> 8048f7d: c7 04 24 08 a3 04 08 movl $0x804a308,(%esp) 8048f84: e8 97 f9 ff ff call 8048920 <puts@plt> 8048f89: e8 63 05 00 00 call 80494f1 <phase_defused> 8048f8e: 83 c4 14 add $0x14,%esp 8048f91: 5b pop %ebx 8048f92: 5d pop %ebp 8048f93: c3 ret
这个函数首先将输入的字符串转换成一个长整形,然后得到的书不能大于0x3e9然后将得到的数和地址$0x804c5b0分别作为第二个和第一个参数传递个func7。然后func7返回的是1即可。下面上func7的代码。
08048edd <fun7>: 8048edd: 55 push %ebp 8048ede: 89 e5 mov %esp,%ebp 8048ee0: 53 push %ebx 8048ee1: 83 ec 14 sub $0x14,%esp 8048ee4: 8b 55 08 mov 0x8(%ebp),%edx 8048ee7: 8b 4d 0c mov 0xc(%ebp),%ecx 8048eea: b8 ff ff ff ff mov $0xffffffff,%eax 8048eef: 85 d2 test %edx,%edx 8048ef1: 74 35 je 8048f28 <fun7+0x4b> 8048ef3: 8b 1a mov (%edx),%ebx 8048ef5: 39 cb cmp %ecx,%ebx 8048ef7: 7e 13 jle 8048f0c <fun7+0x2f> 8048ef9: 89 4c 24 04 mov %ecx,0x4(%esp) 8048efd: 8b 42 04 mov 0x4(%edx),%eax 8048f00: 89 04 24 mov %eax,(%esp) 8048f03: e8 d5 ff ff ff call 8048edd <fun7> 8048f08: 01 c0 add %eax,%eax 8048f0a: eb 1c jmp 8048f28 <fun7+0x4b> 8048f0c: b8 00 00 00 00 mov $0x0,%eax 8048f11: 39 cb cmp %ecx,%ebx 8048f13: 74 13 je 8048f28 <fun7+0x4b> 8048f15: 89 4c 24 04 mov %ecx,0x4(%esp) 8048f19: 8b 42 08 mov 0x8(%edx),%eax 8048f1c: 89 04 24 mov %eax,(%esp) 8048f1f: e8 b9 ff ff ff call 8048edd <fun7> 8048f24: 8d 44 00 01 lea 0x1(%eax,%eax,1),%eax 8048f28: 83 c4 14 add $0x14,%esp 8048f2b: 5b pop %ebx 8048f2c: 5d pop %ebp 8048f2d: c3 ret
这个代码里有递归,首先会检查传入的第一个参数是不是0,如果不是0则取其对应的内容。然后将取的内容和第二个参数比较,从而如果第二个参数大,则重新取值,进行递归。递归的边界是相等,且返回0。如果小于则取地址依然重新递归。递归的参数不同之处在于如果是小于则取后的值越来越大,否者越来越小。最后选取50的原因是让递归首先执行地址8048f15对应的部分,然后递归后会返回0,然后接着执行给eax赋值为1返回。所以答案为50.可以自己用p/u *(int *)(地址)@3看内存中的数据。
以上是对隐藏关的分析,并得出了其需要的输入为50,然后接着上面的jump之后输入50,然后程序就继续运行到设置的下一个断点,然后此时仍然需要一次jump再跳回去(phase_defused入口),这样就跟什么都没发生一样。(当然事实上,这样对后续的题是有影响的,不过没有关系,这样做,没有什么大的地址错误,仍然可以解决掉隐藏关)。
注:
1:由于call指令会push返回地址到栈中,且每个新的函数调用都会最开始push一个ebp,所以新的帧顶到上个帧的帧底有个8字节的差距,而非下一个帧的ebp即为上个帧的esp。
2:可以用x/s 地址 来检查内存中的一段字符串。
3:可以用p来看地址的内容,并且输出为制定格式(x/s也可)
4:可以用info registers来看寄存器的值。
5:隐藏关里,jump很好使。