CSAPP BOMB Lab

栏目: C · 发布时间: 7年前

内容简介:最近复习 CSAPP,BOMB Lab 作为 CSAPP 第三章的配套练习。做完这个练习也是花了较多时间,学到了很多。(好气啊)搞了半天没搞好汇编的高亮,只能先将就着把博客发出来,没高亮有点恶心,还请多见谅整个 Lab 主要用到了 objdump 和 gdb(lldb) 进行分析。

最近复习 CSAPP,BOMB Lab 作为 CSAPP 第三章的配套练习。做完这个练习也是花了较多时间,学到了很多。

(好气啊)搞了半天没搞好汇编的高亮,只能先将就着把博客发出来,没高亮有点恶心,还请多见谅

整个 Lab 主要用到了 objdump 和 gdb(lldb) 进行分析。

直接利用 objdump -d 获得汇编代码开始分析。一共有 6 个 phase,我们先从第一个开始。

phase_1

400ee0:    48 83 ec 08              sub    $0x8,%rsp
  400ee4:    be 00 24 40 00           mov    $0x402400,%esi
  400ee9:    e8 4a 04 00 00           callq  401338 
<strings_not_equal>
 
  400eee:    85 c0                    test   %eax,%eax
  400ef0:    74 05                    je     400ef7 
 <phase_1 0x17="">
  
  400ef2:    e8 43 05 00 00           callq  40143a 
  <explode_bomb>
   
  400ef7:    48 83 c4 08              add    $0x8,%rsp
  400efb:    c3                       retq 

  </explode_bomb>
 </phase_1>
</strings_not_equal>

$0x402400 传给 %esi 寄存器,并调用 strings_not_equal 函数,然后判断 %eax 中是否为 0,为 0 则返回,非 0 则 BOMB!!

因此关键在于找出需要比较的 strings 是啥。这里就比较简单了,%esi 寄存器用于保存传递给调用函数的第二个参数,因此需要比对的字符串保存在 $0x402400 地址处。利用 gdb(这里使用 Mac 的 lldb 作为替代) 的 x 指令可以查看指定内存地址的值。

(lldb) x/s 0x402400
0x00402400: "Border relations with Canada have never been better."

关于第一个参数,是在调用 phase_1 函数时就传递进来的(%rdi 寄存器保存第一个参数),然后两个参数一起传入 strings_not_equal 函数

400e32:    e8 67 06 00 00           callq  40149e 
<read_line>
 
  400e37:    48 89 c7                 mov    %rax,%rdi
  400e3a:    e8 a1 00 00 00           callq  400ee0 
 <phase_1>
  
  400e3f:    e8 80 07 00 00           callq  4015c4 
  <phase_defused>

  </phase_defused>
 </phase_1>
</read_line>

利用 ida 反编译结果如下:

__int64 __fastcall phase_1(__int64 a1)
{
  __int64 result; // rax

  result = strings_not_equal(a1, "Border relations with Canada have never been better.");
  if ( (_DWORD)result )
    explode_bomb(a1, "Border relations with Canada have never been better.");
  return result;
}

phase_2

400efc:    55                       push   %rbp
  400efd:    53                       push   %rbx
  400efe:    48 83 ec 28              sub    $0x28,%rsp
  400f02:    48 89 e6                 mov    %rsp,%rsi
  400f05:    e8 52 05 00 00           callq  40145c 
<read_six_numbers>
 
  400f0a:    83 3c 24 01              cmpl   $0x1,(%rsp)
  400f0e:    74 20                    je     400f30 
 <phase_2 0x34="">
  
  400f10:    e8 25 05 00 00           callq  40143a 
  <explode_bomb>
   
  400f15:    eb 19                    jmp    400f30 
   <phase_2 0x34="">
    

  400f17:    8b 43 fc                 mov    -0x4(%rbx),%eax
  400f1a:    01 c0                    add    %eax,%eax
  400f1c:    39 03                    cmp    %eax,(%rbx)
  400f1e:    74 05                    je     400f25 
    <phase_2 0x29="">
     
  400f20:    e8 15 05 00 00           callq  40143a 
     <explode_bomb>
      
  400f25:    48 83 c3 04              add    $0x4,%rbx
  400f29:    48 39 eb                 cmp    %rbp,%rbx
  400f2c:    75 e9                    jne    400f17 
      <phase_2 0x1b="">
       
  400f2e:    eb 0c                    jmp    400f3c 
       <phase_2 0x40="">
        
  400f30:    48 8d 5c 24 04           lea    0x4(%rsp),%rbx
  400f35:    48 8d 6c 24 18           lea    0x18(%rsp),%rbp
  400f3a:    eb db                    jmp    400f17 
        <phase_2 0x1b="">
         

  400f3c:    48 83 c4 28              add    $0x28,%rsp
  400f40:    5b                       pop    %rbx
  400f41:    5d                       pop    %rbp
  400f42:    c3                       retq   

        </phase_2>
       </phase_2>
      </phase_2>
     </explode_bomb>
    </phase_2>
   </phase_2>
  </explode_bomb>
 </phase_2>
</read_six_numbers>

phase_2 中,可以看到函数先调用了 read_six_number 函数,并将当前栈指针( %rsp 保存的内容)作为参数( $rsi )传递进去,跟进该函数

40145c:    48 83 ec 18              sub    $0x18,%rsp
  401460:    48 89 f2                 mov    %rsi,%rdx
  401463:    48 8d 4e 04              lea    0x4(%rsi),%rcx
  401467:    48 8d 46 14              lea    0x14(%rsi),%rax
  40146b:    48 89 44 24 08           mov    %rax,0x8(%rsp)
  401470:    48 8d 46 10              lea    0x10(%rsi),%rax
  401474:    48 89 04 24              mov    %rax,(%rsp)
  401478:    4c 8d 4e 0c              lea    0xc(%rsi),%r9
  40147c:    4c 8d 46 08              lea    0x8(%rsi),%r8
  401480:    be c3 25 40 00           mov    $0x4025c3,%esi
  401485:    b8 00 00 00 00           mov    $0x0,%eax
  40148a:    e8 61 f7 ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  40148f:    83 f8 05                 cmp    $0x5,%eax
  401492:    7f 05                    jg     401499 
<read_six_numbers 0x3d="">
 
  401494:    e8 a1 ff ff ff           callq  40143a 
 <explode_bomb>
  

  401499:    48 83 c4 18              add    $0x18,%rsp
  40149d:    c3                       retq  

 </explode_bomb>
</read_six_numbers>

与 phase_1 类似,查看 0x4025c3 处的内容

(lldb) x/s 0x4025c3
0x004025c3: "%d %d %d %d %d %d"

结合前面的汇编代码,得处函数的作用就是读取 6 个整数,保存在 (%rsi ~ %rsi+18)这个区间里,而 %rsi 中保存的地址其实就是 phase_2 函数中栈指针 %rsp 的内容。所以实际读取的数据已经保存在了 phase_2 的函数栈中

反编译结果如下:

__int64 __fastcall read_six_numbers(__int64 a1, __int64 a2)
{
  __int64 result; // rax

  result = __isoc99_sscanf(a1, &unk_4025C3, a2, a2 + 4, a2 + 8, a2 + 12, a2 + 16, a2 + 20);
  if ( (signed int)result <= 5 )
    explode_bomb();
  return result;
}

回到 phase_2 继续分析,读取整数后的下一行 cmpl $0x1,(%rsp) ,而 (%$rsp) 对应的值正式读取的第一个数,可以看出该数必须为 1,然后跳至 400f30 ,进入函数的核心,也就是一个循环。

汇编代码中利用空行隔离出了循环代码,逻辑比较简单,就是每次都在上一个的数的基础上翻倍,即以 2 为公比的等比数列,因此 phase_2 的答案就是 1 2 4 8 16 32

反编译结果:

__int64 __fastcall phase_2(__int64 a1)
{
  __int64 result; // rax
  __int64 *v2; // rbx
  __int64 v3; // [rsp-38h] [rbp-38h]
  __int64 v4; // [rsp-20h] [rbp-20h]

  read_six_numbers(a1, &v3);
  if ( (_DWORD)v3 != 1 )
    explode_bomb();
  v2 = (__int64 *)((char *)&v3 + 4);
  do {
    result = (unsigned int)(2 * *((_DWORD *)v2 - 1));
    if ( *(_DWORD *)v2 != (_DWORD)result )
      explode_bomb();
    v2 = (__int64 *)((char *)v2 + 4);
  } while ( v2 != &v4 );
  return result;
}

phase_3

400f43:    48 83 ec 18              sub    $0x18,%rsp
  400f47:    48 8d 4c 24 0c           lea    0xc(%rsp),%rcx
  400f4c:    48 8d 54 24 08           lea    0x8(%rsp),%rdx
  400f51:    be cf 25 40 00           mov    $0x4025cf,%esi
  400f56:    b8 00 00 00 00           mov    $0x0,%eax
  400f5b:    e8 90 fc ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  400f60:    83 f8 01                 cmp    $0x1,%eax
  400f63:    7f 05                    jg     400f6a 
<phase_3 0x27="">
 
  400f65:    e8 d0 04 00 00           callq  40143a 
 <explode_bomb>
  
  400f6a:    83 7c 24 08 07           cmpl   $0x7,0x8(%rsp)

  400f6f:    77 3c                    ja     400fad 
  <phase_3 0x6a="">
   
  400f71:    8b 44 24 08              mov    0x8(%rsp),%eax
  400f75:    ff 24 c5 70 24 40 00     jmpq   *0x402470(,%rax,8)
  400f7c:    b8 cf 00 00 00           mov    $0xcf,%eax
  400f81:    eb 3b                    jmp    400fbe 
   <phase_3 0x7b="">
    
  400f83:    b8 c3 02 00 00           mov    $0x2c3,%eax
  400f88:    eb 34                    jmp    400fbe 
    <phase_3 0x7b="">
     
  400f8a:    b8 00 01 00 00           mov    $0x100,%eax
  400f8f:    eb 2d                    jmp    400fbe 
     <phase_3 0x7b="">
      
  400f91:    b8 85 01 00 00           mov    $0x185,%eax
  400f96:    eb 26                    jmp    400fbe 
      <phase_3 0x7b="">
       
  400f98:    b8 ce 00 00 00           mov    $0xce,%eax
  400f9d:    eb 1f                    jmp    400fbe 
       <phase_3 0x7b="">
        
  400f9f:    b8 aa 02 00 00           mov    $0x2aa,%eax
  400fa4:    eb 18                    jmp    400fbe 
        <phase_3 0x7b="">
         
  400fa6:    b8 47 01 00 00           mov    $0x147,%eax
  400fab:    eb 11                    jmp    400fbe 
         <phase_3 0x7b="">
          
  400fad:    e8 88 04 00 00           callq  40143a 
          <explode_bomb>
           
  400fb2:    b8 00 00 00 00           mov    $0x0,%eax
  400fb7:    eb 05                    jmp    400fbe 
           <phase_3 0x7b="">
            
  400fb9:    b8 37 01 00 00           mov    $0x137,%eax

  400fbe:    3b 44 24 0c              cmp    0xc(%rsp),%eax
  400fc2:    74 05                    je     400fc9 
            <phase_3 0x86="">
             
  400fc4:    e8 71 04 00 00           callq  40143a 
             <explode_bomb>
              
  400fc9:    48 83 c4 18              add    $0x18,%rsp
  400fcd:    c3                       retq

             </explode_bomb>
            </phase_3>
           </phase_3>
          </explode_bomb>
         </phase_3>
        </phase_3>
       </phase_3>
      </phase_3>
     </phase_3>
    </phase_3>
   </phase_3>
  </phase_3>
 </explode_bomb>
</phase_3>

函数接受两个整数输入

(lldb) x/s 0x4025cf
0x004025cf: "%d %d"

从后面一连串的相似结构可以看出函数中包含一个 switch 语句,跳转到 0x402470+ %rax * 8 的位置

通过如下方式获得跳转表:

(lldb)  p/x *(int *)(0x402470)
(int) $1 = 0x00400f7c
(lldb)  p/x *(int *)(0x402470+8)
(int) $2 = 0x00400fb9
...

通过跳转表可获得 8 对解,分别对应应该传入的两个参数

反编译结果:

signed __int64 __fastcall phase_3(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6)
{
  signed __int64 result; // rax
  __int64 v7; // [rsp-10h] [rbp-10h]

  if ( (signed int)__isoc99_sscanf(a1, "%d %d", &v7, (char *)&v7 + 4, a5, a6) <= 1 )
    explode_bomb(a1, "%d %d");
  switch ( (_DWORD)v7 )
  {
    case 0:
      result = 207LL;
      break;
    case 1:
      result = 311LL;
      break;
    case 2:
      result = 707LL;
      break;
    case 3:
      result = 256LL;
      break;
    case 4:
      result = 389LL;
      break;
    case 5:
      result = 206LL;
      break;
    case 6:
      result = 682LL;
      break;
    case 7:
      result = 327LL;
      break;
    default:
      explode_bomb(a1, "%d %d");
      return result;
  }
  if ( (_DWORD)result != HIDWORD(v7) )
    explode_bomb(a1, "%d %d");
  return result;
}

phase_4

40100c:    48 83 ec 18              sub    $0x18,%rsp
  401010:    48 8d 4c 24 0c           lea    0xc(%rsp),%rcx
  401015:    48 8d 54 24 08           lea    0x8(%rsp),%rdx
  40101a:    be cf 25 40 00           mov    $0x4025cf,%esi
  40101f:    b8 00 00 00 00           mov    $0x0,%eax
  401024:    e8 c7 fb ff ff           callq  400bf0 <__isoc99_sscanf@plt>
  401029:    83 f8 02                 cmp    $0x2,%eax
  40102c:    75 07                    jne    401035 
<phase_4 0x29="">
 

  40102e:    83 7c 24 08 0e           cmpl   $0xe,0x8(%rsp)
  401033:    76 05                    jbe    40103a 
 <phase_4 0x2e="">
  
  401035:    e8 00 04 00 00           callq  40143a 
  <explode_bomb>
   
  40103a:    ba 0e 00 00 00           mov    $0xe,%edx
  40103f:    be 00 00 00 00           mov    $0x0,%esi
  401044:    8b 7c 24 08              mov    0x8(%rsp),%edi
  401048:    e8 81 ff ff ff           callq  400fce 
   <func4>
    
  40104d:    85 c0                    test   %eax,%eax
  40104f:    75 07                    jne    401058 
    <phase_4 0x4c="">
     

  401051:    83 7c 24 0c 00           cmpl   $0x0,0xc(%rsp)
  401056:    74 05                    je     40105d 
     <phase_4 0x51="">
      
  401058:    e8 dd 03 00 00           callq  40143a 
      <explode_bomb>
       
  40105d:    48 83 c4 18              add    $0x18,%rsp
  401061:    c3                       retq   

      </explode_bomb>
     </phase_4>
    </phase_4>
   </func4>
  </explode_bomb>
 </phase_4>
</phase_4>

第一部分逻辑与 phase_3 一样,读取两个整数设为 a1(a1 < 15), a2

第二部分对 a1 进行校验,将 a1, 0, 15, 作为参数传入 func4

第三部分校验 a2,只需要 a2=0 即可

func4 如下:

# 设 y in %eax, v1 in edi, v2 in %esi, v3 in %edx, v4 in %ecx
  400fce:    48 83 ec 08              sub    $0x8,%rsp 
  400fd2:    89 d0                    mov    %edx,%eax    # y = v3
  400fd4:    29 f0                    sub    %esi,%eax    # y -= v2
  400fd6:    89 c1                    mov    %eax,%ecx    # v4 = y
  400fd8:    c1 e9 1f                 shr    $0x1f,%ecx   # 右移 31 位取得 v4 的符号位
  400fdb:    01 c8                    add    %ecx,%eax    # y+= v4
  400fdd:    d1 f8                    sar    %eax         # y /= 2
  400fdf:    8d 0c 30                 lea    (%rax,%rsi,1),%ecx   #v4 = y+v2
  400fe2:    39 f9                    cmp    %edi,%ecx    v1 < v4?
  400fe4:    7e 0c                    jle    400ff2 
<func4 0x24="">
 
  400fe6:    8d 51 ff                 lea    -0x1(%rcx),%edx          # v3 = v4-1
400fe9:    e8 e0 ff ff ff           callq  400fce 
 <func4>
           # func4(v1, v2, v3)
  400fee:    01 c0                    add    %eax,%eax            # y *= 2
  400ff0:    eb 15                    jmp    401007 
  <func4 0x39="">
     # return
  400ff2:    b8 00 00 00 00           mov    $0x0,%eax        # y = 0
  400ff7:    39 f9                    cmp    %edi,%ecx        # v1 > v4?
  400ff9:    7d 0c                    jge    401007 
   <func4 0x39="">
    
  400ffb:    8d 71 01                 lea    0x1(%rcx),%esi   # v4 += 1
  400ffe:    e8 cb ff ff ff           callq  400fce 
    <func4>
        #func4(v1, v2, v3)
  401003:    8d 44 00 01              lea    0x1(%rax,%rax,1),%eax  # y = 2y+1

  401007:    48 83 c4 08              add    $0x8,%rsp
  40100b:    c3                       retq   

    </func4>
   </func4>
  </func4>
 </func4>
</func4>

func4 比较清晰,就是函数迭代,因此直接在源码加以注释

大致作用通过二分搜索逼近,使得 v1(传入的值即 a1) 与 v4([v3-v2+sign(v3-v2)]/2+v2 即 v2 与 v3 的中间值) 相等返回 0

__int64 __fastcall func4(__int64 a1, __int64 a2, int a3)
{
  signed int v3; // ecx
  __int64 result; // rax

  v3 = (a3 - (signed int)a2) / 2 + a2;
  if ( v3 > (signed int)a1 )
    return 2 * (unsigned int)func4(a1, a2, v3 - 1);
  result = 0LL;
  if ( v3 < (signed int)a1 )
    result = 2 * (unsigned int)func4(a1, (unsigned int)(v3 + 1), a3) + 1;
  return result;
}

由于当 v4 < v1 时 y = 2y + 1一定不会为 0,因此需要 v4 始终大于等于 v1 ,等于 v1 后返回 0,因此可选值为 7,3,1,0 均可

__int64 __fastcall phase_4(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6)
{
  __int64 v6; // rdi
  __int64 result; // rax
  __int64 v8; // [rsp-10h] [rbp-10h]

  if ( (unsigned int)__isoc99_sscanf(a1, "%d %d", &v8, (char *)&v8 + 4, a5, a6) != 2 || (unsigned int)v8 > 0xE )
    explode_bomb(a1, "%d %d");
  v6 = (unsigned int)v8;
  result = func4((unsigned int)v8, 0LL, 14);
  if ( (_DWORD)result || HIDWORD(v8) )
    explode_bomb(v6, 0LL);
  return result;
}

phase_5

401062:    53                       push   %rbx
  401063:    48 83 ec 20              sub    $0x20,%rsp

  401067:    48 89 fb                 mov    %rdi,%rbx
  40106a:    64 48 8b 04 25 28 00     mov    %fs:0x28,%rax
  401071:    00 00 
  401073:    48 89 44 24 18           mov    %rax,0x18(%rsp)
  401078:    31 c0                    xor    %eax,%eax

  40107a:    e8 9c 02 00 00           callq  40131b 
<string_length>
 
  40107f:    83 f8 06                 cmp    $0x6,%eax
  401082:    74 4e                    je     4010d2 
 <phase_5 0x70="">
  
  401084:    e8 b1 03 00 00           callq  40143a 
  <explode_bomb>
   
  401089:    eb 47                    jmp    4010d2 
   <phase_5 0x70="">
    

# LOOP:
  40108b:    0f b6 0c 03              movzbl (%rbx,%rax,1),%ecx
  40108f:    88 0c 24                 mov    %cl,(%rsp)
  401092:    48 8b 14 24              mov    (%rsp),%rdx
  401096:    83 e2 0f                 and    $0xf,%edx
  401099:    0f b6 92 b0 24 40 00     movzbl 0x4024b0(%rdx),%edx
  4010a0:    88 54 04 10              mov    %dl,0x10(%rsp,%rax,1)
  4010a4:    48 83 c0 01              add    $0x1,%rax
  4010a8:    48 83 f8 06              cmp    $0x6,%rax
  4010ac:    75 dd                    jne    40108b 
    <phase_5 0x29="">
     

  4010ae:    c6 44 24 16 00           movb   $0x0,0x16(%rsp)
  4010b3:    be 5e 24 40 00           mov    $0x40245e,%esi
  4010b8:    48 8d 7c 24 10           lea    0x10(%rsp),%rdi
  4010bd:    e8 76 02 00 00           callq  401338 
     <strings_not_equal>
      
  4010c2:    85 c0                    test   %eax,%eax
  4010c4:    74 13                    je     4010d9 
      <phase_5 0x77="">
       
  4010c6:    e8 6f 03 00 00           callq  40143a 
       <explode_bomb>
        
  4010cb:    0f 1f 44 00 00           nopl   0x0(%rax,%rax,1)
  4010d0:    eb 07                    jmp    4010d9 
        <phase_5 0x77="">
         
  4010d2:    b8 00 00 00 00           mov    $0x0,%eax
  4010d7:    eb b2                    jmp    40108b 
         <phase_5 0x29="">
          

  4010d9:    48 8b 44 24 18           mov    0x18(%rsp),%rax
  4010de:    64 48 33 04 25 28 00     xor    %fs:0x28,%rax
  4010e5:    00 00 
  4010e7:    74 05                    je     4010ee 
          <phase_5 0x8c="">
           
  4010e9:    e8 42 fa ff ff           callq  400b30 <__stack_chk_fail@plt>
  4010ee:    48 83 c4 20              add    $0x20,%rsp
  4010f2:    5b                       pop    %rbx
  4010f3:    c3                       retq   


          </phase_5>
         </phase_5>
        </phase_5>
       </explode_bomb>
      </phase_5>
     </strings_not_equal>
    </phase_5>
   </phase_5>
  </explode_bomb>
 </phase_5>
</string_length>

代码中间有一个 LOOP 注释是我标记的,为函数的核心,其他部分比较简单就一笔带过。

前三段分配栈,canary 保护,并且要求输入的字符串长度为 6,经过循环变化后,字符串需要跟 0x40245e 位置处的字符 flyers 相等

我们把循环代码单独拎出来,此时各个寄存器的状态:

%eax=0, %rbx=%rdi(即输入的字符串的起始位置)

40108b:    0f b6 0c 03              movzbl (%rbx,%rax,1),%ecx
  40108f:    88 0c 24                 mov    %cl,(%rsp)
  401092:    48 8b 14 24              mov    (%rsp),%rdx
  401096:    83 e2 0f                 and    $0xf,%edx
  401099:    0f b6 92 b0 24 40 00     movzbl 0x4024b0(%rdx),%edx
  4010a0:    88 54 04 10              mov    %dl,0x10(%rsp,%rax,1)
  4010a4:    48 83 c0 01              add    $0x1,%rax
  4010a8:    48 83 f8 06              cmp    $0x6,%rax
  4010ac:    75 dd                    jne    40108b 
<phase_5 0x29="">

</phase_5>

由于 %rbx 存储字符串其实地址, %rax 起下标作用,因此 movzbl (%rbx,%rax,1),%ecx 的作用是将输入字符串的第 %rax 个字符放入 %ecx 中并做零扩展。

mov %cl,(%rsp); (%rsp),%rdx 取低 8 位(即一个字符)并通过内存间接放入 %rdx。

and $0xf,%edx; movzbl 0x4024b0(%rdx),%edx 将 edx 的低 4 位作为偏移量,基址为 0x4024b0 ,值重新放入 %edx 中

mov %dl,0x10(%rsp,%rax,1) 将 %edx 中的低 8 位放入 %rsp + %rax + 0x10 的位置。并在循环之后 4010b8: 0x10(%rsp),%rdi 将该内存位置保存的字符串作为参数传入 strings_not_equal 函数。

之后循环 6 次,对每个字符都做对应变换

综上, phase_5 遍历字符串,将每个字符的低 4 位作为偏移量,以 0x4024b0 为基址,获得一个新的字符串 flyers

(lldb) x/s 0x4024b0
0x004024b0: "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"

原理理解了,直接写个脚本计算

total = 'maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?'
result = 'flyers'

offset = [total.find(result[i]) for i in range(6)]

# 因为计算出来的低 4 位,ascii 英文字母的高 4 位为 1100(小写) 或 1000(大写)
out = ''.join([chr(c+64) for c in offset])

print(out)  # IONEFG (如果为 c+64+32 即为 ionefg)

phase_6

4010f4:    41 56                    push   %r14
  4010f6:    41 55                    push   %r13
  4010f8:    41 54                    push   %r12
  4010fa:    55                       push   %rbp
  4010fb:    53                       push   %rbx
  4010fc:    48 83 ec 50              sub    $0x50,%rsp

# 读取六个整数,第一个需要大于 5
  401100:    49 89 e5                 mov    %rsp,%r13
  401103:    48 89 e6                 mov    %rsp,%rsi
  401106:    e8 51 03 00 00           callq  40145c 
<read_six_numbers>
 
  40110b:    49 89 e6                 mov    %rsp,%r14
  40110e:    41 bc 00 00 00 00        mov    $0x0,%r12d

# --------------------- section 1 -----------------------

# 嵌套循环,读取的所有数字必须互异,且均小于 6
  401114:    4c 89 ed                 mov    %r13,%rbp
  401117:    41 8b 45 00              mov    0x0(%r13),%eax
  40111b:    83 e8 01                 sub    $0x1,%eax
  40111e:    83 f8 05                 cmp    $0x5,%eax
  401121:    76 05                    jbe    401128 
 <phase_6 0x34="">
  
  401123:    e8 12 03 00 00           callq  40143a 
  <explode_bomb>
   
  401128:    41 83 c4 01              add    $0x1,%r12d         # 循环变量 i
  40112c:    41 83 fc 06              cmp    $0x6,%r12d
  401130:    74 21                    je     401153 
   <phase_6 0x5f="">
    
  401132:    44 89 e3                 mov    %r12d,%ebx

  # 内嵌循环
  401135:    48 63 c3                 movslq %ebx,%rax
  401138:    8b 04 84                 mov    (%rsp,%rax,4),%eax
  40113b:    39 45 00                 cmp    %eax,0x0(%rbp)
  40113e:    75 05                    jne    401145 
    <phase_6 0x51="">
     
  401140:    e8 f5 02 00 00           callq  40143a 
     <explode_bomb>
      
  401145:    83 c3 01                 add    $0x1,%ebx          # 循环变量 j
  401148:    83 fb 05                 cmp    $0x5,%ebx
  40114b:    7e e8                    jle    401135 
      <phase_6 0x41="">
       
  # 内嵌循环结束

  40114d:    49 83 c5 04              add    $0x4,%r13
  401151:    eb c1                    jmp    401114 
       <phase_6 0x20="">
        

# --------------------- section 2 -----------------------

  401153:    48 8d 74 24 18           lea    0x18(%rsp),%rsi
  401158:    4c 89 f0                 mov    %r14,%rax        # %rsp
  40115b:    b9 07 00 00 00           mov    $0x7,%ecx

  # 循环读取 6 个数字 num,并将 7 - num 重新放回
  401160:    89 ca                    mov    %ecx,%edx
  401162:    2b 10                    sub    (%rax),%edx
  401164:    89 10                    mov    %edx,(%rax)
  401166:    48 83 c0 04              add    $0x4,%rax
  40116a:    48 39 f0                 cmp    %rsi,%rax
  40116d:    75 f1                    jne    401160 
        <phase_6 0x6c="">
         
  40116f:    be 00 00 00 00           mov    $0x0,%esi
  401174:    eb 21                    jmp    401197 
         <phase_6 0xa3="">
          


# --------------------- section 3 -----------------------

  # 内层循环,将数组中的数字作为序号顺序,把链表每个节点地址放入栈中(%rsp + 20 起始)
  401176:    48 8b 52 08              mov    0x8(%rdx),%rdx # 获得 next 指向的下一节点
  40117a:    83 c0 01                 add    $0x1,%eax      # 循环变量 j
  40117d:    39 c8                    cmp    %ecx,%eax
  40117f:    75 f5                    jne    401176 
          <phase_6 0x82="">
           

  401181:    eb 05                    jmp    401188 
           <phase_6 0x94="">
            
  401183:    ba d0 32 60 00           mov    $0x6032d0,%edx     # 结构体第一个节点的地址
  401188:    48 89 54 74 20           mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:    48 83 c6 04              add    $0x4,%rsi
  401191:    48 83 fe 18              cmp    $0x18,%rsi
  401195:    74 14                    je     4011ab 
            <phase_6 0xb7="">
             
  401197:    8b 0c 34                 mov    (%rsp,%rsi,1),%ecx  # 取得数组中的第 %esi/4(bytes) 的元素值
  40119a:    83 f9 01                 cmp    $0x1,%ecx           
  40119d:    7e e4                    jle    401183 
             <phase_6 0x8f="">
               # 值小于等于一直接入栈
  40119f:    b8 01 00 00 00           mov    $0x1,%eax     # 内层循环变量 j
  4011a4:    ba d0 32 60 00           mov    $0x6032d0,%edx
  4011a9:    eb cb                    jmp    401176 
              <phase_6 0x82="">
               

# --------------------- section 4 -----------------------

  # 对每个节点的 next 值重新赋值,反转链表
  4011ab:    48 8b 5c 24 20           mov    0x20(%rsp),%rbx 
  4011b0:    48 8d 44 24 28           lea    0x28(%rsp),%rax
  4011b5:    48 8d 74 24 50           lea    0x50(%rsp),%rsi
  4011ba:    48 89 d9                 mov    %rbx,%rcx 

  4011bd:    48 8b 10                 mov    (%rax),%rdx 
  4011c0:    48 89 51 08              mov    %rdx,0x8(%rcx) 
  4011c4:    48 83 c0 08              add    $0x8,%rax   
  4011c8:    48 39 f0                 cmp    %rsi,%rax 
  4011cb:    74 05                    je     4011d2 
               <phase_6 0xde="">
                
  4011cd:    48 89 d1                 mov    %rdx,%rcx    
  4011d0:    eb eb                    jmp    4011bd 
                <phase_6 0xc9="">
                 
  4011d2:    48 c7 42 08 00 00 00     movq   $0x0,0x8(%rdx) # 尾节点
  4011d9:    00 

# --------------------- section 5 -----------------------

# 检查链表是否以节点的 num1 值为依据从大到小排列
  4011da:    bd 05 00 00 00           mov    $0x5,%ebp # 循环变量
  4011df:    48 8b 43 08              mov    0x8(%rbx),%rax
  4011e3:    8b 00                    mov    (%rax),%eax
  4011e5:    39 03                    cmp    %eax,(%rbx)
  4011e7:    7d 05                    jge    4011ee 
                 <phase_6 0xfa="">
                  
  4011e9:    e8 4c 02 00 00           callq  40143a 
                  <explode_bomb>
                   
  4011ee:    48 8b 5b 08              mov    0x8(%rbx),%rbx
  4011f2:    83 ed 01                 sub    $0x1,%ebp
  4011f5:    75 e8                    jne    4011df 
                   <phase_6 0xeb="">
                    


  4011f7:    48 83 c4 50              add    $0x50,%rsp
  4011fb:    5b                       pop    %rbx
  4011fc:    5d                       pop    %rbp
  4011fd:    41 5c                    pop    %r12
  4011ff:    41 5d                    pop    %r13
  401201:    41 5e                    pop    %r14
  401203:    c3                       retq   

                   </phase_6>
                  </explode_bomb>
                 </phase_6>
                </phase_6>
               </phase_6>
              </phase_6>
             </phase_6>
            </phase_6>
           </phase_6>
          </phase_6>
         </phase_6>
        </phase_6>
       </phase_6>
      </phase_6>
     </explode_bomb>
    </phase_6>
   </phase_6>
  </explode_bomb>
 </phase_6>
</read_six_numbers>

phase_6 很长,需要一定(很多很多)的耐心。我将该部分分成了 6 个 section,各个 section 都有相应功能注释。

难点主要在于 section 3 与 4,再简单提一下。

(lldb) x/24wx 0x6032d0
0x006032d0: 0x0000014c 0x00000001 0x006032e0 0x00000000
0x006032e0: 0x000000a8 0x00000002 0x006032f0 0x00000000
0x006032f0: 0x0000039c 0x00000003 0x00603300 0x00000000
0x00603300: 0x000002b3 0x00000004 0x00603310 0x00000000
0x00603310: 0x000001dd 0x00000005 0x00603320 0x00000000
0x00603320: 0x000001bb 0x00000006 0x00000000 0x00000000

通过查看 401183: mov $0x6032d0,%edx 提到的 0x6032d0 处的值,可以发现每行第四列值均等于下一行第一列的地址。因此可以猜出此处应为一个链表。结构体应如下:

struct Node {
    int num;    // %rdx
    int num2;   // %rdx + 4
    Node *next; // %rex + 8
}

弄懂这个要点之后再看 3 与 4 应该就比较好懂了。

最后在 section 5 中需要链表根据节点的 num1 从大到小排列,因此 section4 中用于作为序号的数组就是 3 4 5 6 1 2 ,由于 section 2 中求了对 7 的补数,因此输入就是 4 3 2 1 6 5

该函数通过 ida 反编译出来也有 90 多行,且命名也难懂,就不贴了。

CSAPP BOMB Lab


以上所述就是小编给大家介绍的《CSAPP BOMB Lab》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Charlotte's Web

Charlotte's Web

E. B. White / Puffin Classics / 2010-6-3 / GBP 6.99

This is the story of a little girl named Fern who loved a little pig named Wilbur and of Wilbur's dear friend, Charlotte A. Cavatica, a beautiful large grey spider. With the unlikely help of Templeton......一起来看看 《Charlotte's Web》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具