二进制炸弹实验
实验目的
提升对x86汇编的阅读和理解能力
实验内容
每人一个二进制炸弹:bomb_学号
该炸弹需要接收几组输入
- 如果输入与预期不同,则炸弹会爆炸
为使炸弹不爆炸,需要找到正确的输入
反汇编
调试
实验步骤
准备阶段
-
查看
bomb.c
源文件,分析炸弹的关键在phase_1()
,phase_2()
,phase_3()
三个函数。 -
反汇编给出的二进制文件,使用命令
objdump -d <binary> > xxx.s
然后对三个关键函数的汇编代码进行分析,找到比较语句才能得到答案。
-
对二进制炸弹进行
gdb
调试,使用命令gdb bomb_201902001018
设置断点后,使用
run
命令运行调试,layout regs
分割窗口。
拆弹阶段
第一颗炸弹
-
在
phase_1()
函数里无比较语句,分析其调用的strings_not_equal
函数,且从该函数返回时%eax=0
。 -
在
strings_not_equal
函数中,要使返回%eax=0
,则在调用strcmp@plt
函数后返回%eax=0
,要分析strcmp@plt
函数,进入gdb
调试,设置断点在该函数入口0x8001120
。 -
进入该函数后,
si
命令调试,
分析易知,其实是比较%rdi
和%rsi
,相等则返回%eax=0
。而%rdi
是存着输入字符串,则%rsi
中存着答案,使用命令
x/s $rsi
得到答案
As long as you’re headed that way, I’ll go with you.
第二颗炸弹
-
在
phase_2()
函数中,分析read_six_numbers
函数发现其中有炸弹函数explode_bomb
,不引爆的条件是%eax>6
,进入之前的__isoc99_sscanf@plt
函数。 -
结果分析了半天,发现根本看不懂,执行完这个函数至少几千行。后来考虑函数名
read_six_numbers
应该是读6个数字的意思,在函数的某行发现注释\# 4010 <fmt_six_num>
,应该是把格式存到了%rsi
里,查看是6个整型格式%d
,那么这个函数应该只是判断格式的,输入6个整型再gdb
跳过即可。 -
设置断点
0x80015cf
,即read_six_numbers
后面。执行到下图所在位置分析可知输入的6个数字保存在栈中,位置为从栈顶依次往上;而答案保存在内存地址
0x2a8e+%rip
中,程序依次比较,相等则将%rax+1
,否则引爆炸弹,直到%rax=6
。查看答案所在的内存地址。在执行当前指令后,使用命令x/6w $rdx
得到答案
461 379 521 611 738 579
第三颗炸弹
-
在
phase_3()
中,同phase_2()
设置了格式判断,存在%rsi
中,查看为两个整型格式。输入2个整数跳过判断。 -
设置断点
0x8001643
,分析得%rsp
中内容应该在[0,7]
上,即第一个参数的范围,否则都会爆炸。然后程序根据第一个参数跳转到不同的代码位置,共8种情况。然后将第二个参数分别于内存地址中的magic_num_p3+4i,i=0,1,2..7
进行比较。 -
可知,对应第二个参数答案在该地址里,使用命令。
x/8d 0x8004060
得到
868 184 367 833
82 749 610 802
即答案有8个。依次为
0 868
,1,184
…….7,802
。
验证阶段
将所得答案写入到文件,作为炸弹文件的参数执行,成功通过。
实验思考和总结
- 第一颗炸弹的答案其实在
phase_1()
函数里就存在了%rsi
里面。不用进入后面的函数。 - 本次实验锻炼了我对汇编指令的阅读理解能力,教会了我使用
gdb
进行基本调试。