CSAPP Bomb Lab

本文详细解析了CSAPP炸弹实验室的六道题目,包括字符串比对、数字验证、寄存器工作原理等内容,通过gdb调试技巧展示了如何解决每一道难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CSAPP Bomb Lab

答案

  1. Border relations with Canada have never been better.
  2. 1 2 4 8 16 32
  3. 多个答案
    • 0 207
    • 1 311
    • 2 707
    • 3 256
    • 4 389
    • 5 206
    • 6 682
    • 7 327
  4. 应该有多个答案
    • 7 0
  5. 一个6个字符的字符串,字符串的ascii值依次为
    • 9+k×16
    • 15+k×16
    • 14+k×16
    • 5+k×16
    • 6+k×16
    • 7+k×16
  6. ​ 4 3 2 1 6 5

第一题

解答思路
  • string_not_equal函数比对(0x402400)位置的string与输入的string
  • 直接运行gdb,print (char*)0x402400即可
  • 不需要读完string_not_equal函数,可以猜测0x402400就是要找的,然后一试就过了。不过也不可以绝对相信函数名,或许出题人骗我们呢 2333

第二题

解答思路
  • 汇编代码显示,调用read_six_numbers读入6个数字,放在从栈底开始的24个字节里。测试第一个是否为1,用循环测试后一个是否是前一个的2倍。所以直接输入1 2 4 8 16 32即可AC

第三题

解题思路
  • lea    0xc(%rsp),%rcx //rcx=12+rsp
    lea    0x8(%rsp),%rdx //rdx=8+rsp
    mov    $0x4025cf,%esi //%d %d
    mov    $0x0,%eax
    callq  400bf0 <__isoc99_sscanf@plt>

    从调用sscanf前的寄存器准备工作中看出,%esi放着格式字符串,用gdbprint (char*)0x4025cf打印出"%d %d"

  • 然后测试读入的第一个数字是否大于7,如果是,explode_bomb

  • 然后就是一个switch,用gdbx/14w 0x402470打印出

    0x402470: 0x00400f7c  0x00000000  0x00400fb9  0x00000000
    0x402480: 0x00400f83  0x00000000  0x00400f8a  0x00000000
    0x402490: 0x00400f91  0x00000000  0x00400f98  0x00000000
    0x4024a0: 0x00400f9f  0x00000000

    按照对应关系确定第二个读入的数字即可

第四题

解题思路
  • 同样是用sscanf读入两个数字
  • 由于逻辑比较复杂,但是反编译比较简单,可以直接反编译得到结果

第五题

解题思路
  • callq  40131b <string_length>
    cmp    $0x6,%eax

    读入6个字符的字符串

  • movzbl (%rbx,%rax,1),%ecx
    mov    %cl,(%rsp)
    mov    (%rsp),%rdx
    and    $0xf,%edx
    movzbl 0x4024b0(%rdx),%edx
    mov    %dl,0x10(%rsp,%rax,1)

    提取每个字符的ascii的低4bits,放在edx里,然后从0x4024b0+edx的位置读入数据放在栈上

  • mov    $0x40245e,%esi
    lea    0x10(%rsp),%rdi
    callq  401338 <strings_not_equal>

    后面调用了strings_not_equal,比对0x40245e处的字符串及我们放在栈上的数据。

  • 用gdb分别打印0x4024b0 0x40245e处的字符串,获得

    • maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?
    • flyers
  • 此时可以知道,前面提取数据时,是以我们输入的字符的低4bit的数值为偏移量,从0x4024b0开始的字符串按照偏移量提取字符放在栈上,然后与flyers比对。偏移量依次为 9 15 14 5 6 7

  • 但是这些字符不可打印出来,所以我们需要加上 16×k 来获得可打印的字符

第六题

一些心得
  • 不要尝试完整的人肉反汇编成C,而是大概知道哪段代码有哪些功能,然后用gdb调试,看看猜的对不对。比如本题以下代码

    
    #from 代码段的401153
    
    lea    0x18(%rsp),%rsi
    mov    %r14,%rax
    mov    $0x7,%ecx
    
    mov    %ecx,%edx
    sub    (%rax),%edx
    mov    %edx,(%rax)
    add    $0x4,%rax
    cmp    %rsi,%rax
    jne    401160 <phase_6+0x6c>

    大概知道是改变读入的数字的值,但是不确定确切功能,这时候可以在用gdb,在读入之后的地方设断点,打印这块内存区域的多个字节的值,然后再在这段代码执行后的地方设断点,打印值,观察变化,结合汇编代码,更加容易知道其功能

  • 安利一个gdb插件peda,大大提高gdb的用户体验

解题思路
  • 整段代码分为 个部分

    • 0x4010fc 到 0x401106:读入6个数值

    • 0x40110b 到 0x401151:一个大循环,对读入的数字的合法性进行检查,要求读入的数字的取值范围是 [1,6] ,并且相互之间不相等。(这时候或许就可以暴力了233333)

    • 0x401153 到 0x40116d:另一个循环,对输入的数字顺序进行调整。(一开始想着直接看汇编,但是出错了,后来用gdb调试,很容易就看到了这个特性)

    • 0x401176 到 0x4011a9:一个大循环把链表的node的地址按照一定顺序写到栈上(里面有多个小循环、跳转,比较复杂)。通过大概的反汇编、gdb打印该段代码执行前后内存的值、猜测、测试不同的输入的数字序列,获得该段的功能。

    其中,该段中把关于0x6032d0的值写入栈中,所以用gdb命令x/30w 0x6032d0打印改地址附近的多个字节,结果如下

    0x6032d0 <node1>:   0x0000014c  0x00000001  0x006032e0  0x00000000
    0x6032e0 <node2>:   0x000000a8  0x00000002  0x006032f0  0x00000000
    0x6032f0 <node3>:   0x0000039c  0x00000003  0x00603300  0x00000000
    0x603300 <node4>:   0x000002b3  0x00000004  0x00603310  0x00000000
    0x603310 <node5>:   0x000001dd  0x00000005  0x00603320  0x00000000
    0x603320 <node6>:   0x000001bb  0x00000006  0x00000000  0x00000000

    可以看到有6个node,每个node的第三个字节都对应另一个node的地址,很明显,这是一个链表。

    由此可以知道该段代码的功能为把node的地址写在栈上,地址在栈上的排列顺序由读入的数字确定。当然,读入的数字的顺序在前面的一段代码被处理了,所以直接从汇编了解其逻辑比较难,还是用gdb打印该段代码执行后的值,并且尝试改变输入的数字的顺序来确定该段的逻辑。

    node地址在栈上关于读入的数字的分布规则为

    • node地址越大,对应的数字越小,1对应0x603320,2对应0x603310,3对应0x603300,4对应0x6032f0,5对应0x6032e0,6对应0x6032d0
    • node地址按照读入数字的顺序,排列在栈上。

    • 0x4011ab 到 0x4011d9:该段从%rsp+0x20开始,读入前面写到栈上的node地址,然后写到上一个节点的偏移量为8bit的位置,也就是node里存放next node的指针的位置。其实就是按照栈上node地址的排列顺序重新排列链表里node的顺序,其等价的C代码如下:

    struct node{
        int num;
        int index;
        node *next;
    };
    
    node **next = %rsp+0x28;
    node **endnode = %rsp+0x50;
    node *currentnode = *(%rsp+0x20);
    node *temp;
    while(1){
        temp = *next;
        currentnode->next = temp;
        next += 1;  //in fact, it add 8 bytes;
        if(endnode==next)
            break;
        currentnode = temp;
    }
    temp->next = null;
    • 0x4011df 到 0x4011f5:依次访问链表的节点,判断是否有后一个节点的数据大于前一个的情况,如果有,bomb。

### CSAPP Bomb Lab 实验指导 Bomb Lab 是《计算机系统:程序员视角》(CSAPP) 中的一个重要实验项目。该实验旨在帮助学生理解二进制文件的工作原理以及逆向工程的基础技能。 #### 实验目标 实验的主要目的是让学生通过分析给定的可执行程序 `bomb` 来找出六个阶段(phase) 的输入字符串,从而成功解除炸弹爆炸[^2]。如果输入错误,则会触发“BOOM!!!”,表示炸弹引爆;而正确输入则可以顺利进入下一阶段直至完成全部六阶段挑战。 #### 工具准备 为了顺利完成此实验,建议准备好以下工具: - **GDB调试器**:用于逐步跟踪代码执行过程并查看寄存器状态。 - **objdump反汇编工具**:能够将机器码转换成人类可读形式以便阅读和理解。 - **hex编辑器**:当遇到难以解释的数据时可能需要用到此类软件来观察原始字节流。 #### 解题思路概述 ##### 阶段一至六通用方法论 对于每一个阶段来说,基本策略如下: 1. 使用 GDB 设置断点于各个阶段入口处; 2. 运行程序直到到达指定位置后暂停下来; 3. 利用 objdump 或者其他手段获取当前函数对应的汇编指令集; 4. 结合已知条件推导出满足要求的具体数值或字符序列作为最终答案提交测试验证其有效性。 具体到不同阶段可能会涉及到更复杂的逻辑判断或是特定算法的应用,比如循环结构、位运算操作等都需要仔细研究才能得出结论[^1]。 ```bash gdb ./bomb (gdb) break *phase_1 (gdb) run ``` 上述命令展示了如何设置 GDB 断点以开始对第一个阶段的研究工作。 #### 参考资料推荐 - 官方教材《Computer Systems: A Programmer's Perspective (CSAPP)》,其中包含了大量有关底层编程的知识背景介绍。 - 各大高校公开课程网站上发布的相关教学材料往往也具有很高的参考价值,特别是那些附带详细解答说明的内容更是不可多得的学习资源。 - 社区论坛和技术博客也是不错的选择,在这里可以找到许多前辈分享的经验贴子和个人见解,有助于拓宽解决问题的角度与思维方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值