CSAPP Bomb Lab

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\times16$
    • $15+k\times16$
    • $14+k\times16$
    • $5+k\times16$
    • $6+k\times16$
    • $7+k\times16$
  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

第三题

解题思路

  • 1
    2
    3
    4
    5
    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打印出

    1
    2
    3
    4
    0x402470:	0x00400f7c	0x00000000	0x00400fb9	0x00000000
    0x402480: 0x00400f83 0x00000000 0x00400f8a 0x00000000
    0x402490: 0x00400f91 0x00000000 0x00400f98 0x00000000
    0x4024a0: 0x00400f9f 0x00000000

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

第四题

解题思路

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

第五题

解题思路

  • 1
    2
    callq  40131b <string_length>
    cmp $0x6,%eax

    读入6个字符的字符串

  • 1
    2
    3
    4
    5
    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的位置读入数据放在栈上

  • 1
    2
    3
    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\times k$来获得可打印的字符

第六题

一些心得

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #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打印改地址附近的多个字节,结果如下

      1
      2
      3
      4
      5
      6
      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代码如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      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。