拆弹实验

二进制拆弹实验通常是一些高校计算机系统基础的实验,通常考察一些汇编的知识和对程序的理解。在这里以一个6关卡的拆弹实验作为例子,讲解拆弹实验的完成思路。

准备工作

linux环境的构建工作,由于我不想写篇幅的限制,在这里就省略了。
准备工作可以大致分为以下几个步骤。

  1. 将炸弹数据包bomblab.tar解压,并进入终端中的炸弹压缩包所在目录
  2. 解压压缩包
    1
    tar -xvf bomblab.tar
  3. 运行炸弹。在解压出来的炸弹文件夹下,运行
    1
    ./bomb
  4. 如果出现权限限制,给bomb增加可执行权限即可
    1
    chmod +x bomb
  5. 利用objdump工具进行反汇编,并将输出的汇编指令导入文件当中
    1
    objdump -d bomb > bomb.s
  6. 接下来打开一个炸弹所在目录下的终端,和bomb.s文件,开始拆弹吧!

工具介绍

GNU symbolic debugger,简称GDB ,是 Linux 中最常用的一款程序调试器。GDB 通常以 gdb 命令的形式在终端(Shell)中使用。

GDB中有很多种的调试命令。现列举在后面过程中经常用到的几种。

  1. 打开GDB: gdb [调试程序名称]
    1
    gdb bomb
  2. 查看寄存器的内容: i r [寄存器名称]
    1
    2
    i r eax
    #info register eax
  3. 查看断点: i b
    1
    2
    i b 
    #info breakpoints
  4. 设置断点: b *[地址]
    1
    b *0x8040abc
  5. 打印字符串: x /s [地址]
    1
    x /s 0x8041234

    phase0 字符串匹配

    题目介绍

    该阶段要求输入与程序中内置的某一特定字符串相匹配的字节序列。

    代码分析

    找到bomb.s中的phase0部分,可能与我下文的内容不一样,只要找到phase0即可。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    0804898b <phase_0>:
    #基址指针入栈,因为要另起一个栈了
    804898b: 55 push %ebp
    #栈顶指针位置变成栈基
    804898c: 89 e5 mov %esp,%ebp
    #栈操作
    804898e: 83 ec 08 sub $0x8,%esp
    8048991: 83 ec 08 sub $0x8,%esp
    #把正确答案入栈
    8048994: 68 ec 96 04 08 push $0x80496ec
    8048999: ff 75 08 pushl 0x8(%ebp)
    #比较输入和正确答案是否一样
    804899c: e8 1a 08 00 00 call 80491bb <strings_not_equal>
    80489a1: 83 c4 10 add $0x10,%esp
    80489a4: 85 c0 test %eax,%eax
    #相等跳转
    80489a6: 74 0c je 80489b4 <phase_0+0x29>
    #炸弹爆炸
    80489a8: e8 76 0a 00 00 call 8049423 <explode_bomb>
    80489ad: b8 00 00 00 00 mov $0x0,%eax
    80489b2: eb 05 jmp 80489b9 <phase_0+0x2e>
    80489b4: b8 01 00 00 00 mov $0x1,%eax
    80489b9: c9 leave
    80489ba: c3 ret
  • 上述的汇编代码是AT&T格式的汇编代码,因此,%表示的意思是(寄存器的)内容。
  • ebp寄存器,其中bp表示base pointer,是基址指针。而e是扩展的意思,随着机器位数增加,出现的扩展。
  • push是入栈,把某个内容推入栈中。
  • mov是移动指令,就是把第一个值赋给第二个,如上第二条指令就是将当前栈顶指针的值赋值给基址指针,可以认为是另起一个栈。
  • push $0x80496ec 可以判断,字符串就是在这时导入进来的。
  • call调用了一个函数,根据英文名称,可以看出这个函数的意思是字符串不相等。
  • je是指jump equal,相等跳转。根据上下文意思可以知道,如果相等,那么就跳转到后面,否则就继续执行到爆炸函数。
  • ret即为return返回。
  • 剩余的内容对于解题来说并非十分重要,因此不予详解。

解决方案

1
2
3
4
5
6
7
8
9
$ gdb bomb

(gdb) b *0xxxxxxxx #这个地址必须是第一个炸弹引爆之前的地址

(gdb) r ans.txt #这个文件是装答案的文件

(gdb) x /s 0xxxxxxx #这个地址是存字符串的地址,一般是push这句话后面跟着的

#得到的字符串就是本题的答案

phase1 浮点表示

题目介绍

该阶段要求输入对应某浮点(float或double)数值表示的一对整数(short或int)。

代码分析

找到bomb.s中的phase1部分,可能与我下文的内容不一样,只要找到phase1即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
080489bb <phase_1>:
80489bb: 55 push %ebp
80489bc: 89 e5 mov %esp,%ebp
80489be: 83 ec 28 sub $0x28,%esp
80489c1: c7 45 f4 91 7b 6a 33 movl $0x336a7b91,-0xc(%ebp)
80489c8: db 45 f4 fildl -0xc(%ebp)
80489cb: dd 5d e8 fstpl -0x18(%ebp)
80489ce: 8d 45 e0 lea -0x20(%ebp),%eax
80489d1: 50 push %eax
80489d2: 8d 45 e4 lea -0x1c(%ebp),%eax
80489d5: 50 push %eax
80489d6: 68 17 97 04 08 push $0x8049717
80489db: ff 75 08 pushl 0x8(%ebp)
80489de: e8 ed fb ff ff call 80485d0 <__isoc99_sscanf@plt>
80489e3: 83 c4 10 add $0x10,%esp
#炸弹爆炸判断条件
80489e6: 83 f8 02 cmp $0x2,%eax
80489e9: 74 0c je 80489f7 <phase_1+0x3c>
80489eb: e8 33 0a 00 00 call 8049423 <explode_bomb>

80489f0: b8 00 00 00 00 mov $0x0,%eax
80489f5: eb 2c jmp 8048a23 <phase_1+0x68>
80489f7: 8d 45 e8 lea -0x18(%ebp),%eax
80489fa: 83 c0 04 add $0x4,%eax
80489fd: 8b 10 mov (%eax),%edx
80489ff: 8b 45 e4 mov -0x1c(%ebp),%eax
8048a02: 39 c2 cmp %eax,%edx
8048a04: 75 0c jne 8048a12 <phase_1+0x57>
8048a06: 8d 45 e8 lea -0x18(%ebp),%eax
8048a09: 8b 10 mov (%eax),%edx
8048a0b: 8b 45 e0 mov -0x20(%ebp),%eax
#炸弹爆炸判断条件
8048a0e: 39 c2 cmp %eax,%edx
8048a10: 74 0c je 8048a1e <phase_1+0x63>
8048a12: e8 0c 0a 00 00 call 8049423 <explode_bomb>

8048a17: b8 00 00 00 00 mov $0x0,%eax
8048a1c: eb 05 jmp 8048a23 <phase_1+0x68>
8048a1e: b8 01 00 00 00 mov $0x1,%eax
8048a23: c9 leave
8048a24: c3 ret
  • 两个炸弹爆炸,条件分别是eax寄存器不等于2,和eax寄存器和edx寄存器内容不相等。
  • 由于题目中提到是一对整数,因此猜测第一次比较2,是比对答案的数目。(后将验证)