题目
Ubuntu16.04 amd64
GDB:GNU Project debugger, Ubuntu下sudo apt-get install gdb安装,用来调试
objdump: 用来做反编译器
常用gdb命令
i r
x/s
x/a
ni
i register
(终端计算器bc)
游戏开始前设断点
b explode_bomb
b phase_1
b phase_2
b phase_3
b phase_4
b phase_5
b phase_6
逐个解析
phase_1:
发现有两行都是callq :分别作用是调用 strings_not_equal 和 explode_bomb 这两个函数
而这里 %esi 对应的是第二个参数,第一个参数呢?
当然就是我们拆弹时需要输入的字符串了。
之后的 test 是用来判断函数的返回值 %eax 是否为 0, 如果为 0 则进行跳转,否则炸弹爆炸,所以我们实际上要做的,就是看看 $0x4027f0 这个地址里对应存放的是什么字符串
x/s 0x402400
得到答案Border relations with Canada have never been better
把答案写入answer.txt
set args answer.txt
phase_2:
add指针移四个字节
最重要的add %eax,%eax
所以是乘以2
从cmpl $0x1, (%rsp) 看出第一个数字一定是 1,然后跳转到 +24 的位置,然后把 1 移动到 %ebx 中,跳转到 +57 的位置,然后和 5 进行比较,因为 1 比 5 小,所以会跳转到 +31 的位置。
接着是 movslq 语句,这个语句是带符号地把第一个寄存器扩展并复制到第二个寄存器中,所以现在 %rdx 的值也是 1。lea 之后 %eax 等于 0,然后用 cltq 扩展到 64 位(也就是 %rax 等于 0),接着的语句相当于是 %eax = (%rsp) + 4 * %rax 即 %eax 等于 1。然后与自己相加等于乘以 2,现在 %eax 等于 2,然后等于是判断第二个参数((%rsp, %rdx, 4))和 2 是否相等,所以第二个数字是 2。
然后进行循环的累加并返回到 +31 的位置,继续循环。接着就是类似的操作了,最后分析可以得到每次增大一倍,答案就是 1 2 4 8 16 32。
phase_3:
考查跳转指令控制语句switch
$0x4025cf输入的东西存的地方
从第一个 jmpq 开始,发现是switch语句,case0到case7,一一找出来就好了。
八个答案,输入时记得转化为十进制
可能的答案为:
0 207
1 311
2 707
3 256
4 389
5 206
6 682
7 327
phase_4
比较2和输入的个数:所以是两个输入
用到逻辑右移和算术右移
由它cmpl number1和0的大小,然后相等就je,所以第二个数字 number1 = 0。而第一个数字 number0,要满足 func4(number0, 0, 14) 的返回值为0,来看func4
func4中有个if和else if,而且还callq 400fce,
注意:如果第一个参数number0取得是7,即取 number0 = 7,使 func4(number0, 0, 14) 返回0,就直接跳过那两个大于7或者小于7的判断递归直接到结果
事实上func4函数可以不看,直接设断点枚举输入找需要的输出
phase_5:
要常备ASCII码表
phase_5中if else中else里面有个for循环
mov %fs:0x28,%rax保护模式
xor %eax,%eax抑或
movzbl (%rbx,%rax,1),%ecx 0扩展
两次初始化操作后最后是要比较两个字符串,有一个在0x40245e中即是f:”flyers”,最后答案就是相与之后变成ionefg
从”maduiersnfotvbyl”中得到”flyers”,可以取下标9 15 14 5 6 7,对应十六进制分别为 0x9 0xf 0xe 0x5 0x6 0x7,该输入由input字符串中每个字符的低8位给出。使用man ascii 查看 ASCII 表,对照后可知可以输入 ionefg
phase_6汇编代码巨长
压栈,读取6个数字到 int numbers[6]
第一个循环
读取的第一个数<= 5,就goto L1
输一个序列后按照用7减过的数字再另外开辟一块空间存进去,在此新的空间比较> =
63004492每个加4然后print出来
如:print *6304500
用数组存的,指针只是优化,最后指针便为0
根据输入的数字逆序重排的链表value值但带递增
(要求链表结点的value值严格单调递增),而原来结点的值按顺序依次为0x14c 0xa8 0x39c 0x2b3 0x1dd 0x1bb
结构体如下
|
|
0x14c 0xa8 0x39c 0x2b3 0x1dd 0x1bb
正确顺序应为3 4 5 6 1 2
由此推断4 3 2 1 6 5
secret_phase:
secret_phase是存在的,objdump -t一下能看见这个符号
发现它出现在phase_defused函数里面
read_line和bomb_defused这两个函数吧
查看0x402619处字符串为”%d %d %s”
返回值不是0的时候就跳到401635
set args s
cmp $0x3e8,%eax 比较这两个,所以输入的数字要小于318:即是1000
print *0x6030f0得到36
地址6030f0是个二叉树
看fun7函数递归的反编译:
test %rdi,%rdi %rdi地址是null
注意:64位程序前六个参数原来是存在寄存器里
比较edx就是我们输入的数和edx即36比较
如果大于36就到28行,小于等于就返回值乘以二,第一个返回fun7
rdi的后八位放到rdi里面(为什么是八位?因为64操作系统里指针是八位的)
大于等于就到57
第二个返回fun7:lea 0x1(%rax,%rax,1),%eax
乘以二再加一
不断print 6303984 依次加8
判断条件可以看出这里的每个结点有2个子结点点,子结点的值分别存放在当前结点地址后8位和后16位的位置,看刘聪学长博客
即是二叉树
来看看什么是csapp
提前写好:
b explode_bomb
b pharse_1
b pharse_2
b pharse_3
b pharse_4
b pharse_5
b pharse_6