我们看了很多关于特种兵在危机关头拆炸弹的场景,觉得很酷吧!所以现在就让我们来拆一个“炸弹”。Bomb Lab这个实验是相当有趣的,比起之前耗脑的Data Lab,这个Lab主要是学习反汇编以及阅读反汇编出来的汇编代码。通过对一个二进制可执行文件的反汇编,找出正确的(那根线),然后“剪短“,否则的话就会”Boom!“,不过不会立即伤及生命,如果你在CMU上课,你会丢掉0.5分,如果不是,你会收到愤怒。现在就来看看我的拆炸弹之旅吧!这里我的环境是OS X El Capitan还有Ubuntu 16.04,所以LLDB和GDB一起上,不过反汇编出来的代码都差不多:
Phase1
Mac没有GDB,所以就使用LLDB来代替喽:
进入LLDB
lldb bomb
使用disassemble
进行反汇编,参考bomb.c文件,可以知道主要的几个函数名:首先是Phase_1
(lldb) disas -n phase_1
得到以下汇编代码
bomb`phase_1:
bomb[0x400ee0] <+0>: subq $0x8, %rsp
bomb[0x400ee4] <+4>: movl $0x402400, %esi
bomb[0x400ee9] <+9>: callq 0x401338 ; strings_not_equal
bomb[0x400eee] <+14>: testl %eax, %eax
bomb[0x400ef0] <+16>: je 0x400ef7 ; <+23>
bomb[0x400ef2] <+18>: callq 0x40143a ; explode_bomb
bomb[0x400ef7] <+23>: addq $0x8, %rsp
bomb[0x400efb] <+27>: retq
这段代码还是挺好理解的,保存栈指针(Stack pointer),将 $0x402400
传给%esi
,调用位于0x401338
的strings_not_equal
函数,比较%eax
是否为0
,不为零则调用explode_bomb
函数,为零则返回。所以关键要找出字符串是什么。根据上述的汇编代码,可以发现字符串被保存在0x402400
这里,所以使用print
来查看:
(lldb) print (char *)0x402400
得到
0x00402400: "Border relations with Canada have never been better."
所以第一关的答案就是这个啦!
Phase2
同样,还是先反汇编出代码
bomb`phase_2:
bomb[0x400efc] <+0>: pushq %rbp
bomb[0x400efd] <+1>: pushq %rbx
bomb[0x400efe] <+2>: subq $0x28, %rsp
bomb[0x400f02] <+6>: movq %rsp, %rsi
bomb[0x400f05] <+9>: callq 0x40145c ; read_six_numbers
bomb[0x400f0a] <+14>: cmpl $0x1, (%rsp)
bomb[0x400f0e] <+18>: je 0x400f30 ; <+52>
bomb[0x400f10] <+20>: callq 0x40143a ; explode_bomb
bomb[0x400f15] <+25>: jmp 0x400f30 ; <+52>
bomb[0x400f17] <+27>: movl -0x4(%rbx), %eax
bomb[0x400f1a] <+30>: addl %eax, %eax
bomb[0x400f1c] <+32>: cmpl %eax, (%rbx)
bomb[0x400f1e] <+34>: je 0x400f25 ; <+41>
bomb[0x400f20] <+36>: callq 0x40143a ; explode_bomb
bomb[0x400f25] <+41>: addq $0x4, %rbx
bomb[0x400f29] <+45>: cmpq %rbp, %rbx
bomb[0x400f2c] <+48>: jne 0x400f17 ; <+27>
bomb[0x400f2e] <+50>: jmp 0x400f3c ; <+64>
bomb[0x400f30] <+52>: leaq 0x4(%rsp), %rbx
bomb[0x400f35] <+57>: leaq 0x18(%rsp), %rbp
bomb[0x400f3a] <+62>: jmp 0x400f17 ; <+27>
bomb[0x400f3c] <+64>: addq $0x28, %rsp
bomb[0x400f40] <+68>: popq %rbx
bomb[0x400f41] <+69>: popq %rbp
bomb[0x400f42] <+70>: retq
从上述汇编中,可以发现从%rsp
位置开始保存数字。反汇编read_six_numbers
得到
bomb`read_six_numbers:
bomb[0x40145c] <+0>: subq $0x18, %rsp
bomb[0x401460] <+4>: movq %rsi, %rdx
bomb[0x401463] <+7>: leaq 0x4(%rsi), %rcx
bomb[0x401467] <+11>: leaq 0x14(%rsi), %rax
bomb[0x40146b] <+15>: movq %rax, 0x8(%rsp)
bomb[0x401470] <+20>: leaq 0x10(%rsi), %rax
bomb[0x401474] <+24>: movq %rax, (%rsp)
bomb[0x401478] <+28>: leaq 0xc(%rsi), %r9
bomb[0x40147c] <+32>: leaq 0x8(%rsi), %r8
bomb[0x401480] <+36>: movl $0x4025c3, %esi
bomb[0x401485] <+41>: movl $0x0, %eax
bomb[0x40148a] <+46>: callq 0x400bf0 ; symbol stub for: __isoc99_sscanf
bomb[0x40148f] <+51>: cmpl $0x5, %eax
bomb[0x401492] <+54>: jg 0x401499 ; <+61>
bomb[0x401494] <+56>: callq 0x40143a ; explode_bomb
bomb[0x401499] <+61>: addq $0x18, %rsp
bomb[0x40149d] <+65>: retq
根据Phase1,很敏感的会发现movl $0x4025c3, %esi
这行。通过之前一样的方法,得到0x4025c3
内存里的字符串,0x004025c3: "%d %d %d %d %d %d"
再根据bomb[0x4014