学校布置了二进制炸弹的作业,一边查攻略一边自己拆,零零总总花了两三天拆完了。拆的时候感觉看一看前人的经验,进度真的快很多,所以虽然自己也只是个小白,还是想把心得放上来供大家参考。
写在前面
感谢 https://www.cnblogs.com/liqiuhao/p/7624880.html和https://blog.youkuaiyun.com/the_v_/article/details/46842337/这两位大佬的无私奉献,我的炸弹是参考这两篇拆的。
0.gdb断点
我在拆炸弹之前特别担心炸弹爆炸,即便知道gdb调试可以设断点,还是不明白怎么操作。所以在最前面先演示一下断点的设置和运行结果,让大家放心拆弹无惧爆炸hhh
怎么进入炸弹文件我就跳过了,应该拆弹之前都会有讲或者有参考步骤的文件之类的。
那么假设我们已经cd到了炸弹所在处,接着就是gdb调试。
(@前面是我的学号,就不显示了)直接输入 gdb bomb(或者是你的炸弹的名字)
然后变成这样,可以直接输入gdb指令啦。
输入 break *0x401751(炸弹所在地址,观察callq xxxxxx<explode_bomb>),回车显示断点设好了。
之后可以直接输入 run开始跑炸弹,如果输错了结果炸弹爆炸,会显示
你的断点就生效了。这个时候就可以继续gdb调试(run 或者x/s 0xxxxxxxx看看数据),或者输入q退出。退出之后,再次gdb bomb要记得重新设断点。如果你的断点设在了炸弹前面,千万不要输入c(continue),不然继续运行的就是爆炸了。
接下来正式开始拆弹!
*csapp 3rd P120:%r(e)di 第一个参数;%r(e)si 第二个参数;%r(e)dx 第三个参数;%r(e)cx 第四个参数,%eax函数返回值。后面maybe会用到。
1.phase1 字符串比较
0000000000400f90 <phase_1>:
400f90: 48 83 ec 08 sub $0x8,%rsp //当前输入
400f94: be 50 27 40 00 mov $0x402750,%esi //把0x402750中的内容,作为第二个参数
400f99: e8 da 04 00 00 callq 401478 <strings_not_equal>//发现调用了一个比较两个字符串的函数
400f9e: 85 c0 test %eax,%eax
400fa0: 74 05 je 400fa7 <phase_1+0x17>//返回值是不是0,上网查的:test 自己,再加上je,就是比较是不是0
400fa2: e8 aa 07 00 00 callq 401751 <explode_bomb>//不然炸
400fa7: 48 83 c4 08 add $0x8,%rsp
400fab: c3 retq
strings_not_equal (我只看了如果字符串相同返回什么)
0000000000401478 <strings_not_equal>:
401478: 41 54 push %r12
40147a: 55 push %rbp
40147b: 53 push %rbx
40147c: 48 89 fb mov %rdi,%rbx //rbx=第一个参数地址:输入
40147f: 48 89 f5 mov %rsi,%rbp// rbp=第二个参数地址:地址
401482: e8 d4 ff ff ff callq 40145b <string_length>
401487: 41 89 c4 mov %eax,%r12d //r12d 输入字符串长度
40148a: 48 89 ef mov %rbp,%rdi
40148d: e8 c9 ff ff ff callq 40145b <string_length>
401492: ba 01 00 00 00 mov $0x1,%edx
401497: 41 39 c4 cmp %eax,%r12d //两字符串长度比较
40149a: 75 3f jne 4014db <strings_not_equal+0x63>
40149c: 0f b6 03 movzbl (%rbx),%eax//相等,提取输入的第一个字符
40149f: 84 c0 test %al,%al
4014a1: 74 25 je 4014c8 <strings_not_equal+0x50>//比较输入是不是0(字符串结束),结束跳转
4014a3: 3a 45 00 cmp 0x0(%rbp),%al//没结束,两个字符串第一个字符比较
4014a6: 74 0a je 4014b2 <strings_not_equal+0x3a>//相同跳...4b2
4014a8: eb 25 jmp 4014cf <strings_not_equal+0x57>
4014aa: 3a 45 00 cmp 0x0(%rbp),%al//从...4bf跳到这里,看出来这个循环块 开始循环逐个比较
4014ad: 0f 1f 00 nopl (%rax)
4014b0: 75 24 jne 4014d6 <strings_not_equal+0x5e>
4014b2: 48 83 c3 01 add $0x1,%rbx//第一个字符相同到这里
4014b6: 48 83 c5 01 add $0x1,%rbp//第二个字符
4014ba: 0f b6 03 movzbl (%rbx),%eax
4014bd: 84 c0 test %al,%al
4014bf: 75 e9 jne 4014aa <strings_not_equal+0x32>//同样,是不是结束了
4014c1: ba 00 00 00 00 mov $0x0,%edx//比较到字符串结束了,edx=0
4014c6: eb 13 jmp 4014db <strings_not_equal+0x63>//跳...4db
4014c8: ba 00 00 00 00 mov $0x0,%edx
4014cd: eb 0c jmp 4014db <strings_not_equal+0x63>
4014cf: ba 01 00 00 00 mov $0x1,%edx
4014d4: eb 05 jmp 4014db <strings_not_equal+0x63>
4014d6: ba 01 00 00 00 mov $0x1,%edx
4014db: 89 d0 mov %edx,%eax//如果全部相同,返回值为0
4014dd: 5b pop %rbx
4014de: 5d pop %rbp
4014df: 41 5c pop %r12
4014e1: c3 retq
分析完了就知道,0x402750里面就是我们的目标字符串,于是就可以用(gdb)x/s 0x402750来查看字符串。我查出来的是“I can see Russia from my house!”中俄友谊地久天长hhhh
2.phase2 数列
0000000000400fac <phase_2>:0 1 1 2 3 5
400fac: 55 push %rbp
400fad: 53 push %rbx
400fae: 48 83 ec 28 sub $0x28,%rsp
400fb2: 48 89 e6 mov %rsp,%rsi
400fb5: e8 cd 07 00 00 callq 401787 <read_six_numbers>//反正看名字知道读入六个数字..仔细看函数太头大了...
400fba: 83 3c 24 00 cmpl $0x0,(%rsp)//rsp指向第一个数字,可以随便输一串数字gdb看一看,反正不怕炸哈哈哈
400fbe: 75 07 jne 400fc7 <phase_2+0x1b> //和0比,不等就炸(ac+1b=c7)
400fc0: 83 7c 24 04 01 cmpl $0x1,0x4(%rsp)//rsp+4 //第二个数字,和1比较
400fc5: 74 21 je 400fe8 <phase_2+0x3c> //不等爆炸,相等跳e8
400fc7: e8 85 07 00 00 callq 401751 <explode_bomb>
400fcc: eb 1a jmp 400fe8 <phase_2+0x3c>
400fce: 8b 43 f8 mov -0x8(%rbx),%eax//eax=rbx前两个数
400fd1: 03 43 fc add -0x4(%rbx),%eax//eax=eax+eax前一个数
400fd4: 39 03 cmp %eax,(%rbx)//比较rbx是否等于前两个数的和
400fd6: 74 05 je 400fdd <phase_2+0x31>相等跳dd 不然炸
400fd8: e8 74 07 00 00 callq 401751 <explode_bomb>
400fdd: 48 83 c3 04 add $0x4,%rbx//rbx后移一个
400fe1: 48 39 eb cmp %rbp,%rbx //rbx是否已经超出6个的范围
400fe4: 75 e8 jne 400fce <phase_2+0x22> //rbx没有超出&#