Bomb Lab:拆除二进制炸弹

Bomb Lab:拆除二进制炸弹

原文:官方实验说明
实验包:bomb.tar

自学包说明:运行配置与原说明的差异

15-213,20xx 年秋季

实验作业 L2:拆除二进制炸弹

布置日期:9 月 13 日;截止日期:9 月 22 日(星期五)。

本次实验的主要负责人是 Harry Bovik(bovik@cs.cmu.edu)。

译注:20xx$Bomblab::SERVER_NAME$Bomblab::REQUESTD_PORT 是原课程模板中的占位内容,按原文保留;日期和联系人也沿用原文。

1 引言

邪恶的 Dr. Evil 在课程使用的机器上安放了大量“二进制炸弹”。二进制炸弹是一个由一系列阶段组成的程序。每个阶段都要求你在 stdin 上输入一个特定的字符串。如果输入正确,该阶段就被拆除,炸弹继续进入下一阶段。否则,炸弹就会“爆炸”:打印 "BOOM!!!",然后终止运行。当所有阶段都被拆除时,整个炸弹才算拆除。

炸弹太多,我们无法一一处理,因此要给每位学生分配一个炸弹去拆除。你的任务是,在截止日期之前拆除自己的炸弹,而且这个任务你别无选择,只能接受。祝你好运,欢迎加入拆弹小组!

步骤 1:获取你的炸弹

在浏览器中访问以下地址,即可获取你的炸弹:

http://$Bomblab::SERVER_NAME:$Bomblab::REQUESTD_PORT/

页面会显示一张二进制炸弹申请表,供你填写。输入用户名和电子邮件地址,然后点击 Submit 按钮。服务器会构建你的炸弹,并将其放在名为 bombk.tar 的 tar 文件中返回给浏览器,其中 k 是你的炸弹的唯一编号。

bombk.tar 文件保存到你打算开展工作的一个(受保护的)目录中。然后执行命令:tar -xvf bombk.tar。这将创建名为 ./bombk 的目录,其中包含以下文件:

  • README:标明炸弹及其所有者。
  • bomb:可执行的二进制炸弹。
  • bomb.c:包含炸弹主例程及 Dr. Evil 友好问候的源文件。
  • writeup.{pdf,ps}:实验说明。

如果你出于某种原因申请了多个炸弹,也没有关系。选择其中一个进行实验,删除其余的即可。

步骤 2:拆除你的炸弹

你在本次实验中的任务就是拆除自己的炸弹。

你必须在课程使用的某台机器上完成作业。事实上,据说 Dr. Evil 确实非常邪恶,炸弹一旦在其他地方运行,就一定会爆炸。我们还听说,炸弹内部另有多种防篡改装置。

你可以借助许多工具拆除炸弹。请阅读提示部分,了解一些技巧和思路。最好的方法是使用你喜欢的调试器,逐步执行反汇编后的二进制程序。

每次炸弹爆炸时,它都会通知 bomblab 服务器,并从你的实验最终成绩中扣除 1/2 分(最多扣除 20 分)。因此,引爆炸弹是有代价的。你必须小心!

前四个阶段各值 10 分。第 5 和第 6 阶段稍难一些,因此各值 15 分。你能获得的最高分是 70 分。

虽然各阶段的拆除难度逐步增加,但你在逐个完成阶段的过程中积累的技能,应该能够抵消这种难度增长。不过,最后一个阶段即使对最优秀的学生也是挑战,因此请不要等到最后一刻才开始。

炸弹会忽略空白输入行。如果你运行炸弹时提供了命令行参数,例如:

linux> ./bomb psol.txt

那么它会从 psol.txt 读取输入行,直到遇到 EOF(文件结束),随后切换到 stdin。Dr. Evil 一时心软,加入了这个功能,让你不必反复输入已经拆除的阶段的解答。

为了避免意外引爆炸弹,你需要学习如何单步执行汇编代码,以及如何设置断点。你还需要学习如何检查寄存器和内存状态。完成本实验的一个有益副作用是,你会变得非常擅长使用调试器。这是一项至关重要的技能,将在你今后的职业生涯中带来丰厚回报。

实验安排

这是一个独立完成的项目。所有作业均以电子方式提交。说明和更正将发布在课程留言板上。

提交

不需要专门执行提交操作。在你拆弹的过程中,炸弹会自动将你的进度告知教师。你可以访问课程排行榜,查看自己的完成情况:

http://$Bomblab::SERVER_NAME:$Bomblab::REQUESTD_PORT/scoreboard

该网页会持续更新,显示每个炸弹的拆除进度。

提示(请务必阅读!)

拆除炸弹有许多方法。你可以完全不运行程序,而是对它进行非常细致的检查,弄清楚它究竟做了什么。这是一项有用的技术,但并不总是容易做到。你也可以在调试器中运行它,一步步观察它的行为,并利用这些信息拆除炸弹。这可能是最快的拆弹方法。

我们确实有一项要求:请不要使用蛮力穷举! 你可以编写一个程序,尝试每一种可能的密钥,以找出正确的那一个。但这样做并不好,原因如下:

  • 每次猜错并引爆炸弹,都会扣除 1/2 分(最多扣除 20 分)。
  • 每次猜错,都会向 bomblab 服务器发送一条消息。你可能很快就会让这些消息挤满网络,并导致系统管理员撤销你的计算机访问权限。
  • 我们没有告诉你字符串有多长,也没有告诉你其中包含哪些字符。即使你作出这些字符串都少于 80 个字符且仅包含字母的(错误)假设,每个阶段也会有 2680 种猜测。这需要极长的运行时间,你无法在作业截止之前得到答案。

有许多工具专门用于帮助你弄清程序如何工作,以及在程序不能正常工作时找出问题所在。下面列出了一些可能有助于分析炸弹的工具,以及它们的使用提示。

  • gdb

    GNU 调试器是一种命令行调试工具,几乎所有平台上都可以使用。你可以逐行跟踪程序、检查内存和寄存器、查看源代码及汇编代码(我们不会提供炸弹的大部分源代码)、设置断点、设置内存观察点,以及编写脚本。

    CS:APP 网站提供了一份非常方便的单页 gdb 速查表,你可以打印出来作为参考。以下是使用 gdb 的另外一些提示:

    • 为了避免每次输入错误内容都会引爆炸弹,你需要学习如何设置断点。
    • 要查看联机文档,可以在 gdb 命令提示符下输入 help,或在 Unix 提示符下输入 man gdbinfo gdb。有些人也喜欢在 emacsgdb-mode 中运行 gdb
  • objdump -t

    此命令会打印炸弹的符号表。符号表包含炸弹中所有函数和全局变量的名称、炸弹所调用的所有函数的名称,以及它们的地址。查看函数名,也许能让你有所发现!

  • objdump -d

    使用此命令可以反汇编炸弹中的全部代码。你也可以只查看个别函数。阅读汇编代码可以让你了解炸弹如何工作。

    虽然 objdump -d 能提供大量信息,但它并不能告诉你全部情况。对系统级函数的调用会以难以理解的形式显示。例如,对 sscanf 的一次调用可能显示为:

    8048c36: e8 99 fc ff ff call 80488d4 <_init+0x1a0>

    要确定这里调用的是 sscanf,你需要在 gdb 中进行反汇编。

  • strings

    此工具会显示炸弹中的可打印字符串。

正在寻找某个工具?或者在找文档?别忘了,aproposmaninfo 命令都是你的好帮手。特别是 man ascii,可能会派上用场。info gas 会提供关于 GNU 汇编器的详尽信息,多到超出你的想象。此外,网络也可能是一座信息宝库。如果遇到难题,尽管向教师求助。