CSAPP实验二:二进制炸弹(Bomb Lab)
Posted CNFINIT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSAPP实验二:二进制炸弹(Bomb Lab)相关的知识,希望对你有一定的参考价值。
本系列文章为中国科学技术大学计算机专业学科基础课《计算机系统》布置的实验,上课所用教材和内容为黑书CSAPP,当时花费很大精力和弯路,现来总结下各个实验,本文章为第二个实验——二进制炸弹(Bomb Lab)。
一、实验名称:二进制炸弹
二、实验学时: 3
三、实验内容和目的
1.二进制炸弹包含若干个阶段,每个阶段需要输入特定的字符串,所有输入正确则炸弹被排除,否则…..
任务是找出这些字符串
字符串记录到文件中,可按下列方式验证:
./bomb solution.txt
用换行区别不同阶段的字符串
实验完成后上传solution.txt的打包文件
2.从教辅系统上下载压缩包、组队表格
压缩包包含48个bomb代码包
在组队表格中找到自己的组号
根据“学号%48 + 1”领取自己的代码
学号191,领取bomb48
解压后有如下文件
bomb 二进制可执行文件,任务目标文件
bomb.c bomb的源文件,辅助理解bomb代码
3.GDB参考
课本3.12(第二版3.11)节,“现实生活:使用GDB调试器”
更详细一些的资料:
http://heather.cs.ucdavis.edu/~matloff/UnixAndC/CLanguage/Debug.html
官方网站
http://www.gnu.org/software/gdb/
四、实验原理
查看bomb.c可知程序利用phase_*函数(*为1~6) 检查输入字符串是否合法,不合法就引爆炸弹。我们的任务就是逆向出每个phase的检查规则,构造出合法字符串。
当然,bomb.c没有给出phase_*的源码
逆向方法:gdb,直接反汇编
五、汇编复习
想要完成拆弹任务,不但需要理解不同寄存器的常用方法,也要弄明白具体的操作符是什么意思:
类型 | 语法 | 例子 | 备注 |
常量 | 符号$开头 | $-42, $0x15213 | 一定要注意十进制还是十六进制 |
寄存器 | 符号%开头 | %esi, %rax | 可能存的是值或者地址 |
内存地址 | 括号括起来 | (%rbx),0x1c(%rax),0x4(%rcx,%rdi,0x1) | 括号实际上是去寻址的意思 |
一些汇编语句与实际命令的转换:
指令 | 效果 |
mov %rbx, %rdx | rdx = rbx |
add (%rdx), %r8 | r8 += value at rdx |
mul $3, %r8 | r8 *= 3 |
sub $1, %r8 | r8-- |
lea (%rdx, %rbx, 2), %rdx | rdx = rdx + rbx*2 |
比较与跳转是拆弹的关键,基本所有的字符判断就是通过比较来实现的,比方说cmp b,a会计算a-b的值,test b, a会计算a&b,注意运算符的顺序。例如
cmpl %r9, %r10
jg 8675309
等同于
if %r10 > %r9, jump to 8675309
各种不同的跳转:
指令 | 效果 | 指令 | 效果 |
jmp | Always jump | ja | Jump if above(unsigned >) |
je/jz | Jump if eq / zero | jae | Jump if above / equal |
jne/jnz | Jump if !eq / !zero | jb | Jump if below(unsigned <) |
jg | Jump if greater | jbe | Jump if below / equal |
jge | Jump if greater / eq | js | Jump if sign bits is 1(neg) |
jl | Jump if less | jns | Jump if sign bit is 0 (pos) |
jle | Jump if less / eq | x | x |
举几个例子
cmp $0x15213,
%r12jge deadbeef
若%r12 >= 0x15213,则跳转到 0xdeadeef
cmp %rax, %rdi
jae 15213b
如果%rdi的无符号值大于等于%rax,则跳转到0x15213b
test %r8,
%r8jnz (%rsi)
如果%r8 & %r8不为零,那么跳转到%rsi存着的地址中。
# 检查符号表
# 然后可以寻找跟 bomb 有关的内容
objdump -t bomb | less
# 反编译
# 搜索 explode_bomb
objdump -d bomb > bomb.txt
# 显示所有字符
strings bomb | less
GDB 介绍
gdb bomb
# 获取帮助
help
# 设置断点
break explode_bomb
break phase_1
# 开始运行
run
# 检查汇编 会给出对应的代码的汇编
disas
# 查看寄存器内容
info registers
# 打印指定寄存器
print $rsp
# 每步执行
stepi
# 检查寄存器或某个地址
x/4wd $rsp
六、实验步骤及结果:
1.准备工作
首先反汇编
首先反汇编代码,objdump –d bomb > bomb.txt,对bomb进行反汇编并将汇编代码输出到bomb.txt中。
bomb.txt文件已经生成,为后面的分析做准备
开始GDB调试break进入调试窗口
2. Phase1
调试函数1
设置断点break phase_1
接着运行run,就会在断点处停下,这里会先让我们输入第一关的密码,随便输入一个抵达断点再说。
我们现在到断点了,可以利用 disas 来看看对应的汇编代码,其实就和我们之前反汇编出来的一致。
08048b80 <phase_1>:
0x08048b80 <+0>: push %ebp
0x08048b81 <+1>: mov %esp,%ebp
0x08048b83 <+3>: sub $0x8,%esp
=> 0x08048b86 <+6>: movl $0x80499d8,0x4(%esp)
0x08048b8e <+14>: mov 0x8(%ebp),%eax
0x08048b91 <+17>: mov %eax,(%esp)
0x08048b94 <+20>: call 0x8049113 <strings_not_equal>
0x08048b99 <+25>: test %eax,%eax
0x08048b9b <+27>: je 0x8048ba2 <phase_1+34>
0x08048b9d <+29>: call 0x80496da <explode_bomb>
0x08048ba2 <+34>: leave
0x08048ba3 <+35>: ret
第一步先压栈,ebp为栈底指针,esp为栈顶指针
第二步把esp赋值给ebp
第三步把0x18赋值给esp
第四步把内存中地址为$0x80499d8的内容赋值给*(esp+4)
第五步输入的字符*(ebp+8)->eax即为所求,理由如后续。
后续比较两字符串是否相等,如果相等令eax为0 否则为1。
再往后,如果eax=0 则进入phase2 否则爆炸
最后为第二个炸弹做准备。返回。
用(gdb) x/s 0x80499d8 查看位于该地址处的内容,可以看到出现
Why make trillions when we could make... billions?
读出数据后使用RUN命令测试成功,上面字符串即为所求。
然后输入 quit 退出 gdb,新建一个文本文件 touch solution.txt,方便以后输入答案。
下面的phase步骤都是先打断点,再分析
3. Phase2
调试函数2
0x8048baa<phase_2>:
0x08048ba4 <+0>: push %ebp
0x08048ba5 <+1>: mov %esp,%ebp
0x08048ba7 <+3>: sub $0x28,%esp
=> 0x08048baa <+6>: movl $0x0,-0x4(%ebp)
0x08048bb1 <+13>: lea -0x20(%ebp),%eax
0x08048bb4 <+16>: mov %eax,0x4(%esp)
0x08048bb8 <+20>: mov 0x8(%ebp),%eax
0x08048bbb <+23>: mov %eax,(%esp)
0x08048bbe <+26>: call 0x8049080 <read_six_numbers>
0x08048bc3 <+31>: movl $0x0,-0x8(%ebp)
0x08048bca <+38>: jmp 0x8048bf3 <phase_2+79>
0x08048bcc <+40>: mov -0x8(%ebp),%eax
0x08048bcf <+43>: mov -0x20(%ebp,%eax,4),%edx
0x08048bd3 <+47>: mov -0x8(%ebp),%eax
0x08048bd6 <+50>: add $0x3,%eax
0x08048bd9 <+53>: mov -0x20(%ebp,%eax,4),%eax
0x08048bdd <+57>: cmp %eax,%edx
0x08048bdf <+59>: je 0x8048be6 <phase_2+66>
0x08048be1 <+61>: call 0x80496da <explode_bomb>
0x08048be6 <+66>: mov -0x8(%ebp),%eax
0x08048be9 <+69>: mov -0x20(%ebp,%eax,4),%eax
0x08048bed <+73>: add %eax,-0x4(%ebp)
0x08048bf0 <+76>: incl -0x8(%ebp)
0x08048bf3 <+79>: cmpl $0x2,-0x8(%ebp)
0x08048bf7 <+83>: jle 0x8048bcc <phase_2+40>
0x08048bf9 <+85>: cmpl $0x0,-0x4(%ebp)
0x08048bfd <+89>: jne 0x8048c04 <phase_2+96>
0x08048bff <+91>: call 0x80496da <explode_bomb>
0x08048c04 <+96>: leave
0x08048c05 <+97>: ret
生成的txt文件中代码如上所示。
由这句话0x08048bc3 <+31>: movl $0x0,-0x8(%ebp) 表明-0x8(%ebp)里的值一开始是0
然后根据0x08048bf3 <+79>: cmpl $0x2,-0x8(%ebp)知道循环三次
再根据以下
0x08048bcc <+40>: mov -0x8(%ebp),%eax
0x08048bcf <+43>: mov -0x20(%ebp,%eax,4),%edx
0x08048bd3 <+47>: mov -0x8(%ebp),%eax
0x08048bd6 <+50>: add $0x3,%eax
0x08048bd9 <+53>: mov -0x20(%ebp,%eax,4),%eax
0x08048bdd <+57>: cmp %eax,%edx
0x08048bdf <+59>: je 0x8048be6 <phase_2+66>
这段可知每隔三个数比较数组元素是否相等,不相等则跳转炸弹爆炸,故输入4 5 6 4 5 6即可通过。
4. Phase3
调试函数3
08048c06 <phase_3>:
0x08048c06 <+0>: push %ebp
0x08048c07 <+1>: mov %esp,%ebp
0x08048c09 <+3>: sub $0x38,%esp
0x08048c0c <+6>: movl $0x0,-0x8(%ebp)
0x08048c13 <+13>: lea -0x10(%ebp),%eax
0x08048c16 <+16>: mov %eax,0x10(%esp)
0x08048c1a <+20>: lea -0x11(%ebp),%eax
0x08048c1d <+23>: mov %eax,0xc(%esp)
0x08048c21 <+27>: lea -0xc(%ebp),%eax
0x08048c24 <+30>: mov %eax,0x8(%esp)
0x08048c28 <+34>: movl $0x8049a0b,0x4(%esp)
0x08048c30 <+42>: mov 0x8(%ebp),%eax
=> 0x08048c33 <+45>: mov %eax,(%esp)
0x08048c36 <+48>: call 0x8048868 <sscanf@plt>
0x08048c3b <+53>: mov %eax,-0x8(%ebp)
0x08048c3e <+56>: cmpl $0x2,-0x8(%ebp)
0x08048c42 <+60>: jg 0x8048c49 <phase_3+67>
0x08048c44 <+62>: call 0x80496da <explode_bomb>
0x08048c49 <+67>: mov -0xc(%ebp),%eax
0x08048c4c <+70>: mov %eax,-0x24(%ebp)
0x08048c4f <+73>: cmpl $0x7,-0x24(%ebp)
0x08048c53 <+77>: ja 0x8048d19 <phase_3+275>
0x08048c59 <+83>: mov -0x24(%ebp),%edx
0x08048c5c <+86>: mov 0x8049a14(,%edx,4),%eax
0x08048c63 <+93>: jmp *%eax
0x08048c65 <+95>: movb $0x79,-0x1(%ebp)
0x08048c69 <+99>: mov -0x10(%ebp),%eax
0x08048c6c <+102>: cmp $0x346,%eax
0x08048c71 <+107>: je 0x8048d22 <phase_3+284>
0x08048c77 <+113>: call 0x80496da <explode_bomb>
0x08048c7c <+118>: jmp 0x8048d22 <phase_3+284>
0x08048c81 <+123>: movb $0x69,-0x1(%ebp)
0x08048c85 <+127>: mov -0x10(%ebp),%eax
0x08048c88 <+130>: cmp $0x36f,%eax
0x08048c8d <+135>: je 0x8048d22 <phase_3+284>
0x08048c93 <+141>: call 0x80496da <explode_bomb>
0x08048c98 <+146>: jmp 0x8048d22 <phase_3+284>
0x08048c9d <+151>: movb $0x68,-0x1(%ebp)
0x08048ca1 <+155>: mov -0x10(%ebp),%eax
0x08048ca4 <+158>: cmp $0x274,%eax
0x08048ca9 <+163>: je 0x8048d22 <phase_3+284>
0x08048cab <+165>: call 0x80496da <explode_bomb>
0x08048cb0 <+170>: jmp 0x8048d22 <phase_3+284>
0x08048cb2 <+172>: movb $0x6e,-0x1(%ebp)
0x08048cb6 <+176>: mov -0x10(%ebp),%eax
0x08048cb9 <+179>: cmp $0x46,%eax
0x08048cbc <+182>: je 0x8048d22 <phase_3+284>
0x08048cbe <+184>: call 0x80496da <explode_bomb>
0x08048cc3 <+189>: jmp 0x8048d22 <phase_3+284>
0x08048cc5 <+191>: movb $0x64,-0x1(%ebp)
0x08048cc9 <+195>: mov -0x10(%ebp),%eax
0x08048ccc <+198>: cmp $0x15b,%eax
0x08048cd1 <+203>: je 0x8048d22 <phase_3+284>
0x08048cd3 <+205>: call 0x80496da <explode_bomb>
0x08048cd8 <+210>: jmp 0x8048d22 <phase_3+284>
---Type <return> to continue, or q <return> to quit---
0x08048cda <+212>: movb $0x6b,-0x1(%ebp)
0x08048cde <+216>: mov -0x10(%ebp),%eax
0x08048ce1 <+219>: cmp $0x35c,%eax
0x08048ce6 <+224>: je 0x8048d22 <phase_3+284>
0x08048ce8 <+226>: call 0x80496da <explode_bomb>
0x08048ced <+231>: jmp 0x8048d22 <phase_3+284>
0x08048cef <+233>: movb $0x65,-0x1(%ebp)
0x08048cf3 <+237>: mov -0x10(%ebp),%eax
0x08048cf6 <+240>: cmp $0x29c,%eax
0x08048cfb <+245>: je 0x8048d22 <phase_3+284>
0x08048cfd <+247>: call 0x80496da <explode_bomb>
0x08048d02 <+252>: jmp 0x8048d22 <phase_3+284>
0x08048d04 <+254>: movb $0x63,-0x1(%ebp)
0x08048d08 <+258>: mov -0x10(%ebp),%eax
0x08048d0b <+261>: cmp $0xeb,%eax
0x08048d10 <+266>: je 0x8048d22 <phase_3+284>
0x08048d12 <+268>: call 0x80496da <explode_bomb>
0x08048d17 <+273>: jmp 0x8048d22 <phase_3+284>
0x08048d19 <+275>: movb $0x63,-0x1(%ebp)
0x08048d1d <+279>: call 0x80496da <explode_bomb>
0x08048d22 <+284>: movzbl -0x11(%ebp),%eax
0x08048d26 <+288>: cmp %al,-0x1(%ebp)
0x08048d29 <+291>: je 0x8048d30 <phase_3+298>
0x08048d2b <+293>: call 0x80496da <explode_bomb>
0x08048d30 <+298>: leave
0x08048d31 <+299>: ret
总体汇编代码如上所示,具体分析如下:
本题代码整体太长,一点一点解读既费时间,又可能找不到头绪。所幸我们找到了里面一直出现的cmp je语句,这提示我们一个重要信息,即附近有个switch循环,仔细寻找后如下
0x08048c13 <+13>: lea -0x10(%ebp),%eax
0x08048c16 <+16>: mov %eax,0x10(%esp)
0x08048c1a <+20>: lea -0x11(%ebp),%eax
0x08048c1d <+23>: mov %eax,0xc(%esp)
0x08048c21 <+27>: lea -0xc(%ebp),%eax
0x08048c24 <+30>: mov %eax,0x8(%esp)
0x08048c28 <+34>: movl $0x8049a0b,0x4(%esp)
分析上面几个lea和mov语句可知,该操作获取了三个参数,
x/sb 0x8049a0b,得0x8049a0b: "%d %c %d"。依次是int,char,int
再根据如下
0x08048c49 <+67>: mov -0xc(%ebp),%eax
0x08048c4c <+70>: mov %eax,-0x24(%ebp)
0x08048c4f <+73>: cmpl $0x7,-0x24(%ebp)
由上三行可知,比较第一个参数在不在0到7之间,然后后面根据第一个输入的参数进行跳转。
如果输入 0,那么就直接执行下一条 mov 语句,然后0x08048c6c <+102>: cmp $0x346,%eax是比较第三个参数是否和 0x346 相等,所以我们知道第三个参数是 838(如果第一个参数是 0)的话。如果一切正常,那么就会跳转到 +284 的位置,也就是:
0x08048d22 <+284>: movzbl -0x11(%ebp),%eax
0x08048d26 <+288>: cmp %al,-0x1(%ebp)
0x08048d29 <+291>: je 0x8048d30 <phase_3+298>
0x08048d2b <+293>: call 0x80496da <explode_bomb>
0x08048d30 <+298>: leave
0x08048d31 <+299>: ret
我们只要搞清楚 %al 里面的值是什么就好(会和第二个参数进行比较),具体的值,其实就是前面 mov 语句0x08048c65 <+95>: movb $0x79,-0x1(%ebp),读入的 0x79(121),对应的字符是 y。
所以答案是 0 y 838,当然选择不同的分支就有不同的答案,其他分支的分析也都是类似的。运行一下,就可以发现这一关又过了。
5. Phase4
调试函数4
08048d72 <phase_4>:
0x08048d72 <+0>: push %ebp
0x08048d73 <+1>: mov %esp,%ebp
0x08048d75 <+3>: sub $0x28,%esp
=> 0x08048d78 <+6>: lea -0xc(%ebp),%eax
0x08048d7b <+9>: mov %eax,0x8(%esp)
0x08048d7f <+13>: movl $0x8049a34,0x4(%esp)
0x08048d87 <+21>: mov 0x8(%ebp),%eax
0x08048d8a <+24>: mov %eax,(%esp)
0x08048d8d <+27>: call 0x8048868 <sscanf@plt>
0x08048d92 <+32>: mov %eax,-0x4(%ebp)
0x08048d95 <+35>: cmpl $0x1,-0x4(%ebp)
0x08048d99 <+39>: jne 0x8048da2 <phase_4+48>
0x08048d9b <+41>: mov -0xc(%ebp),%eax
0x08048d9e <+44>: test %eax,%eax
0x08048da0 <+46>: jg 0x8048da7 <phase_4+53>
0x08048da2 <+48>: call 0x80496da <explode_bomb>
0x08048da7 <+53>: mov -0xc(%ebp),%eax
0x08048daa <+56>: mov %eax,(%esp)
0x08048dad <+59>: call 0x8048d32 <func4>
0x08048db2 <+64>: mov %eax,-0x8(%ebp)
0x08048db5 <+67>: cmpl $0x262,-0x8(%ebp)
0x08048dbc <+74>: je 0x8048dc3 <phase_4+81>
0x08048dbe <+76>: call 0x80496da <explode_bomb>
0x08048dc3 <+81>: leave
0x08048dc4 <+82>: ret
0x08048d7f <+13>: movl $0x8049a34,0x4(%esp) 可看出此时刻获取了某个参数,打个断点看一下x/s 0x8049a34,得0x8049a34: "%d"
说明此刻输入一个整数
再由
0x08048db5 <+67>: cmpl $0x262,-0x8(%ebp)
0x08048dbc <+74>: je 0x8048dc3 <phase_4+81>
0x08048dbe <+76>: call 0x80496da <explode_bomb>
0x08048dc3 <+81>: leave
得即从斐波那契函数等于0x0x262时是第几个数,即为输入,。
F(x) = F(x-1)+F(x-2), F(1)=1,F(2)=1,F(3)=2......F(15)=610即0x262,但是然后看func4里面有减的,所以要找14。
6. Phase5
调试函数5
08048dc5 <phase_5>:
0x08048dc5 <+0>: push %ebp //压栈 ebp为栈指针 esp为栈指针
0x08048dc6 <+1>: mov %esp,%ebp //把esp赋值给ebp
0x08048dc8 <+3>: sub $0x18,%esp //0x18赋值给esp
=> 0x08048dcb <+6>: mov 0x8(%ebp),%eax //*(esp+8)->eax 就是输入的字符串
0x08048dce <+9>: mov %eax,(%esp) //eax的值赋值给*esp
0x08048dd1 <+12>: call 0x80490e9 <string_length>
0x08048dd6 <+17>: mov %eax,-0x4(%ebp)
0x08048dd9 <+20>: cmpl $0x6,-0x4(%ebp)//输入字符串长6
0x08048ddd <+24>: je 0x8048de4 <phase_5+31>
0x08048ddf <+26>: call 0x80496da <explode_bomb>
0x08048de4 <+31>: movl $0x0,-0x8(%ebp)
0x08048deb <+38>: jmp 0x8048e0d <phase_5+72>
0x08048ded <+40>: mov -0x8(%ebp),%edx
0x08048df0 <+43>: mov -0x8(%ebp),%eax
0x08048df3 <+46>: add 0x8(%ebp),%eax
0x08048df6 <+49>: movzbl (%eax),%eax
0x08048df9 <+52>: movsbl %al,%eax
0x08048dfc <+55>: and $0xf,%eax //取后4位
0x08048dff <+58>: movzbl 0x804a5c0(%eax),%eax
0x08048e06 <+65>: mov %al,-0xf(%ebp,%edx,1)
0x08048e0a <+69>: incl -0x8(%ebp)
0x08048e0d <+72>: cmpl $0x5,-0x8(%ebp)
0x08048e11 <+76>: jle 0x8048ded <phase_5+40>
0x08048e13 <+78>: movb $0x0,-0x9(%ebp)
0x08048e17 <+82>: movl $0x8049a37,0x4(%esp)
0x08048e1f <+90>: lea -0xf(%ebp),%eax
0x08048e22 <+93>: mov %eax,(%esp)
0x08048e25 <+96>: call 0x8049113 <strings_not_equal>
0x08048e2a <+101>: test %eax,%eax
0x08048e2c <+103>: je 0x8048e33 <phase_5+110> //如果eax=0 则进入phase6 否则爆炸
0x08048e2e <+105>: call 0x80496da <explode_bomb>
0x08048e33 <+110>: leave //为结束函数做准备
0x08048e34 <+111>: ret
1.调用string_length测长度3,若不为6则爆炸
8048dd1:e8 13 03 00 00 call 80490e9 <string_length>
8048dd6:89 45 fc mov %eax,-0x4(%ebp)
8048dd9:83 7d fc 06 cmpl $0x6,-0x4(%ebp)//输入字符串长6
8048ddd:74 05 je 8048de4 <phase_5+0x1f>
8048ddf: e8 f6 08 00 00 call 80496da <explode_bomb>
2.循环6次,取出字符,截取低四位
8048df6: 0f b6 00 movzbl (%eax),%eax
8048df9: 0f be c0 movsbl %al,%eax
8048dfc: 83 e0 0f and $0xf,%eax//取后4位
8048dff: 0f b6 80 c0 a5 04 08 movzbl 0x804a5c0(%eax),%eax
8048e06: 88 44 15 f1 mov %al,-0xf(%ebp,%edx,1)
3.根据输入字符ASCII码低四位与索引比较,不同则爆炸。
我们得到的作为参考用,也就是索引表功能的字符串为isrveawhobpnutf,而我们的目的字符串为saints,分别为1位,5位,0位,11位,13位和1位,所以只要我们输入的六个字符的相应的低4位的二进制表示为1,5,0,11,13,1 即可。所以这一关我选取的密码是150km1。
7. Phase6
调试函数6
0x8048e3b <fun6>:
8048e35: 55 push %ebp
8048e36: 89 e5 mov %esp,%ebp
8048e38: 83 ec 10 sub $0x10,%esp # esp-0x10
8048e3b: 8b 45 08 mov 0x8(%ebp),%eax
# eax=arg=local2=0x804a66c
8048e3e: 89 45 f0 mov %eax,-0x10(%ebp) # local4=arg
8048e41: 8b 45 08 mov 0x8(%ebp),%eax
8048e44: 89 45 f0 mov %eax,-0x10(%ebp)
8048e47: 8b 45 08 mov 0x8(%ebp),%eax # eax=arg
# eax=*(arg+8)=*(0x804a66c)
8048e4a: 8b 40 08 mov 0x8(%eax),%eax
# local3=eax=*(0x804a66c)
8048e4d: 89 45 f4 mov %eax,-0xc(%ebp)
# eax=local4=0x804a66c
8048e50: 8b 45 f0 mov -0x10(%ebp),%eax
# *(0x804a66c)=0
8048e53: c7 40 08 00 00 00 00 movl $0x0,0x8(%eax)
8048e5a: eb 62 jmp 8048ebe <fun6+0x89>
#loop
8048e5c: 8b 45 f0 mov -0x10(%ebp),%eax # eax=local4
# local1=local4
8048e5f: 89 45 fc mov %eax,-0x4(%ebp)
8048e62: 8b 45 f0 mov -0x10(%ebp),%eax
# local2=local4
8048e65: 89 45 f8 mov %eax,-0x8(%ebp)
8048e68: eb 0f jmp 8048e79 <fun6+0x44>
8048e6a: 8b 45 fc mov -0x4(%ebp),%eax
8048e6d: 89 45 f8 mov %eax,-0x8(%ebp)
8048e70: 8b 45 fc mov -0x4(%ebp),%eax
8048e73: 8b 40 08 mov 0x8(%eax),%eax
8048e76: 89 45 fc mov %eax,-0x4(%ebp)
8048e79: 83 7d fc 00 cmpl $0x0,-0x4(%ebp)
# if(local1==0)
8048e7d: 74 0e je 8048e8d <fun6+0x58>
8048e7f: 8b 45 fc mov -0x4(%ebp),%eax
8048e82: 8b 10 mov (%eax),%edx
8048e84: 8b 45 f4 mov -0xc(%ebp),%eax
8048e87: 8b 00 mov (%eax),%eax
8048e89: 39 c2 cmp %eax,%edx
8048e8b: 7f dd jg 8048e6a <fun6+0x35>
8048e8d: 8b 45 f8 mov -0x8(%ebp),%eax
8048e90: 3b 45 fc cmp -0x4(%ebp),%eax
8048e93: 74 0b je 8048ea0 <fun6+0x6b>
8048e95: 8b 55 f8 mov -0x8(%ebp),%edx
8048e98: 8b 45 f4 mov -0xc(%ebp),%eax
8048e9b: 89 42 08 mov %eax,0x8(%edx)
8048e9e: eb 06 jmp 8048ea6 <fun6+0x71>
8048ea0: 8b 45 f4 mov -0xc(%ebp),%eax
8048ea3: 89 45 f0 mov %eax,-0x10(%ebp)
8048ea6: 8b 45 f4 mov -0xc(%ebp),%eax
8048ea9: 8b 40 08 mov 0x8(%eax),%eax
8048eac: 89 45 f8 mov %eax,-0x8(%ebp)
8048eaf: 8b 55 f4 mov -0xc(%ebp),%edx
8048eb2: 8b 45 fc mov -0x4(%ebp),%eax
8048eb5: 89 42 08 mov %eax,0x8(%edx)
8048eb8: 8b 45 f8 mov -0x8(%ebp),%eax
8048ebb: 89 45 f4 mov %eax,-0xc(%ebp)
8048ebe: 83 7d f4 00 cmpl $0x0,-0xc(%ebp) #是否为0
#if(local3!=0) jump 39;
8048ec2: 75 98 jne 8048e5c <fun6+0x27>
8048ec4: 8b 45 f0 mov -0x10(%ebp),%eax
8048ec7: c9 leave
8048ec8: c3 ret
0x8048ecf <phase_6>:
0x08048ec9 <+0>: push %ebp
0x08048eca <+1>: mov %esp,%ebp
0x08048ecc <+3>: sub $0x18,%esp
=> 0x08048ecf <+6>: movl $0x804a63c,-0x8(%ebp)
0x08048ed6 <+13>: mov 0x8(%ebp),%eax
0x08048ed9 <+16>: mov %eax,(%esp)
0x08048edc <+19>: call 0x8048858 <atoi@plt>
0x08048ee1 <+24>: mov %eax,%edx
0x08048ee3 <+26>: mov -0x8(%ebp),%eax
0x08048ee6 <+29>: mov %edx,(%eax)
0x08048ee8 <+31>: mov -0x8(%ebp),%eax
0x08048eeb <+34>: mov %eax,(%esp)
0x08048eee <+37>: call 0x8048e35 <fun6>
0x08048ef3 <+42>: mov %eax,-0x8(%ebp)
0x08048ef6 <+45>: mov -0x8(%ebp),%eax
0x08048ef9 <+48>: mov %eax,-0x4(%ebp)
0x08048efc <+51>: movl $0x1,-0xc(%ebp)
0x08048f03 <+58>: jmp 0x8048f11 <phase_6+72>
0x08048f05 <+60>: mov -0x4(%ebp),%eax
0x08048f08 <+63>: mov 0x8(%eax),%eax
0x08048f0b <+66>: mov %eax,-0x4(%ebp)
0x08048f0e <+69>: incl -0xc(%ebp)
0x08048f11 <+72>: cmpl $0x7,-0xc(%ebp)
0x08048f15 <+76>: jle 0x8048f05 <phase_6+60>
0x08048f17 <+78>: mov -0x4(%ebp),%eax
0x08048f1a <+81>: mov (%eax),%edx
0x08048f1c <+83>: mov 0x804a63c,%eax
#在这设置一个断点 break *0x8048f21
0x08048f21 <+88>: cmp %eax,%edx
0x08048f23 <+90>: je 0x8048f2a <phase_6+97>
0x08048f25 <+92>: call 0x80496da <explode_bomb>
0x08048f2a <+97>: leave
0x08048f2b <+98>: ret
看到phase_6的<+88>行是和输入的数做比较,只要在这里设置断点直接查看edx中的值即可
0xf8=248,即为答案。
8.实验总结
所以每个关卡的答案为:
Why make trillions when we could make... billions?
4 5 6 4 5 6
0 y 838
14
150km1
248
一开始接触这个实验的时候什么都不懂或者说是什么都不敢动。查阅一些料后并学习了一些gdb 的使用方法后,开始着手研究反编译代码,并一步一步她开始拆除炸弹。本次实验后,对涌过gdb 调试工具来调试程序有了一些了解。整个二进制炸弹的程序分别用到了直接她址寻址、循环语句、跳转、递归函数、字符串switch码转换和链表等知识,涉及内容多覆盖面广,破解炸弹的过程是一次重要的巩固和提高的过程。
以上是关于CSAPP实验二:二进制炸弹(Bomb Lab)的主要内容,如果未能解决你的问题,请参考以下文章