羊城杯2023 Quals Reverse WriteUp

  • 文件夹里突然发现的一篇远古复现wp,发出来

一. CSGO

  • go1.18写的exe,找到main函数

  • void __golang main_main()
    {
      __int64 v0; // r14
      _QWORD *v1; // rax
      __int64 i; // rax
      __int64 v3; // rdi
      main__Ctype_char *v4; // rax
      void (**v5)(void); // rax
      __int64 v6; // rbx
      main__Ctype_char *v7; // rax
      char v8; // al
      io_Writer_0 p0; // [rsp+0h] [rbp-C8h]
      runtime__type_0 *p0b; // [rsp+0h] [rbp-C8h]
      io_Writer_0 p0c; // [rsp+0h] [rbp-C8h]
      io_Reader_0 p0d; // [rsp+0h] [rbp-C8h]
      _BYTE p0a[40]; // [rsp+0h] [rbp-C8h] OVERLAPPED
      main__Ctype_char *p0e; // [rsp+0h] [rbp-C8h]
      string p0f; // [rsp+0h] [rbp-C8h]
      uint8 *p0g; // [rsp+0h] [rbp-C8h]
      _slice_interface_ v17; // [rsp+10h] [rbp-B8h]
      _slice_interface_ v18; // [rsp+10h] [rbp-B8h]
      string v19; // [rsp+10h] [rbp-B8h]
      _slice_interface_ v20; // [rsp+20h] [rbp-A8h]
      main__Ctype_char *p1; // [rsp+50h] [rbp-78h]
      _QWORD *v22; // [rsp+60h] [rbp-68h]
      __int128 v23; // [rsp+78h] [rbp-50h] BYREF
      const char *v24; // [rsp+88h] [rbp-40h]
      _QWORD *v25; // [rsp+90h] [rbp-38h]
      void *v26; // [rsp+98h] [rbp-30h]
      char **v27; // [rsp+A0h] [rbp-28h]
      void *v28; // [rsp+A8h] [rbp-20h]
      char **v29; // [rsp+B0h] [rbp-18h]
      void (**v30)(void); // [rsp+B8h] [rbp-10h]
    
      if ( (unsigned __int64)&v23 + 8 <= *(_QWORD *)(v0 + 16) )
        runtime_morestack_noctxt_abi0();
      v30 = 0LL;
      v28 = &unk_17E120;
      v29 = &main__stmp_0;
      fmt_Fprintln(p0, v17);
      p0c.data = runtime_newobject(p0b);
      v22 = v1;
      *v1 = 0LL;
      v26 = &unk_17E120;
      v27 = &main__stmp_1;
      *(_OWORD *)&v20.len = (unsigned __int128)fmt_Fprint(p0c, v18);
      v24 = "\b";
      v25 = v22;
      fmt_Fscanf(p0d, v19, v20);
      for ( i = 0LL; i < 64; i = v3 + 1 )
      {
        v3 = i;
        if ( (unsigned __int64)(i - ((i + 11) >> 6 << 6) + 11) >= 0x40 )
          runtime_panicIndex();
        *(string *)&p0a[16] = runtime_intstring(*(uint8 (**)[4])p0a, *(int64 *)&p0a[8]);
        runtime_concatstring2(*(runtime_tmpBuf **)p0a, *(string *)&p0a[8], *(string *)&p0a[24]);
      }
      main__Cfunc_CString(*(string *)p0a);
      p1 = v4;
      p0f.len = (__int64)main_main_func1(p0e);
      v30 = v5;
      v6 = v22[1];
      main__Cfunc_CString(p0f);
      main__Cfunc_enc_abi0(v7, p1);
      *(string *)&p0a[8] = runtime_gostring(p0g);
      if ( v6 == 60 && (runtime_memequal(), v8) )
      {
        fmt_Fprintln(*(io_Writer_0 *)p0a, *(_slice_interface_ *)&p0a[16]);
      }
      else
      {
        *((_QWORD *)&v23 + 1) = &main__stmp_2;
        fmt_Fprintln(*(io_Writer_0 *)p0a, *(_slice_interface_ *)&p0a[16]);
      }
      (*v30)();
    }
    
  • 分析逻辑:输入字符串,base64换表加密,比较

  • 动调得到表:LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJK

  • 解密得到:DASCTF{73913519-A0A6-5575-0F10-DDCBF50FA8CA}

二. Blast

  • 控制流混淆,写脚本去除

  • from idc import *
    def patch(start, end):
    	i = start
    	while i < end:
    		if print_insn_mnem(i) == 'jnz' and print_insn_mnem(i + 6) == 'jmp' and print_operand(i + 0xb, 0) == '$+5' and print_insn_mnem(i + 0xb) == 'jmp':
    			print(hex(i))
    			for j in range(i, i + 0x10):
    				patch_byte(j, 0x90)
    				i += 0xf
    		i += 1
    for seg in Segments():
    	if get_segm_name(seg) == '.text':
    		patch(seg, 0x40B7E4)
    
  • 可以用findcrypt插件或动调识别出其实就是两次md5加密,最后比较

  • 直接爆破

  • from hashlib import *
    
    result = [
        '14d89c38cd0fb23a14be2798d449c182',
        'a94837b18f8f43f29448b40a6e7386ba',
        'af85d512594fc84a5c65ec9970956ea5',
        'af85d512594fc84a5c65ec9970956ea5',
        '10e21da237a4a1491e769df6f4c3b419',
        'a705e8280082f93f07e3486636f3827a',
        '297e7ca127d2eef674c119331fe30dff',
        'b5d2099e49bdb07b8176dff5e23b3c14',
        '83be264eb452fcf0a1c322f2c7cbf987',
        'a94837b18f8f43f29448b40a6e7386ba',
        '71b0438bf46aa26928c7f5a371d619e1',
        'a705e8280082f93f07e3486636f3827a',
        'ac49073a7165f41c57eb2c1806a7092e',
        'a94837b18f8f43f29448b40a6e7386ba',
        'af85d512594fc84a5c65ec9970956ea5',
        'ed108f6919ebadc8e809f8b86ef40b05',
        '10e21da237a4a1491e769df6f4c3b419',
        '3cfd436919bc3107d68b912ee647f341',
        'a705e8280082f93f07e3486636f3827a',
        '65c162f7c43612ba1bdf4d0f2912bbc0',
        '10e21da237a4a1491e769df6f4c3b419',
        'a705e8280082f93f07e3486636f3827a',
        '3cfd436919bc3107d68b912ee647f341',
        '557460d317ae874c924e9be336a83cbe',
        'a705e8280082f93f07e3486636f3827a',
        '9203d8a26e241e63e4b35b3527440998',
        '10e21da237a4a1491e769df6f4c3b419',
        'f91b2663febba8a884487f7de5e1d249',
        'a705e8280082f93f07e3486636f3827a',
        'd7afde3e7059cd0a0fe09eec4b0008cd',
        '488c428cd4a8d916deee7c1613c8b2fd',
        '39abe4bca904bca5a11121955a2996bf',
        'a705e8280082f93f07e3486636f3827a',
        '3cfd436919bc3107d68b912ee647f341',
        '39abe4bca904bca5a11121955a2996bf',
        '4e44f1ac85cd60e3caa56bfd4afb675e',
        '45cf8ddfae1d78741d8f1c622689e4af',
        '3cfd436919bc3107d68b912ee647f341',
        '39abe4bca904bca5a11121955a2996bf',
        '4e44f1ac85cd60e3caa56bfd4afb675e',
        '37327bb06c83cb29cefde1963ea588aa',
        'a705e8280082f93f07e3486636f3827a',
        '23e65a679105b85c5dc7034fded4fb5f',
        '10e21da237a4a1491e769df6f4c3b419',
        '71b0438bf46aa26928c7f5a371d619e1',
        'af85d512594fc84a5c65ec9970956ea5',
        '39abe4bca904bca5a11121955a2996bf',
    ]
    for i in range(len(result)):
        for j in range(30,128):
            if md5(md5(chr(j).encode()).hexdigest().encode()).hexdigest() == result[i]:
                print(chr(j),end="")
    
  • 得到Hello_Ctfer_Velcom_To_my_Mov_and_md5(md5)_world

三. ez加密器

  • 根据字符串提示找到如下:

  • __int64 sub_1400140E0()
    {
      char *v0; // r8
      char *v1; // rcx
      char *v2; // r9
      char v3; // si
      unsigned __int8 v4; // di
      int v5; // eax
      int v6; // edx
      int v7; // edi
      int v8; // eax
      int v9; // edi
      int v10; // ebp
      int v11; // edi
      int v12; // r12d
      int v13; // edi
      char v14; // di
      int v15; // eax
      int v16; // edx
      int v18; // esi
      int v19; // eax
      int v20; // esi
      int v21; // edi
      int v22; // esi
      int v23; // ebp
      int v24; // esi
      char *v25; // [rsp+20h] [rbp-D8h] BYREF
      __int64 v26; // [rsp+28h] [rbp-D0h]
      char v27[8]; // [rsp+38h] [rbp-C0h] BYREF
      char Str2[184]; // [rsp+40h] [rbp-B8h] BYREF
    
      sub_140003D87();
      sub_140003C30((__int64)a000000, (__int64)a11111111111111);
      sub_1400036A0((__int64)a000000, 6u, (unsigned __int8 *)v27);
      sub_140003AE0((__int64)&v25, (__int64)v27, a11111111111111, 40);
      v0 = v25;
      if ( (int)v26 <= 0 )
      {
        v2 = Str2;
      }
      else
      {
        v1 = Str2;
        v2 = &Str2[2 * (int)v26];
        do
        {
          v3 = *v0;
          v4 = (unsigned __int8)*v0 >> 4;
          v5 = v4;
          if ( v4 <= 9u )
          {
            LOBYTE(v6) = v4 ^ 0x30;
            if ( !v4 )
              LOBYTE(v6) = 48;
          }
          else
          {
            v6 = 65;
            do
            {
              v7 = v6 & v5;
              v6 ^= v5;
              v5 = 2 * v7;
            }
            while ( 2 * v7 );
            v8 = 0xFFFFFFF5;
            v9 = 1;
            do
            {
              v10 = v9;
              v11 = v8 & v9;
              v12 = v8;
              v8 ^= v10;
              v9 = 2 * v11;
            }
            while ( v9 );
            if ( v10 != v12 )
            {
              do
              {
                v13 = v6 & v8;
                v6 ^= v8;
                v8 = 2 * v13;
              }
              while ( 2 * v13 );
            }
          }
          *v1 = v6;
          v1 += 2;
          v14 = v3 & 0xF;
          v15 = v3 & 0xF;
          if ( (v3 & 0xFu) > 9 )
          {
            v16 = 65;
            do
            {
              v18 = v16 & v15;
              v16 ^= v15;
              v15 = 2 * v18;
            }
            while ( 2 * v18 );
            v19 = -11;
            v20 = 1;
            do
            {
              v21 = v20;
              v22 = v19 & v20;
              v23 = v19;
              v19 ^= v21;
              v20 = 2 * v22;
            }
            while ( v20 );
            if ( v21 != v23 )
            {
              do
              {
                v24 = v16;
                v16 ^= v19;
                v19 = 2 * (v19 & v24);
              }
              while ( v19 );
            }
          }
          else
          {
            LOBYTE(v16) = v14 ^ 0x30;
            if ( !v14 )
              LOBYTE(v16) = 48;
          }
          *(v1 - 1) = v16;
          ++v0;
        }
        while ( v1 != v2 );
      }
      *v2 = 0;
      if ( !strcmp(Big_Numbers1_1400150A0, Str2) )
        sub_1400016E0((__int64)"------\nGetFlag!\n------");
      system("pause");
      return 0i64;
    }
    
  • __int64 __fastcall sub_140003C30(__int64 a1, __int64 a2)
    {
      __int64 result; // rax
    
      sub_1400016E0((__int64)"Please enter the verification code: \n");
      sub_140001730(&unk_140016000, a1);
      if ( !(unsigned __int8)sub_140003A20(a1)
        || (sub_1400016E0((__int64)"Please enter the flag: \n"),
            sub_140001730(&unk_140016000, a2),
            result = sub_140003910(a2),
            !(_BYTE)result) )
      {
        exit(-1);
      }
      return result;
    }
    
  • 输入函数,输入6位code以及flag

  • __int64 __fastcall sub_1400036A0(__int64 a1, unsigned __int16 a2, unsigned __int8 *a3)
    {
      signed int v6; // esi
      unsigned int v7; // edx
      __int64 v8; // rdi
      int v9; // ecx
      _BYTE *v10; // r12
      _BYTE *v11; // rbp
      int v12; // eax
      int v13; // r9d
      int v14; // eax
      unsigned int v15; // r9d
      unsigned __int8 *v16; // rax
      __int64 v17; // rcx
      __int16 v18; // r11
      _BYTE *v19; // r9
      unsigned __int8 *v20; // r11
      _BYTE *v21; // rbx
      int v22; // eax
      int v23; // ecx
      _BYTE *v25; // r11
      unsigned __int8 *v26; // r10
      int v27; // eax
      int v28; // ecx
    
      v6 = 3 * (a2 / 3u);
      if ( a2 <= 2u )
        goto LABEL_19;
      LOWORD(v7) = 0;
      v8 = 0i64;
      v9 = 0;
      do
      {
        v10 = (_BYTE *)(a1 + v8 + 1);
        a3[(unsigned __int16)v7] = *(_BYTE *)(a1 + v8) >> 2;
        v11 = (_BYTE *)(a1 + v8 + 2);
        a3[(unsigned __int16)v7 + 1] = (*v10 >> 4) | (16 * *(_BYTE *)(a1 + v8)) & 0x30;
        a3[(unsigned __int16)v7 + 2] = (*v11 >> 6) | (4 * *v10) & 0x3C;
        a3[(unsigned __int16)v7 + 3] = *v11 & 0x3F;
        v12 = 3;
        do
        {
          v13 = v9 & v12;
          v9 ^= v12;
          v12 = 2 * v13;
        }
        while ( 2 * v13 );
        v8 = (unsigned __int16)v9;
        v7 = (unsigned __int16)v7;
        v14 = 4;
        do
        {
          v15 = v7;
          v7 ^= v14;
          v14 = 2 * (v14 & v15);
        }
        while ( v14 );
        v9 = (unsigned __int16)v9;
      }
      while ( (unsigned __int16)v9 < v6 );
      if ( (_WORD)v7 )
      {
        v16 = a3;
        do
        {
          v17 = *v16++;
          *(v16 - 1) = off_140015108[v17];
        }
        while ( v16 != &a3[(unsigned __int16)(v7 - 1) + 1] );
      }
      else
      {
    LABEL_19:
        v7 = 0;
      }
      v18 = a2 - 3 * (a2 / 3u);
      if ( v18 == 1 )
      {
        v7 = (unsigned __int16)v7;
        v25 = (_BYTE *)(a1 + a2 - 1);
        v26 = &a3[(unsigned __int16)v7];
        *v26 = *v25 >> 2;
        v26[1] = (16 * *v25) & 0x30;
        *v26 = off_140015108[*v26];
        v26[1] = off_140015108[v26[1]];
        v27 = 4;
        v26[2] = 61;
        v26[3] = 61;
        do
        {
          v28 = v7 & v27;
          v7 ^= v27;
          v27 = 2 * v28;
        }
        while ( 2 * v28 );
        return v7;
      }
      else
      {
        if ( v18 == 2 )
        {
          v7 = (unsigned __int16)v7;
          v19 = (_BYTE *)(a1 + a2 - 2);
          v20 = &a3[(unsigned __int16)v7];
          v21 = (_BYTE *)(a1 + a2 - 1);
          *v20 = *v19 >> 2;
          v20[1] = (*v21 >> 4) | (16 * *v19) & 0x30;
          v20[2] = (4 * *v21) & 0x3C;
          *v20 = off_140015108[*v20];
          v20[1] = off_140015108[v20[1]];
          v20[2] = off_140015108[v20[2]];
          v22 = 4;
          v20[3] = 61;
          do
          {
            v23 = v7 & v22;
            v7 ^= v22;
            v22 = 2 * v23;
          }
          while ( 2 * v23 );
        }
        return v7;
      }
    }
    
  • BASE64换表加密,对code进行加密

  • __int64 __fastcall sub_140003AE0(__int64 a1, __int64 a2, const void *a3, int a4)
    {
      size_t v6; // rbx
      unsigned __int8 v8; // r14
      int v9; // ebp
      char *v10; // rdi
      __int64 *v11; // r8
      __int64 v12; // rdx
      char *v13; // rbx
      char *v14; // r8
      char *v15; // rcx
      __int64 result; // rax
      unsigned __int64 v17; // r9
      unsigned int v18; // eax
      unsigned int v19; // ecx
      __int64 v20; // r8
      char v21[184]; // [rsp+20h] [rbp-B8h] BYREF
    
      v6 = a4;
      sub_1400016E0(&unk_140016003);
      sub_140001A20(a2, v21);
      v8 = ((unsigned int)((int)v6 >> 31) >> 29) - ((v6 + ((unsigned int)((int)v6 >> 31) >> 29)) & 7) + 8;
      v9 = v6 + v8;
      v10 = (char *)malloc(v9);
      memcpy(v10, a3, v6);
      v11 = (__int64 *)&v10[v6];
      v12 = 0x101010101010101i64 * v8;
      if ( v8 >= 8u )
      {
        *v11 = v12;
        v17 = (unsigned __int64)(v11 + 1) & 0xFFFFFFFFFFFFFFF8ui64;
        *(__int64 *)((char *)v11 + v8 - 8) = v12;
        if ( (((_DWORD)v11 - (_DWORD)v17 + v8) & 0xFFFFFFF8) >= 8 )
        {
          v18 = ((_DWORD)v11 - v17 + v8) & 0xFFFFFFF8;
          v19 = 0;
          do
          {
            v20 = v19;
            v19 += 8;
            *(_QWORD *)(v17 + v20) = v12;
          }
          while ( v19 < v18 );
        }
      }
      else if ( (v8 & 4) != 0 )
      {
        *(_DWORD *)v11 = v12;
        *(_DWORD *)((char *)v11 + v8 - 4) = v12;
      }
      else if ( ((unsigned int)((int)v6 >> 31) >> 29) - (((_BYTE)v6 + ((unsigned int)((int)v6 >> 31) >> 29)) & 7) != 0xF8 )
      {
        *(_BYTE *)v11 = v8;
        if ( (v8 & 2) != 0 )
          *(_WORD *)((char *)v11 + v8 - 2) = v12;
      }
      if ( v9 > 0 )
      {
        v13 = v10;
        do
        {
          v14 = v13;
          v15 = v13;
          v13 += 8;
          sub_140002180(v15, v21, v14);
        }
        while ( v13 != &v10[8 * ((unsigned int)(v9 - 1) >> 3) + 8] );
      }
      sub_1400016E0(&unk_140016003);
      result = a1;
      *(_QWORD *)a1 = v10;
      *(_DWORD *)(a1 + 8) = v9;
      return result;
    }
    
  • DES,用加密后的code进行flag的加密,此时code正好8字节,符合DES加密标准

  • 故爆破六位code

  • from Crypto.Cipher import DES
    import base64
    
    c= bytes.fromhex("0723105D5C12217DCDC3601F5ECB54DA9CCEC2279F1684A13A0D716D17217F4C9EA85FF1A42795731CA3C55D3A4D7BEA")
    tab1 = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/'
    tab2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    for i in range(1000000):
        key = base64.b64encode(str(i).rjust(6,"0").encode()).decode().translate(str.maketrans(tab2,tab1)).encode()
        cipher = DES.new(key, DES.MODE_ECB)
        m= cipher.decrypt(c)
        if b"DASCTF{" in m:
            print(m)
            exit(1)
    
    
    
  • DASCTF{f771b96b71514bb6bc20f3275fa9404e}

四. vm_wo

  • 逻辑很简单

  • 写个反汇编脚本提取指令

  • opcode= [26, 0, 3, 25, 1, 1, 13, 2, 7, 24, 1, 2, 1, 0, 3, 26, 0, 3, 25,
              1, 2, 13, 2, 6, 24, 1, 2, 1, 0, 4, 26, 0, 3, 25, 1, 3, 13, 2, 5,
              24, 1, 2, 1, 0, 5, 26, 0, 3, 25, 1, 4, 13, 2, 4, 24, 1, 2, 1, 0, 6]
    
    pc=0
    while pc<len(opcode):
        print('0x%04x: '%pc,end="")
        if opcode[pc] == 0:
            print('swap reg%d reg%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==1:
            print('xor reg%d reg%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==2:
            print('add reg%d %d'%(opcode[pc+1],pc+2))
        elif opcode[pc]==3:
            print('add reg%d reg%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==4:
            print('sub reg%d %d'% (opcode[pc+1],pc+2))
        elif opcode[pc]==5:
            print('sub reg%d reg%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==6:
            print('mul reg%d %d'% (opcode[pc+1],pc+2))
        elif opcode[pc]==7:
            print('mul reg%d reg%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==8:
            print('div reg%d %d'% (opcode[pc+1],pc+2))
        elif opcode[pc]==9:
            print('div reg%d reg%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==13:
            print('mov reg%d reg0<<%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc] == 24:
            print('reg0 = reg2 | reg1')
        elif opcode[pc]==25:
            print('mov reg%d reg0>>%d'% (opcode[pc+1],opcode[pc+2]))
        elif opcode[pc]==26:
            print('mov reg%d %d'% (opcode[pc+1],opcode[pc+2]))
        pc+=3
    
  • 0x0000: mov reg0 3
    0x0003: mov reg1 reg0>>1
    0x0006: mov reg2 reg0<<7
    0x0009: reg0 = reg2 | reg1
    0x000c: xor reg0 reg3
    0x000f: mov reg0 3
    0x0012: mov reg1 reg0>>2
    0x0015: mov reg2 reg0<<6
    0x0018: reg0 = reg2 | reg1
    0x001b: xor reg0 reg4
    0x001e: mov reg0 3
    0x0021: mov reg1 reg0>>3
    0x0024: mov reg2 reg0<<5
    0x0027: reg0 = reg2 | reg1
    0x002a: xor reg0 reg5
    0x002d: mov reg0 3
    0x0030: mov reg1 reg0>>4
    0x0033: mov reg2 reg0<<4
    0x0036: reg0 = reg2 | reg1
    0x0039: xor reg0 reg6
    
    
  • 逻辑比较简单

  • 直接找到reg3到reg6的值逆就完了

  • enc = [0xDF, 0xD5, 0xF1, 0xD1, 0xFF, 0xDB, 0xA1, 0xA5, 0x89, 0xBD, 0xE9, 0x95, 0xB3, 0x9D, 0xE9, 0xB3, 0x85, 0x99, 0x87,
           0xBF, 0xE9, 0xB1, 0x89, 0xE9, 0x91, 0x89, 0x89, 0x8F, 0xAD]
    key = 0xBEEDBEEF.to_bytes(4, 'little')
    def decode(s):
        s = (s >> 3 | s << 5) & 0xFF
        s = s ^ key[3]
        s = (s << 4 | s >> 4) & 0xFF
        s = s ^ key[2]
        s = (s << 3 | s >> 5) & 0xFF
        s = s ^ key[1]
        s = (s << 2 | s >> 6) & 0xFF
        s = s ^ key[0]
        s = (s << 1 | s >> 7) & 0xFF
        return s
    
    flag=''
    for i in range(len(enc)):
        flag+=chr(decode(enc[i]))
    print(flag)
    
  • DASCTF{you_are_right_so_cool}