CSAPP Bomb Lab

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/h_zx_h_zx/article/details/77990360

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。

展开阅读全文

没有更多推荐了,返回首页