鹏城杯2023 Reverse Writeup

鹏城杯2023初赛 re WP

一. 安全编程

  • rust逆向,直接动调

  • 定位关键函数sub_7FD043E88C70

  • 下断点跟进

  • 观察控制台

  • guess number
    plz input 1-10 number

  • 这时我们随便输入一个数,往下跟进

  • .text:00007F14B3684E9B
    .text:00007F14B3684E9B loc_7F14B3684E9B:
    .text:00007F14B3684E9B cmp     [rsp+0D8h+var_88], eax
    .text:00007F14B3684E9F jnz     loc_7F14B3684F63
    
  • 将输入的数与程序随机生成的数进行比较,从而跳转

  • .text:00007F14B3684EA5 inc     [rsp+0D8h+var_84]
    .text:00007F14B3684EA9 lea     rax, [rsp+0D8h+var_84]
    .text:00007F14B3684EAE mov     [rsp+0D8h+var_A0], rax
    .text:00007F14B3684EB3 lea     rax, sub_7F14B36D13F0
    .text:00007F14B3684EBA mov     [rsp+0D8h+var_98], rax
    .text:00007F14B3684EBF lea     rax, unk_7F14B36E6F08
    .text:00007F14B3684EC6 mov     [rsp+0D8h+var_C0], rax
    .text:00007F14B3684ECB mov     [rsp+0D8h+var_B8], 2
    .text:00007F14B3684ED4 mov     [rsp+0D8h+var_D0], 0
    .text:00007F14B3684EDD lea     rax, [rsp+0D8h+var_A0]
    .text:00007F14B3684EE2 mov     [rsp+0D8h+var_B0], rax
    .text:00007F14B3684EE7 mov     [rsp+0D8h+var_A8], 1
    .text:00007F14B3684EF0 mov     rdi, r14
    .text:00007F14B3684EF3 call    r13 ; sub_7F14B369D660
    .text:00007F14B3684EF6 cmp     [rsp+0D8h+var_84], 64h ; 'd'
    .text:00007F14B3684EFB jz      loc_7F14B368500E
    
  • 如果比较结果相同就跳到上述分支,注意到inc这一关键计数

  • 再看cmp [rsp+0D8h+var_84], 64h ; 'd',这一比较再次决定跳转

  • shift+E查看数据发现关键字符串:恭喜你获得flag,就在下面这段中

  • .text:00007F14B368500E
    .text:00007F14B368500E loc_7F14B368500E:
    .text:00007F14B368500E lea     rax, unk_7F14B36E6F28
    .text:00007F14B3685015 mov     [rsp+0D8h+var_C0], rax
    .text:00007F14B368501A mov     [rsp+0D8h+var_B8], 1
    .text:00007F14B3685023 mov     [rsp+0D8h+var_D0], 0
    .text:00007F14B368502C mov     [rsp+0D8h+var_B0], rbx
    .text:00007F14B3685031 mov     [rsp+0D8h+var_A8], 0
    .text:00007F14B368503A lea     rdi, [rsp+0D8h+var_D0]
    .text:00007F14B368503F call    cs:qword_7F14B36E9FA8
    .text:00007F14B3685045 lea     rdi, [rsp+0D8h+var_D0]
    .text:00007F14B368504A call    cs:qword_7F14B36E9C18
    .text:00007F14B3685050 lea     rdi, [rsp+0D8h+var_D0]
    .text:00007F14B3685055 mov     esi, 1
    .text:00007F14B368505A call    cs:qword_7F14B36E9E80
    .text:00007F14B3685060 lea     rdx, unk_7F14B36D2080
    .text:00007F14B3685067 lea     rdi, [rsp+0D8h+var_A0]
    .text:00007F14B368506C mov     ecx, 0Dh
    .text:00007F14B3685071 mov     rsi, rax
    .text:00007F14B3685074 call    cs:qword_7F14B36E9D50
    .text:00007F14B368507A cmp     dword ptr [rsp+0D8h+var_A0], 0
    .text:00007F14B368507F jnz     loc_7F14B3685275
    
  • 那我们就明白了,直接将64hpatch为01h,这样只需要一次正确即可找到flag

  • 接着动调结束,让程序执行完,就会发现程序生成一个img.png,即为flag

  • flag{d846b8394630f42e02fef698a4e3df1b}

二. bad_pe

  • DIE查壳,没啥问题

  • 拖进IDA看看

  • __int64 start()
    {
      unsigned __int64 v0; // rax
      HMODULE ModuleHandleA; // rax
      char *v2; // rdx
      int v3; // ecx
      char *v4; // r10
      __int64 v5; // r11
      char *v6; // r8
      char *v7; // rdx
      char i; // r9
      char *v9; // rcx
      void (*v10)(void); // r9
      unsigned __int64 v11; // rax
      char v13[14]; // [rsp+2Ah] [rbp-Eh] BYREF
    
      v0 = __rdtsc();
      dword_418004 = HIDWORD(v0);
      ModuleHandleA = GetModuleHandleA(0i64);
      strcpy(v13, ".ATOM");
      v2 = (char *)ModuleHandleA + *((int *)ModuleHandleA + 15);
      v3 = *((unsigned __int16 *)v2 + 3);
      if ( (_WORD)v3 )
      {
        v4 = v2 + 264;
        v5 = (__int64)&v2[40 * (v3 - 1) + 304];
        while ( *v4 != 46 )
        {
    LABEL_18:
          v4 += 40;
          if ( v4 == (char *)v5 )
            return 0i64;
        }
        v6 = v13;
        v7 = v4;
        for ( i = 65; ; i = v6[1] )
        {
          ++v7;
          ++v6;
          if ( *v7 != i )
            break;
          if ( !i )
            goto LABEL_10;
        }
        if ( *v7 || i )
          goto LABEL_18;
    LABEL_10:
        v9 = (char *)ModuleHandleA + *((unsigned int *)v4 + 3);
        if ( *((_DWORD *)v4 + 2) )//0xdd12
        {
          v7 = 0i64;
          do
            (v7++)[(_QWORD)v9] ^= 0x23u;
          while ( *((_DWORD *)v4 + 2) > (unsigned int)v7 );
        }
        else if ( !v9 )
        {
          return 0i64;
        }
        v10 = (void (*)(void))sub_414140(v9, v7, v6);
        v11 = __rdtsc();
        dword_418000 = HIDWORD(v11);
        if ( (unsigned int)(HIDWORD(v11) - dword_418004) <= 1 )
          v10();
      }
      return 0i64;
    }
    
  • 想动调解密,但发现PE文件格式魔改掉了

  • 放进010看看,发现一堆0x23

  • 写脚本去除:

  • arr = 0x23
    with open('C:\\Users\\lenovo\\Desktop\\bad_pe.exe', 'rb') as f:
        b = f.read()
    b = bytearray(b)
    for i in range(len(b)):
        b[i]^=0x23
    with open('C:\\Users\\lenovo\\Desktop\\COD_de1', 'wb') as f:
        f.write(b)
    
  • 发现在2e00处开始是一个新的PE文件,dump出来

  • data = open('C:\\Users\\lenovo\\Desktop\\COD_de1', 'rb').read()[0x2e00: 0x2e00 + 0xdd12]
    data = bytes(i for i in data)
    open('C:\\Users\\lenovo\\Desktop\\COD_de2', 'wb').write(data)
    
  • 将新文件拖入IDA,成功找到main函数

  • int __cdecl main(int argc, const char **argv, const char **envp)
    {
      __int128 *v3; // rdi
      int v4; // edx
      unsigned int v5; // eax
      signed __int64 v6; // rdi
      void *v7; // rsp
      void *v8; // rsp
      char *v9; // rax
      char *v10; // rdx
      char v11; // r8
      char v13[8]; // [rsp+30h] [rbp-B0h] BYREF
      __int64 v14; // [rsp+38h] [rbp-A8h] BYREF
      __int128 v15[2]; // [rsp+40h] [rbp-A0h] BYREF
      __int16 v16[8]; // [rsp+60h] [rbp-80h] BYREF
      char v17[112]; // [rsp+70h] [rbp-70h] BYREF
    
      _main(argc, argv, envp);
      v3 = v15;
      v15[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405130);
      v14 = 0x2179336B336874i64;
      v15[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405140);
      qmemcpy(v16, ".~c", 3);
      do
      {
        v4 = *(_DWORD *)v3;
        v3 = (__int128 *)((char *)v3 + 4);
        v5 = ~v4 & (v4 - 16843009) & 0x80808080;
      }
      while ( !v5 );
      if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
        v5 >>= 16;
      if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
        v3 = (__int128 *)((char *)v3 + 2);
      v6 = (char *)v3 - __CFADD__((_BYTE)v5, (_BYTE)v5) - 3 - (char *)v15;
      v7 = alloca(v6);
      v8 = alloca(v6);
      printf("please input your flag:");
      putchar(10);
      scanf("%s", v17);
      rc4_crypt((unsigned int)v17, v6, (unsigned int)&v14, 7, (__int64)v13);
      if ( v6 )
      {
        if ( v13[0] != -67 )
        {
    LABEL_14:
          printf("wrong!");
          return 0;
        }
        v9 = v13;
        v10 = (char *)v15 + 1;
        while ( &v13[(unsigned int)(v6 - 1)] != v9 )
        {
          v11 = v9[1];
          ++v10;
          ++v9;
          if ( v11 != *(v10 - 1) )
            goto LABEL_14;
        }
      }
      printf("successful!!");
      return 0;
    }
    
  • 注意到RC4加密函数

  • char *__fastcall rc4_crypt(__int64 a1, __int64 a2, __int64 a3, int a4, __int64 a5)
    {
      __int64 v5; // r12
      int v6; // r10d
      __int128 *v7; // r11
      int v8; // eax
      char v9; // bl
      char *result; // rax
      __int64 v11; // rbx
      __int64 v12; // r11
      __int64 v13; // rdi
      char v14; // al
      char v15; // r10
      __int128 v16[18]; // [rsp+0h] [rbp-128h] BYREF
    
      LOBYTE(v5) = 0;
      v6 = 0;
      v16[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405030);
      v7 = v16;
      v16[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405040);
      v16[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405050);
      v16[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405060);
      v16[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405070);
      v16[5] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405080);
      v16[6] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405090);
      v16[7] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4050A0);
      v16[8] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4050B0);
      v16[9] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4050C0);
      v16[10] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4050D0);
      v16[11] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4050E0);
      v16[12] = (__int128)_mm_load_si128((const __m128i *)&xmmword_4050F0);
      v16[13] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405100);
      v16[14] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405110);
      v16[15] = (__int128)_mm_load_si128((const __m128i *)&xmmword_405120);
      do
      {
        v8 = v6;
        v9 = *(_BYTE *)v7;
        ++v6;
        v7 = (__int128 *)((char *)v7 + 1);
        v5 = (unsigned __int8)(v5 + v9 + *(_BYTE *)(a3 + v8 % a4));
        result = (char *)v16 + v5;
        *((_BYTE *)v7 - 1) = *((_BYTE *)v16 + v5);
        *((_BYTE *)v16 + v5) = v9;
      }
      while ( v6 != 256 );
      if ( (int)a2 > 0 )
      {
        v11 = (unsigned int)(a2 - 1);
        v12 = 0i64;
        LOBYTE(v13) = 0;
        LOBYTE(a2) = 0;
        while ( 1 )
        {
          v14 = *((_BYTE *)v16 + (unsigned __int8)(a2 + 1));
          a2 = (unsigned __int8)(a2 + 1);
          v15 = *((_BYTE *)v16 + (unsigned __int8)(v14 + v13));
          v13 = (unsigned __int8)(v14 + v13);
          *((_BYTE *)v16 + a2) = v15;
          *((_BYTE *)v16 + v13) = v14;
          *(_BYTE *)(a5 + v12) = *(_BYTE *)(a1 + v12) ^ *((_BYTE *)v16 + (unsigned __int8)(*((_BYTE *)v16 + a2) + v14));
          result = (char *)(v12 + 1);
          if ( v12 == v11 )
            break;
          ++v12;
        }
      }
      return result;
    }
    
  • 找到keyv14 = '!y3k3ht';,再动调找密文

  • 0xBD, 0xF0, 0x4C, 0xD9, 0xD0, 0x29, 0xF2, 0x46, 0x08, 0xCC, 
    0xC8, 0x9F, 0xBE, 0x4B, 0xEF, 0x67, 0x46, 0x04, 0xE6, 0x32, 
    0xF3, 0xF6, 0xAA, 0xF0, 0xD1, 0xD8, 0xEC, 0x75, 0x49, 0x2F, 
    0xCC, 0x26, 0x2E, 0x7E, 0x63
    
  • 套脚本解密即可

  • def KSA(key):
        key_length = len(key)
        S = list(range(256))
        j = 0
        for i in range(256):
            j = (j + S[i] + key[i % key_length]) % 256
            S[i], S[j] = S[j], S[i]
        return S
    
    def PRGA(S):
        i = 0
        j = 0
        while True:
            i = (i + 1) % 256
            j = (j + S[i]) % 256
            S[i], S[j] = S[j], S[i]
            K = S[(S[i] + S[j]) % 256]
            yield K
            
    def RC4(key):
        S = KSA(key)
        keystream = PRGA(S)
        return keystream
    
    
    if __name__ == '__main__':
        key = 'th3k3y!'
        plaintext = [
            0xBD, 0xF0, 0x4C, 0xD9, 0xD0, 0x29, 0xF2, 0x46,
            0x08, 0xCC, 0xC8, 0x9F, 0xBE, 0x4B, 0xEF, 0x67, 
            0x46, 0x04, 0xE6, 0x32, 0xF3, 0xF6, 0xAA, 0xF0, 
            0xD1, 0xD8, 0xEC, 0x75, 0x49, 0x2F, 0xCC, 0x26, 
            0x2E, 0x7E, 0x63
        ]
        key = key.encode()
        keystream = RC4(key)
    
        ciphertext = []
        for b in plaintext:
            ciphertext.append(chr(b ^ next(keystream)))
        print("".join(ciphertext))
    
  • flag{th3_p3fi15_1s_v3ry_nicccccc!}

三. babyre

  • 定位关键函数

  • __int64 sub_140011F90()
    {
      size_t v1; // [rsp+28h] [rbp+8h]
      int i; // [rsp+44h] [rbp+24h]
    
      sub_14001138E(&unk_140022066);
      sub_1400111A4("plz input flag:\n");
      sub_14001120D(&unk_14001ADD0, Buf1, 49i64);
      v1 = j_strlen(Buf1);
      if ( v1 == 48 )
      {
        for ( i = 0; i < v1 / 4; i += 3 )
          sub_14001107D(&Buf1[4 * i], v1 % 4);
        if ( !j_memcmp(Buf1, &unk_14001D000, 0x30ui64) )
          sub_1400111A4("success");
        else
          sub_1400111A4("fail");
        return 0i64;
      }
      else
      {
        sub_1400111A4("fail");
        return 0i64;
      }
    }
    
  • 看着逻辑很简单,就只有一个加密函数

  • __int64 __fastcall sub_140011870(int *a1)
    {
      char *v1; // rdi
      __int64 i; // rcx
      char v4[32]; // [rsp+0h] [rbp-20h] BYREF
      char v5; // [rsp+20h] [rbp+0h] BYREF
      unsigned int v6; // [rsp+24h] [rbp+4h]
      unsigned int v7; // [rsp+44h] [rbp+24h]
      unsigned int v8; // [rsp+64h] [rbp+44h]
      int j; // [rsp+84h] [rbp+64h]
      int v10; // [rsp+A8h] [rbp+88h]
      int v11; // [rsp+ACh] [rbp+8Ch]
      int v12; // [rsp+B0h] [rbp+90h]
      int v13; // [rsp+B4h] [rbp+94h]
      int v14; // [rsp+D8h] [rbp+B8h]
      int v15; // [rsp+DCh] [rbp+BCh]
      int v16; // [rsp+E0h] [rbp+C0h]
      int v17; // [rsp+E4h] [rbp+C4h]
      int v18; // [rsp+108h] [rbp+E8h]
      int v19; // [rsp+10Ch] [rbp+ECh]
      int v20; // [rsp+110h] [rbp+F0h]
      int v21; // [rsp+114h] [rbp+F4h]
      int k; // [rsp+134h] [rbp+114h]
      unsigned int v23; // [rsp+204h] [rbp+1E4h]
      unsigned int v24; // [rsp+208h] [rbp+1E8h]
      unsigned int v25; // [rsp+20Ch] [rbp+1ECh]
    
      v1 = &v5;
      for ( i = 78i64; i; --i )
      {
        *(_DWORD *)v1 = -858993460;
        v1 += 4;
      }
      sub_14001138E(&unk_140022066);
      v6 = *a1;
      v7 = a1[1];
      v8 = a1[2];
      srand(0xDEADC0DE);
      for ( j = 0; j < 32; ++j )
      {
        v10 = (unsigned __int8)v6;
        v11 = BYTE1(v6);
        v12 = BYTE2(v6);
        v13 = HIBYTE(v6);
        v14 = (unsigned __int8)v7;
        v15 = BYTE1(v7);
        v16 = BYTE2(v7);
        v17 = HIBYTE(v7);
        v18 = (unsigned __int8)v8;
        v19 = BYTE1(v8);
        v20 = BYTE2(v8);
        v21 = HIBYTE(v8);
        for ( k = 0; k < 4; ++k )
        {//相当于23*x+66
          *(&v10 + k) = (unsigned __int8)(23 * *((_BYTE *)&v10 + 4 * k) + 66);
          *(&v14 + k) = (unsigned __int8)(23 * *((_BYTE *)&v14 + 4 * k) + 66);
          *(&v18 + k) = (unsigned __int8)(23 * *((_BYTE *)&v18 + 4 * k) + 66);
        }//对应汇编代码:.text:00007FF6825219F6 movsxd  rax, [rbp+200h+var_EC]
    //.text:00007FF6825219FD imul    eax, [rbp+rax*4+200h+var_178], 17h
    //.text:00007FF682521A05 add     eax, 42h ; 'B'
    //.text:00007FF682521A08 and     eax, 0FFh
    //.text:00007FF682521A0D movsxd  rcx, [rbp+200h+var_EC]
    //.text:00007FF682521A14 mov     [rbp+rcx*4+200h+var_178], eax
        v6 = (v13 << 24) | (v12 << 16) | (v11 << 8) | v10;//合并
        v7 = (v17 << 24) | (v16 << 16) | (v15 << 8) | v14;
        v8 = (v21 << 24) | (v20 << 16) | (v19 << 8) | v18;
        v23 = v7 >> 7;//类似于tea
        v24 = rand() + v23;
        v25 = (v7 >> 15) ^ (v7 << 10) | 3;
        v6 += v24 + (rand() ^ v25);
        v23 = v8 >> 7;
        v24 = rand() + v23;
        v25 = (v8 >> 15) ^ (v8 << 10) | 3;
        v7 += v24 + (rand() ^ v25);
        v23 = v6 >> 7;
        v24 = rand() + v23;
        v25 = (v6 >> 15) ^ (v6 << 10) | 3;
        v8 += v24 + (rand() ^ v25);
      }
      *a1 = v6;
      a1[1] = v7;
      a1[2] = v8;
      return sub_14001132A(v4, &unk_14001ACC8);
    }
    
  • 关键是将这个算法逆了

  • 其中有很多rand,seed种子是固定的0xDEADC0DE所以每次rand生成的值我们都知道

  • //注:一些定义
    typedef unsigned char   uint8;
    #define _BYTE  uint8
    #define _WORD  uint16
    #define LOBYTE(w)           ((BYTE)(((DWORD_PTR)(w)) & 0xff))
    #define HIBYTE(w)           ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
    #define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
    #define WORDn(x, n)   (*((_WORD*)&(x)+n))
    #define BYTE0(x)   BYTEn(x,  0)         // byte 0 (counting from 0)  添加此宏定义
    #define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
    #define BYTE2(x)   BYTEn(x,  2)
    #define BYTE3(x)   BYTEn(x,  3)
    #define BYTE4(x)   BYTEn(x,  4)
    typedef unsigned long DWORD_PTR;
    
    
  • 注意:逆的时候记得求一下逆元:

  • print(inverse(23,256))  #167
    
  • 先把加密函数模拟出来,然后就更方便的编写解密函数

  • 注意unsigned,和IDA提取保持一只即可

  • #include <stdio.h>
    #include <stdlib.h>
    unsigned int my_rand[32][6]={0};
    void encrypt(char* data,int* data2)
    {
        int my_rand[6]={0};
        srand(0xDEADC0DE);
        for(int i=0;i<32;i++)
        {
            for(int j=0;j<12;j++)
            {
                data[j]=data[j]*23+66;
            }
            for(int z=0;z<3;z++)
            {
                data2[z]=(data[4*z+3]<<24)|(data[4*z+2]<<16)|(data[4*z+1]<<8)|data[4*z];
            }
            for(int k=0;k<6;k++)
            {
                my_rand[k]=rand();
            }
        int v23=data2[1]>>7;
        int v24=my_rand[0]+v23;
        int v25=(data2[1]>>15)^(data2[1]<<10)|3;
        data2[0]+=v24+(my_rand[1]^v25);
    
        v23=data2[2]>>7;
        v24=my_rand[2]+v23;
        v25=(data2[2]>>15)^(data2[2]<<10)|3;
        data2[1]+=v24+(my_rand[3]^v25);
    
        v23=data2[0]>>7;
        v24=my_rand[4]+v23;
        v25=(data2[0]>>15)^(data2[0]<<10)|3;
        data2[2]+=v24+(my_rand[5]^v25);
        }
        for(int z=0;z<3;z++)
        {
            data[4*z]=(char)(data2[z]&0xff);
            data[4*z+1]=(char)((data2[z]>>8)&0xff);
            data[4*z+2]=(char)((data2[z]>>16)&0xff);
            data[4*z+3]=(char)((data2[z]>>24)&0xff);
        }
    }
    void decrypt(unsigned char* data,unsigned int* data2)
    {
        srand(0xDEADC0DE);
        for(int i=0;i<32;i++)
        {
            for(int j=0;j<6;j++)
            {
                my_rand[i][j]=rand();
            }
        }
        for(int i=31;i>=0;i--)
        {
            unsigned int v23=data2[0]>>7;
            unsigned int v24=my_rand[i][4]+v23;
            unsigned int v25=(data2[0]>>15)^(data2[0]<<10)|3;
            data2[2]-=v24+(my_rand[i][5]^v25);
    
            v23=data2[2]>>7;
            v24=my_rand[i][2]+v23;
            v25=(data2[2]>>15)^(data2[2]<<10)|3;
            data2[1]-=v24+(my_rand[i][3]^v25);
    
            v23=data2[1]>>7;
            v24=my_rand[i][0]+v23;
            v25=(data2[1]>>15)^(data2[1]<<10)|3;
            data2[0]-=v24+(my_rand[i][1]^v25);
            for(int z=0;z<3;z++)
            {
                data[4*z]=(unsigned char)(data2[z]&0xff);
                data[4*z+1]=(unsigned char)((data2[z]>>8)&0xff);
                data[4*z+2]=(unsigned char)((data2[z]>>16)&0xff);
                data[4*z+3]=(unsigned char)((data2[z]>>24)&0xff);
            }
            for(int j=0;j<12;j++)
            {
                data[j]=167*(data[j]-66 & 0xff);
            }
            for(int z=0;z<3;z++)
            {
                data2[z]=(data[4*z+3]<<24)|(data[4*z+2]<<16)|(data[4*z+1]<<8)|data[4*z];
            }
        }
    }
    
    int main() {
        unsigned char data[] =
        {
            0x48, 0x4D, 0x3B, 0xA0, 0x27, 0x31, 0x28, 0x54,
            0x6D, 0xF1, 0x21, 0x35, 0x18, 0x73, 0x6A, 0x4C,
            0x71, 0x3B, 0xBD, 0x98, 0xB6, 0x5A, 0x77, 0x2D,
            0x0B, 0x2B, 0xCB, 0x9B, 0xE4, 0x8A, 0x4C, 0xA9,
            0x5C, 0x4F, 0x1B, 0xF1, 0x98, 0x3D, 0x30, 0x59,
            0x3F, 0x14, 0xFC, 0x7A, 0xF4, 0x64, 0x02, 0x2B
        };
        unsigned int data2[]={0xA03B4D48, 0x54283127, 0x3521F16D, 0x4C6A7318, 0x98BD3B71, 0x2D775AB6, 0x9BCB2B0B, 0xA94C8AE4, 0xF11B4F5C, 0x59303D98, 0x7AFC143F, 0x2B0264F4};
        decrypt((unsigned char*)data,(unsigned int*)data2);
        decrypt((unsigned char*)data+12,(unsigned int*)data2+3);
        decrypt((unsigned char*)data+24,(unsigned int*)data2+6);
        decrypt((unsigned char*)data+36,(unsigned int*)data2+9);
        puts(data);
        return 0;
    }
    
    
  • 这里脚本我用了两个数组,好像一个就可以hhh

  • 运行得到:flag{1CpOVOIeB1d2FcYUvnN1k5PbfMzMNzUzUgV6mB7hXF}

  • 评价:个人脚本能力依托答辩www

四. StateMachine

  • 看到init函数里面的src和四个看着像密钥的东西,其实可以先猜一下是tea,但是没有delta(十分逆向七分猜(bushi))

  • __int64 __fastcall main(int a1, char **a2, char **a3)
    {
      puts("Welcome! Drill Down.");
      sub_21D8("Welcome! Drill Down.", a2);
      sub_2407();
      putchar(10);
      return 0LL;
    }
    
    
    unsigned __int64 sub_21D8()  //init
    {
      int i; // [rsp+4h] [rbp-43Ch]
      __int64 src[4]; // [rsp+10h] [rbp-430h] BYREF
      char v3[1024]; // [rsp+30h] [rbp-410h] BYREF
      unsigned __int64 v4; // [rsp+438h] [rbp-8h]
    
      v4 = __readfsqword(0x28u);
      for ( i = 0; i <= 9; ++i )
        byte_5104[8 * i] = 1;
      byte_5154 = 1;
      byte_5558 = 1;
      byte_5621 = 1;
      qmemcpy(v3, &unk_3020, 0x157uLL);
      memset(&v3[343], 0, 681);
      qmemcpy(&unk_5158, v3, 0x400uLL);
      memset(&byte_5559[40], 0, 0x2CuLL);
      byte_5559[40] = 119;
      byte_5559[41] = 105;
      byte_5559[42] = 110;
      byte_5559[43] = 33;
      byte_5559[44] = 102;
      byte_5559[45] = 97;
      byte_5559[46] = 105;
      byte_5559[47] = 108;  //win!fail
      byte_5559[24] = 17;
      byte_5559[28] = 34;
      byte_5559[32] = -120;
      byte_5559[36] = -1;
      src[0] = 0x3A84F4140FB6B1B8LL;
      src[1] = 0xB485900290CE01CBLL;
      src[2] = 0x2D7458B7EA807F7CLL;
      src[3] = 0LL;
      memcpy(&byte_5559[88], src, 0x18uLL);
      return v4 - __readfsqword(0x28u);
    }
    
    int sub_2407()
    {
      int i; // [rsp+8h] [rbp-8h]
      int j; // [rsp+Ch] [rbp-4h]
    
      for ( i = 0; i <= 9; ++i )
        pthread_create(&qword_5080[i], 0LL, start_routine, (char *)&unk_5020 + 4 * i);//根据地址,确定thread[0-9]
      pthread_create(&th, 0LL, sub_1C41, 0LL);//th=thread[10]
      pthread_create(&qword_50D8, 0LL, sub_1EFF, 0LL);//50D8=thread[11]
      pthread_create(&qword_50E0, 0LL, sub_1F91, 0LL);//50E0=thread[12]
      for ( j = 0; j <= 9; ++j )
        pthread_join(qword_5080[j], 0LL);
      pthread_join(th, 0LL);
      pthread_join(qword_50D8, 0LL);
      return pthread_join(qword_50E0, 0LL);
    }
    
  • void __fastcall __noreturn start_routine(int *a1)
    {
      int v1; // eax
      int i; // [rsp+18h] [rbp-18h]
      int v3; // [rsp+1Ch] [rbp-14h]
      int v4; // [rsp+20h] [rbp-10h]
      int v5; // [rsp+24h] [rbp-Ch]
      int v6; // [rsp+28h] [rbp-8h]
      int v7; // [rsp+2Ch] [rbp-4h]
    
      v3 = *a1;
      for ( i = 1; i <= (int)&unk_F423F; ++i )
      {
        *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329);
        while ( !byte_5154[1316 * i - 1316] )
          ;
        while ( !byte_5558[1316 * i - 1316] )
          ;
        v4 = sub_1249((unsigned int)(i - 1), *((unsigned int *)&unk_5150 + 329 * i - 329));
        if ( v4 != 29 || v3 )
        {
          if ( v4 == 31 )
            break;
          if ( v3 == (unsigned int)sub_1321(
                                     (unsigned int)(i - 1),
                                     (unsigned int)(*((_DWORD *)&unk_5150 + 329 * i - 329) + 5)) )
          {
            if ( (v4 & 0x18) != 0 )
            {
              if ( (v4 & 0x18) == 8 )
              {
                v6 = sub_13F9((unsigned int)(i - 1), (unsigned int)(*((_DWORD *)&unk_5150 + 329 * i - 329) + 9));
                switch ( v4 & 7 )
                {
                  case 0:
                    *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = v6 + *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329);
                    break;
                  case 1:
                    *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329) - v6;
                    break;
                  case 2:
                    *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = v6;
                    break;
                  case 3:
                    *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329) << v6;
                    break;
                  case 4:
                    *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329) >> v6;
                    break;
                  default:
                    break;
                }
              }
              else if ( v4 == 16 )
              {
                v5 = sub_1321((unsigned int)(i - 1), (unsigned int)(*((_DWORD *)&unk_5150 + 329 * i - 329) + 9));
                do
                {
                  while ( !byte_5104[1316 * i - 1316 + 8 * v5] )
                    ;
                }
                while ( !byte_5621[1316 * i - 1316] );
                *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = (unsigned __int8)byte_5559[1316 * i
                                                                                     - 1316
                                                                                     + *((unsigned int *)&unk_5100
                                                                                       + 329 * i
                                                                                       + 2 * v5
                                                                                       - 329)];
              }
            }
            else
            {
              v7 = sub_1321((unsigned int)(i - 1), (unsigned int)(*((_DWORD *)&unk_5150 + 329 * i - 329) + 9));
              while ( !byte_5104[1316 * i - 1316 + 8 * v7] )
                ;
              v1 = v4 & 7;
              if ( v1 == 3 )
              {
                *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v7 - 329) ^ *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329);
              }
              else if ( (v4 & 7u) <= 3 )
              {
                if ( v1 == 2 )
                {
                  *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v7 - 329);
                }
                else if ( (v4 & 7) != 0 )
                {
                  *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329)
                                                            - *((_DWORD *)&unk_5100 + 329 * i + 2 * v7 - 329);
                }
                else
                {
                  *((_DWORD *)&unk_5100 + 329 * i + 2 * v3) = *((_DWORD *)&unk_5100 + 329 * i + 2 * v3 - 329)
                                                            + *((_DWORD *)&unk_5100 + 329 * i + 2 * v7 - 329);
                }
              }
            }
          }
        }
        else
        {
          *((_DWORD *)&unk_5100 + 329 * i) = getchar();
        }
        byte_5104[1316 * i + 8 * v3] = 1;
      }
      pthread_exit(0LL);
    }
    
  • void __fastcall __noreturn sub_1C41(void *a1)
    {
      int i; // [rsp+4h] [rbp-Ch]
      int v2; // [rsp+8h] [rbp-8h]
      int v3; // [rsp+Ch] [rbp-4h]
    
      for ( i = 1; i <= &unk_1869F; ++i )
      {
        *(&unk_5150 + 329 * i) = *(&unk_5150 + 329 * i - 329);
        while ( !byte_5558[1316 * i - 1316] )
          ;
        v2 = sub_1249((i - 1), *(&unk_5150 + 329 * i - 329));
        if ( (v2 & 0x18) != 0 && (v2 & 0x18) != 16 )
        {
          if ( (v2 & 0x18) == 24 )
          {
            *(&unk_5150 + 329 * i) = *(&unk_5150 + 329 * i - 329) + 5;
            if ( v2 == 28 )
            {
              while ( !*(&byte_5104 + 1316 * i - 1316) )
                ;
              putchar(*(&unk_5100 + 329 * i - 329));
            }
            if ( v2 == 31 )
              break;
          }
          else if ( (v2 & 0x18) == 8 )
          {
            *(&unk_5150 + 329 * i) = *(&unk_5150 + 329 * i - 329) + 25;
            if ( v2 == 15 )
            {
              v3 = sub_1321((i - 1), (*(&unk_5150 + 329 * i - 329) + 5));
              while ( !*(&byte_5104 + 1316 * i + 8 * v3 - 1316) )
                ;
              if ( *(&unk_5100 + 329 * i + 2 * v3 - 329) )
                *(&unk_5150 + 329 * i) = sub_13F9((i - 1), (*(&unk_5150 + 329 * i - 329) + 9));
            }
          }
        }
        else
        {
          *(&unk_5150 + 329 * i) = *(&unk_5150 + 329 * i - 329) + 13;
        }
        byte_5154[1316 * i] = 1;
      }
      pthread_exit(0LL);
    }
    
    
    
  • void __fastcall __noreturn sub_1EFF(void *a1)
    {
      int i; // [rsp+Ch] [rbp-4h]
    
      for ( i = 1; i <= &unk_1869F; ++i )
      {
        memcpy(&unk_5100 + 1316 * i + 88, &unk_5100 + 1316 * i - 1228, 0x400uLL);
        byte_5558[1316 * i] = 1;
      }
      pthread_exit(0LL);
    }
    
  • void __fastcall __noreturn sub_1F91(void *a1)
    {
      int i; // [rsp+0h] [rbp-10h]
      int v2; // [rsp+4h] [rbp-Ch]
      int v3; // [rsp+8h] [rbp-8h]
      int v4; // [rsp+Ch] [rbp-4h]
    
      for ( i = 1; i <= &unk_1869F; ++i )
      {
        memcpy(&unk_5100 + 1316 * i + 1113, &unk_5100 + 1316 * i - 203, 0xC8uLL);
        while ( !byte_5154[1316 * i - 1316] )
          ;
        while ( !byte_5558[1316 * i - 1316] )
          ;
        v2 = sub_1249(i - 1, *(&unk_5150 + 329 * i - 329));
        if ( v2 == 17 )
        {
          v3 = sub_1321((i - 1), (*(&unk_5150 + 329 * i - 329) + 5));
          v4 = sub_1321((i - 1), (*(&unk_5150 + 329 * i - 329) + 9));
          do
          {
            while ( !byte_5104[1316 * i - 1316 + 8 * v3] )
              ;
          }
          while ( !byte_5104[1316 * i - 1316 + 8 * v4] );
          byte_5559[1316 * i + *(&unk_5100 + 329 * i + 2 * v4 - 329)] = *(&unk_5100 + 329 * i + 2 * v3 - 329);
        }
        else if ( v2 == 31 )
        {
          break;
        }
        byte_5621[1316 * i] = 1;
      }
      pthread_exit(0LL);
    }
    
  • __int64 __fastcall sub_1249(int a1, unsigned int a2)
    {
      unsigned int v3; // [rsp+Ch] [rbp-Ch]
      unsigned int v4; // [rsp+10h] [rbp-8h]
    
      v3 = a2 >> 3;
      v4 = a2 & 7;
      if ( v4 > 3 )
        return (*(&unk_5158 + 1316 * a1 + v3) >> v4) | ((((1 << ((a2 & 7) - 3)) - 1) & *(&unk_5158 + 1316 * a1 + v3 + 1)) << (8 - v4));
      else
        return (*(&unk_5158 + 1316 * a1 + v3) >> v4) & 0x1F;
    }
    
  • __int64 __fastcall sub_1321(int a1, unsigned int a2)
    {
      unsigned int v3; // [rsp+Ch] [rbp-Ch]
      unsigned int v4; // [rsp+10h] [rbp-8h]
    
      v3 = a2 >> 3;
      v4 = a2 & 7;
      if ( v4 > 4 )
        return (*(&unk_5158 + 1316 * a1 + v3) >> v4) | ((((1 << ((a2 & 7) - 4)) - 1) & *(&unk_5158 + 1316 * a1 + v3 + 1)) << (8 - v4));
      else
        return (*(&unk_5158 + 1316 * a1 + v3) >> v4) & 0xF;
    }
    
  • __int64 __fastcall sub_13F9(int a1, unsigned int a2)
    {
      unsigned int v3; // [rsp+Ch] [rbp-Ch]
    
      v3 = a2 >> 3;
      if ( (a2 & 7) != 0 )
        return (*(&unk_5158 + 1316 * a1 + v3) >> (a2 & 7)) | (*(&unk_5158 + 1316 * a1 + v3 + 1) << (8 - (a2 & 7))) | ((((1 << (a2 & 7)) - 1) & *(&unk_5158 + 1316 * a1 + v3 + 2)) << (16 - (a2 & 7)));
      else
        return *(&unk_5158 + 1316 * a1 + v3) | (*(&unk_5158 + 1316 * a1 + v3 + 1) << 8);
    }
    
  • 翻译一下:

  • int __cdecl main(int argc, const char **argv, const char **envp)
    {
      puts("Welcome! Drill Down.");
      init_vm();
      run_vm();
      putchar(10);
      return 0;
    }
    
    void __fastcall init_vm()
    {
      int i; // [rsp+4h] [rbp-43Ch]
      __int64 src[4]; // [rsp+10h] [rbp-430h] BYREF
      char v2[1024]; // [rsp+30h] [rbp-410h] BYREF
      unsigned __int64 v3; // [rsp+438h] [rbp-8h]
    
      v3 = __readfsqword(0x28u);
      for ( i = 0; i <= 9; ++i )
        vm_ins[0].reg[i].ready = 1;
      vm_ins[0].pc_ready = 1;
      vm_ins[0].code_ready = 1;
      vm_ins[0].memory_ready = 1;
      qmemcpy(v2, byte_3020, 343uLL);
      v2[343] = 0;
      memset(&v2[344], 0, 680uLL);
      qmemcpy(vm_ins[0].code, v2, sizeof(vm_ins[0].code));
      memset(&vm_ins[0].memory[40], 0, 44uLL);
      qmemcpy(&vm_ins[0].memory[40], "win!fail", 8);
      vm_ins[0].memory[24] = 0x11;
      vm_ins[0].memory[28] = 0x22;
      vm_ins[0].memory[32] = 0x88;
      vm_ins[0].memory[36] = 0xFF;
      src[0] = 0x3A84F4140FB6B1B8LL;
      src[1] = 0xB485900290CE01CBLL;
      src[2] = 0x2D7458B7EA807F7CLL;
      src[3] = 0LL;
      memcpy(&vm_ins[0].memory[88], src, 0x18uLL);
    }
    
    void __fastcall run_vm()
    {
      int i; // [rsp+8h] [rbp-8h]
      int j; // [rsp+Ch] [rbp-4h]
    
      for ( i = 0; i <= 9; ++i )
        pthread_create(&threads[i], 0LL, (void *(*)(void *))start_routine, &dword_5020[i]);
      pthread_create(&threads[10], 0LL, (void *(*)(void *))prepare_pc, 0LL);
      pthread_create(&threads[11], 0LL, (void *(*)(void *))prepare_code, 0LL);
      pthread_create(&threads[12], 0LL, (void *(*)(void *))prepare_memory, 0LL);
      for ( j = 0; j <= 9; ++j )
        pthread_join(threads[j], 0LL);
      pthread_join(threads[10], 0LL);
      pthread_join(threads[11], 0LL);
      pthread_join(threads[12], 0LL);
    }
    
    void __fastcall start_routine(unsigned int *arg)
    {
      int v1; // eax
      int i; // [rsp+18h] [rbp-18h]
      unsigned int reg_index; // [rsp+1Ch] [rbp-14h]
      unsigned int opcode; // [rsp+20h] [rbp-10h]
      unsigned int v5; // [rsp+24h] [rbp-Ch]
      unsigned int imm; // [rsp+28h] [rbp-8h]
      unsigned int v7; // [rsp+2Ch] [rbp-4h]
    
      reg_index = *arg;
      for ( i = 1; i <= 999999; ++i )
      {
        vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[reg_index].value;
        while ( !vm_ins[i - 1].pc_ready )
          ;
        while ( !vm_ins[i - 1].code_ready )
          ;
        opcode = fetch_opcode(i - 1, vm_ins[i - 1].pc);
        if ( opcode != 29 || reg_index )
        {
          if ( opcode == 31 )
            break;
          if ( reg_index == fetch_reg_index(i - 1, vm_ins[i - 1].pc + 5) )
          {
            if ( (opcode & 0x18) != 0 )
            {
              if ( (opcode & 0x18) == 8 )
              {
                imm = fetch_imm16(i - 1, vm_ins[i - 1].pc + 9);
                switch ( opcode & 7 )
                {
                  case 0u:
                    vm_ins[i].reg[reg_index].value = imm + vm_ins[i - 1].reg[reg_index].value;
                    break;
                  case 1u:
                    vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[reg_index].value - imm;
                    break;
                  case 2u:
                    vm_ins[i].reg[reg_index].value = imm;
                    break;
                  case 3u:
                    vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[reg_index].value << imm;
                    break;
                  case 4u:
                    vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[reg_index].value >> imm;
                    break;
                  default:
                    break;
                }
              }
              else if ( opcode == 16 )
              {
                v5 = fetch_reg_index(i - 1, vm_ins[i - 1].pc + 9);
                do
                {
                  while ( !vm_ins[i - 1].reg[v5].ready )
                    ;
                }
                while ( !vm_ins[i - 1].memory_ready );
                vm_ins[i].reg[reg_index].value = (unsigned __int8)vm_ins[i - 1].memory[vm_ins[i - 1].reg[v5].value];
              }
            }
            else
            {
              v7 = fetch_reg_index(i - 1, vm_ins[i - 1].pc + 9);
              while ( !vm_ins[i - 1].reg[v7].ready )
                ;
              v1 = opcode & 7;
              if ( v1 == 3 )
              {
                vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[v7].value ^ vm_ins[i - 1].reg[reg_index].value;
              }
              else if ( (opcode & 7) <= 3 )
              {
                if ( v1 == 2 )
                {
                  vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[v7].value;
                }
                else if ( (opcode & 7) != 0 )
                {
                  vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[reg_index].value - vm_ins[i - 1].reg[v7].value;
                }
                else
                {
                  vm_ins[i].reg[reg_index].value = vm_ins[i - 1].reg[reg_index].value + vm_ins[i - 1].reg[v7].value;
                }
              }
            }
          }
        }
        else
        {
          vm_ins[i].reg[0].value = getchar();
        }
        vm_ins[i].reg[reg_index].ready = 1;
      }
      pthread_exit(0LL);
    }
    
    void __fastcall __noreturn prepare_pc(void *arg)
    {
      int i; // [rsp+4h] [rbp-Ch]
      unsigned int v2; // [rsp+8h] [rbp-8h]
      unsigned int v3; // [rsp+Ch] [rbp-4h]
    
      for ( i = 1; i <= 99999; ++i )
      {
        vm_ins[i].pc = vm_ins[i - 1].pc;
        while ( !vm_ins[i - 1].code_ready )
          ;
        v2 = fetch_opcode(i - 1, vm_ins[i - 1].pc);
        if ( (v2 & 0x18) != 0 && (v2 & 0x18) != 0x10 )
        {
          if ( (v2 & 0x18) == 0x18 )
          {
            vm_ins[i].pc = vm_ins[i - 1].pc + 5;
            if ( v2 == 28 )
            {
              while ( !vm_ins[i - 1].reg[0].ready )
                ;
              putchar((char)vm_ins[i - 1].reg[0].value);
            }
            if ( v2 == 31 )
              break;
          }
          else if ( (v2 & 0x18) == 8 )
          {
            vm_ins[i].pc = vm_ins[i - 1].pc + 25;
            if ( v2 == 15 )
            {
              v3 = fetch_reg_index(i - 1, vm_ins[i - 1].pc + 5);
              while ( !vm_ins[i - 1].reg[v3].ready )
                ;
              if ( vm_ins[i - 1].reg[v3].value )
                vm_ins[i].pc = fetch_imm16(i - 1, vm_ins[i - 1].pc + 9);
            }
          }
        }
        else
        {
          vm_ins[i].pc = vm_ins[i - 1].pc + 13;
        }
        vm_ins[i].pc_ready = 1;
      }
      pthread_exit(0LL);
    }
    
    void __fastcall __noreturn prepare_code(void *arg)
    {
      int i; // [rsp+Ch] [rbp-4h]
    
      for ( i = 1; i <= 99999; ++i )
      {
        memcpy(vm_ins[i].code, vm_ins[i - 1].code, sizeof(vm_ins[i].code));
        vm_ins[i].code_ready = 1;
      }
      pthread_exit(0LL);
    }
    
    void __fastcall __noreturn prepare_memory(void *arg)
    {
      int i; // [rsp+0h] [rbp-10h]
      unsigned int v2; // [rsp+4h] [rbp-Ch]
      unsigned int v3; // [rsp+8h] [rbp-8h]
      unsigned int v4; // [rsp+Ch] [rbp-4h]
    
      for ( i = 1; i <= 99999; ++i )
      {
        memcpy(vm_ins[i].memory, vm_ins[i - 1].memory, sizeof(vm_ins[i].memory));
        while ( !vm_ins[i - 1].pc_ready )
          ;
        while ( !vm_ins[i - 1].code_ready )
          ;
        v2 = fetch_opcode(i - 1, vm_ins[i - 1].pc);
        if ( v2 == 17 )
        {
          v3 = fetch_reg_index(i - 1, vm_ins[i - 1].pc + 5);
          v4 = fetch_reg_index(i - 1, vm_ins[i - 1].pc + 9);
          do
          {
            while ( !vm_ins[i - 1].reg[v3].ready )
              ;
          }
          while ( !vm_ins[i - 1].reg[v4].ready );
          vm_ins[i].memory[vm_ins[i - 1].reg[v4].value] = vm_ins[i - 1].reg[v3].value;
        }
        else if ( v2 == 31 )
        {
          break;
        }
        vm_ins[i].memory_ready = 1;
      }
      pthread_exit(0LL);
    }
    
  • 开了很多并行独立程序,实现了一个类似于实际 CPU 执行的 vm,在计算机使用者的角度不用考虑 CPU 的具体设计,只要知道指令是顺序执行的就行。

  • 下面进行提取执行的指令:

  • codes = open('./vm', 'rb').read()[0x3020: 0x3020 + 0x157]
    codes = ''.join(bin(i)[2: ].rjust(8, '0')[:: -1] for i in codes)
    
    def fetch_imm(codes, pc, size):
        assert pc + size <= len(codes)
        value = int(codes[pc: pc + size][:: -1], 2)
        return value, pc + size
    
    def fetch_opcode(codes, pc):
        return fetch_imm(codes, pc, 5)
    
    def fetch_reg_index(codes, pc):
        return fetch_imm(codes, pc, 4)
    
    def fetch_imm16(codes, pc):
        return fetch_imm(codes, pc, 16)
    
    regs = ['rax', 'rbp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15']
    
    print('.intel_syntax noprefix')
    pc = 0
    while pc < len(codes):
        print('_0x%04x: ' % pc, end='')
        opcode, pc = fetch_opcode(codes, pc)
        if opcode == 15:
            dreg, pc = fetch_reg_index(codes, pc)
            imm, pc = fetch_imm16(codes, pc)
            print('cmp %s, 0\n  jnz _0x%04x' % (regs[dreg], imm))
        elif opcode == 17:
            dreg, pc = fetch_reg_index(codes, pc)
            sreg, pc = fetch_reg_index(codes, pc)
            print('mov [%s + 0x2000], %s' % (regs[sreg], regs[dreg]))
        elif opcode == 28:
            print('call m_putchar')
        elif opcode == 29:
            print('call m_getchar')
        elif opcode == 31:
            print('ret')
        elif opcode == 16:
            dreg, pc = fetch_reg_index(codes, pc)
            sreg, pc = fetch_reg_index(codes, pc)
            print('mov %s, [%s + 0x2000]' % (regs[dreg], regs[sreg]))
        elif opcode & 0x18 == 8:
            dreg, pc = fetch_reg_index(codes, pc)
            imm, pc = fetch_imm16(codes, pc)
            op = ['add', 'sub', 'mov', 'shl', 'shr'][opcode & 7]
            print('%s %s, 0x%x' % (op, regs[dreg], imm))
        elif opcode & 0x18 == 0:
            dreg, pc = fetch_reg_index(codes, pc)
            sreg, pc = fetch_reg_index(codes, pc)
            op = ['add', 'sub', 'mov', 'xor'][opcode & 7]
            print('%s %s, %s' % (op, regs[dreg], regs[sreg]))
        else:
            assert False, hex(opcode)
    
    
  • 运行,得到指令存在main.s中,gcc -c ./main.s -o main.o,编译好用IDA分析。

  • 得到:

  • __int64 __fastcall 0x0000(__int64 a1, __int64 a2)
    {
      __int64 v2; // rbp
      __int64 v3; // r8
      __int64 v4; // rax
      __int64 v5; // r8
      __int64 v6; // r8
      __int64 v7; // rbp
      unsigned __int64 v8; // r10
      __int64 v9; // r8
      unsigned __int64 v10; // r11
      __int64 v11; // rbp
      __int64 v12; // rax
      __int64 v13; // r13
      __int64 v14; // rax
      __int64 v15; // rax
      __int64 v16; // r14
      __int64 v17; // rax
      __int64 v18; // rax
      __int64 v19; // r13
      __int64 v20; // rax
      __int64 v21; // rax
      __int64 v22; // r14
      __int64 v23; // rax
      __int64 v24; // rbp
      __int64 v25; // r8
      __int64 v26; // r9
      __int64 v27; // rdx
      __int64 v28; // rcx
      __int64 v29; // r8
      __int64 v30; // r9
      __int64 v31; // rdx
      __int64 v32; // rcx
      __int64 v33; // r8
      __int64 v34; // r9
      __int64 v35; // rdx
      __int64 v36; // rcx
      __int64 v37; // r8
      __int64 v38; // r9
    
      v2 = 24i64;
      v3 = 0i64;
      do
      {
        v4 = m_getchar(a1, a2, v3);
        *(_QWORD *)(v5 + 0x2000) = v4;
        --v2;
        v3 = v5 + 1;
      }
      while ( v2 );
      do
      {
        v6 = 4i64;
        v7 = 8i64 * MEMORY[0x2030];
        v8 = 0i64;
        do
        {
          v8 = *(_QWORD *)(v7 + 0x2000) ^ (v8 << 8);
          ++v7;
          --v6;
        }
        while ( v6 );
        v9 = 4i64;
        v10 = 0i64;
        do
        {
          v10 = *(_QWORD *)(v7 + 0x2000) ^ (v10 << 8);
          ++v7;
          --v9;
        }
        while ( v9 );
        v11 = 32i64;
        do
        {
          v9 += 1126266966i64;
          v12 = 4i64;
          v13 = 0i64;
          do
          {
            v14 = v12 + 23;
            v13 = *(_QWORD *)(v14 + 0x2000) ^ (v13 << 8);
            v12 = v14 - 24;
          }
          while ( v12 );
          v15 = 4i64;
          v16 = 0i64;
          do
          {
            v17 = v15 + 27;
            v16 = *(_QWORD *)(v17 + 0x2000) ^ (v16 << 8);
            v15 = v17 - 28;
          }
          while ( v15 );
          v8 += (v16 + (v10 >> 5)) ^ (v10 + v9) ^ (v13 + 16 * v10);
          v18 = 4i64;
          v19 = 0i64;
          do
          {
            v20 = v18 + 31;
            v19 = *(_QWORD *)(v20 + 0x2000) ^ (v19 << 8);
            v18 = v20 - 32;
          }
          while ( v18 );
          v21 = 4i64;
          v22 = 0i64;
          do
          {
            v23 = v21 + 35;
            v22 = *(_QWORD *)(v23 + 0x2000) ^ (v22 << 8);
            v21 = v23 - 36;
          }
          while ( v21 );
          v10 += (v22 + (v8 >> 5)) ^ (v8 + v9) ^ (v19 + 16 * v8);
          --v11;
        }
        while ( v11 );
        v24 = 8i64 * MEMORY[0x2030] + 64;
        v25 = 8i64 * MEMORY[0x2030] + 68;
        v26 = 4i64;
        do
        {
          --v26;
          *(_QWORD *)(v24 + 0x2000) = v8;
          *(_QWORD *)(v25 + 0x2000) = v10;
          ++v24;
          ++v25;
          v8 >>= 8;
          v10 >>= 8;
        }
        while ( v26 );
        ++MEMORY[0x2030];
      }
      while ( MEMORY[0x2030] != 3i64 );
      if ( MEMORY[0x2058] != MEMORY[0x2040] )
        m_putchar(a1, a2, 88i64, 24i64);
      else
        m_putchar(a1, a2, 89i64, 23i64);
      m_putchar(v28, v27, v29, v30);
      m_putchar(v32, v31, v33, v34);
      return m_putchar(v36, v35, v37, v38);
    }
    
  • 就是tea加密,套脚本解密即可

  • from ctypes import *
    
    
    def encrypt(v, k):
        v0 = c_uint32(v[0])
        v1 = c_uint32(v[1])
        sum1 = c_uint32(0)
        delta = 0x43217856
        for i in range(32):
            sum1.value += delta
            v0.value += ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
            v1.value += ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
        return v0.value, v1.value
    
    
    def decrypt(v, k):
        v0 = c_uint32(v[0])
        v1 = c_uint32(v[1])
        delta = 0x43217856
        sum1 = c_uint32(delta*32)
        for i in range(32):
            v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
            v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
            sum1.value -= delta
        return long_to_bytes(v0.value)+long_to_bytes(v1.value)
    
    
    if __name__ == '__main__':
        a=[0x0FB6B1B8, 0x3A84F414]
        a1=[0x90CE01CB,0xB4859002]
        a2=[0xEA807F7C,0x2D7458B7]
        k=[17,34,0x88,0xFF]
        res= decrypt(a, k)+decrypt(a1,k)+decrypt(a2,k)
        print("解密后数据:", res)
    
    
    
  • 得到flag:flag{FSM_A_M4j0r_In_CO!}