Note

  • 具体代码请移步至GitHub.

Bomb Lab

实验目的

对可执行文件 bomb 进行调试, 深入其汇编代码, 依次推断出 6 个密码并通过相应 6 个阶段的考验. 除了这 6 个考验以外还存在第七个隐藏考验, 因此实际上共有 7 个阶段的考验以及对应的密码, 具体见下方小节.

实验框架

bomb - 待调试文件主体

bomb 为可执行文件, 需要对其进行调试并破解得到 6 个密码 (加上隐藏考验总共为 7 个密码).

bomb.c - 描述主体构成

bomb.c 中使用 C 程序描述了炸弹 bomb 的主体构成, 其中 support.hphases.h 猜测是实现炸弹本体的代码的头文件.

观察 bomb.c 可得到 bomb 的构成如下:

  • 首先检查命令行中是否给出文件路径, 并打开标准输入/给定文件.
  • 初始化炸弹: initialize_bomb();
  • 连续执行 6 个阶段, 每个阶段均为读入一行输入, 将输入用于解密, 若解密成功则可顺序进入下一阶段, 若 6 个阶段均解密成功则函数退出 (炸弹解除).
  • 此外还可选择挑战第七个隐藏考验.

评价标准

  • 前 4 个考验每个分别占 10 分, 最后 2 个考验每个占 15 分. 总分为 70 分.
  • 对于校内的同学, 每次炸弹爆炸将会向服务器发送一个消息并在最终得分中减去 0.5 分 (最多不超过 20 分, 即 40 次爆炸).

实验思路与总结

目录结构:

  • 可执行文件 bomb 的反汇编内容见文件objdump_bomb.txt.
  • 下列所有函数的机器指令的具体解释见目录disas-output, 某些特定函数所需要的额外信息 (例如跳转表或全局字符串等) 将会在对应的 disas_xxx.txt 文件开头列出.
  • 测试通过的 7 个密码见文件password.txt.

sig_handler

对炸弹拆除进度进行安全重置 :-).

initialize_bomb

函数 initialize_bomb 使用 C 库函数 signal 为信号 SIGINT 安装处理程序 sig_handler.

string_length

函数 string_length 返回所传入字符串的长度.

strings_not_equal

函数 strings_not_equal 检查传入的 2 个字符串是否相同.

explode_bomb

函数 explode_bomb 输出 "炸弹拆除失败" 的提示信息并终止整个程序.

phase_defused

函数 phase_defused 首先检查是否已经通过前 6 个阶段, 若仍未通过前 6 个阶段则直接返回; 若已经通过前 6 个阶段则尝试从第四个阶段的密码中读取开启隐藏阶段的口令, 若口令读取成功并且与一个已知字符串相同则进入隐藏阶段; 否则输出 "成功拆除炸弹" 的提示信息并返回.

read_six_numbers

函数 read_six_numbers 从传入的字符串中读取 6 个整数.

func4

函数 func4 在一个给定范围内对目标值进行二分查找, 并在递归过程中按一定规则产生最终的返回值.

  • 注: 在二分查找时还 func4 还实现了补码下整数除以 2 的幂的算法.

fun7

函数 fun7 在一棵简单的二叉搜索树中查找给定整数, 并在递归过程中按一定规则产生最终的返回值.

phase_1

函数 phase_1 通过调用函数 strings_not_equal 来比较密码是否与一个已知字符串相同.

phase_2

函数 phase_2 首先调用函数 read_six_numbers 从密码中读入 6 个整数, 然后检查这 6 个整数是否满足特定规则.

phase_3

函数 phase_3 首先调用函数 sscanf 读入 2 个整数, 然后实现了一个简单的 C 语言 switch 语句来检查这 2 个数字是否满足特定规则.

phase_4

函数 phase_4 首先调用函数 sscanf 读入 2 个整数, 然后将第一个整数传入函数 func4 并得到 1 个整数结果, 最后检查所返回的整数结果以及第二个整数是否满足特定规则.

phase_5

函数 phase_5 将输入的密码字符串看作是一串整数数组, 通过将数组中的整数作为下标索引某个字母表来将整数数组映射为长度相等的新字符串, 最后比较新字符串是否与一个已知字符串相同.

phase_6

函数 phase_6 首先调用函数 read_six_numbers 从密码中读取 6 个整数, 并使用这 6 个整数从某个全局链表中依次挑选出 6 个结点并连接形成一个新的链表, 最后检查新的链表中的值是否满足特定规则.

secret_phase

函数 secret_phase 首先调用 read_line 函数读入第七个密码, 然后使用 C 库函数 strtol 将其转换为整数, 将该整数传入函数 fun7 得到结果, 最后检查该结果是否满足特定规则.

实验结果展示

见目录 disas-output 下的所有反汇编代码 (已详细注释).

相关资料

GDB

Linux 命令

  • objdump -t <binary-executable>:

    • 打印符号表 (symbol table).
  • objdump -d <binary-executable>:

    • 反汇编. 对于像系统调用 (例如 sscanf) 这样的函数而言, 反汇编得到的函数名有可能不是很直观, 此时在 gdb 中进行反汇编是更好的选择.
  • strings <binary-executable>:

    • 打印可执行文件中的所有可打印字符串.
  • man ascii:

    • 打印关于 ascii 编码的相关文档.
  • info gas:

    • 打印关于 gas 的文档. 如果报错 info: No menu item 'gas' in node '(dir)Top', 需要检查 binutils 包是否安装:

      1
      2
      3
      4
      5
      6
      
      # Check if binutils is installed
      which as
      
      # If binutils is not installed, install it
      sudo apt-get update
      sudo apt-get install binutils
      

      如果已经安装, 再检查是否安装文档 (因为有些 Linux 发行版可能会将 doc 和 software 分开打包):

      1
      2
      
      # Install documentation for binutils, which includes gas
      sudo apt-get install binutils-doc