wp | re | 2021祥雲杯 逆向部分


今年是第二年打祥雲杯,只能說逆向的題型多鍾多樣,上來一個內核題就給我整蒙了。

出了這兩個小題目,簡單記錄一下。

勒索解密

吐槽:你家勒索病毒連個圖形化都沒有,誰知道往哪兒給你打錢啊

這個題是win32的逆向,主要的邏輯比較清晰的,重點就是加密,然后瘋狂的查文檔去看就行了,主要分析如下:

main函數還是比較清晰的:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  void *v4; // ecx
  void *v5; // eax
  _DWORD *i; // esi
  unsigned int v7; // edi
  int v8; // ebx
  void **v9; // ebx
  void **v10; // edi
  size_t v11; // ecx
  size_t v12; // ecx
  void *v13; // ecx
  void *v14; // eax
  int v16; // [esp+10h] [ebp-C0h] BYREF
  char v17[4]; // [esp+14h] [ebp-BCh]
  void *Block[5]; // [esp+18h] [ebp-B8h] BYREF
  unsigned int v19; // [esp+2Ch] [ebp-A4h]
  void *v20[6]; // [esp+30h] [ebp-A0h] BYREF
  HCRYPTPROV phProv[21]; // [esp+48h] [ebp-88h] BYREF
  void *Src[5]; // [esp+9Ch] [ebp-34h] BYREF
  unsigned int v23; // [esp+B0h] [ebp-20h]
  __int64 v24; // [esp+B4h] [ebp-1Ch] BYREF
  int v25; // [esp+BCh] [ebp-14h]
  int v26; // [esp+CCh] [ebp-4h]

  v19 = 15;
  Block[4] = 0;
  LOBYTE(Block[0]) = 0;
  sub_11458A0(Block, ".bmp", 4u);
  v26 = 0;
  sub_1146D00((int)&v16, v3, Block, v17[0]);
  v26 = -1;
  if ( v19 >= 0x10 )
  {
    v4 = Block[0];
    if ( v19 + 1 >= 0x1000 )
    {
      if ( ((int)Block[0] & 0x1F) != 0 )
LABEL_4:
        _invalid_parameter_noinfo_noreturn();
      v5 = (void *)*((_DWORD *)Block[0] - 1);
      if ( v5 >= Block[0] )
        _invalid_parameter_noinfo_noreturn();
      if ( (unsigned int)(Block[0] - v5) < 4 )
        _invalid_parameter_noinfo_noreturn();
      if ( (unsigned int)(Block[0] - v5) > 0x23 )
        _invalid_parameter_noinfo_noreturn();
      v4 = (void *)*((_DWORD *)Block[0] - 1);
    }
    j_j___free_base(v4);
  }
  v24 = 0i64;
  v25 = 0;
  v26 = 1;
  sub_1145AA0(1, (char)"C:\\XX_CTF_XX\\", (int)&v24);
  for ( i = (_DWORD *)v24; i != (_DWORD *)HIDWORD(v24); i += 8 )// 遍歷文件進行加密
  {
    v7 = i[6];
    v8 = i[7];                                  // i應該是個結構體數組
                                                // i[0] 指向文件名
                                                // i[6]是文件長度
    v23 = 15;
    Src[4] = 0;
    LOBYTE(Src[0]) = 0;
    sub_1145580(Src, i, 0, 0xFFFFFFFF);         // 讀取文件或者校驗文件
                                                // 
    LOBYTE(v26) = 2;
    if ( v8 | v7 && v8 <= 0 )
    {
      if ( v7 <= 0x100000 )
      {
        sub_1146B70(v20, (int)Src);             // 創建一個新文件?
        memset(phProv, 0, sizeof(phProv));
        phProv[8] = 15;
        phProv[7] = 0;
        LOBYTE(phProv[3]) = 0;
        phProv[16] = 15;
        phProv[15] = 0;
        LOBYTE(phProv[11]) = 0;
        phProv[0] = 0;
        phProv[1] = 0;
        phProv[2] = 0;
        phProv[10] = 0;
        phProv[18] = 0;
        phProv[19] = 0;
        phProv[9] = 0;
        phProv[17] = 0;
        phProv[20] = 0;
        LOBYTE(v26) = 4;
        v9 = v20;
        if ( v20[5] >= (void *)0x10 )
          v9 = (void **)v20[0];
        v10 = Src;
        if ( v23 >= 0x10 )
          v10 = (void **)Src[0];
        if ( CryptAcquireContextA(phProv, 0, "Microsoft Enhanced RSA and AES Cryptographic Provider", 0x18u, 0xF0000000) )
        {
          if ( *(_BYTE *)v10 )
            v11 = strlen((const char *)v10);
          else
            v11 = 0;
          sub_11458A0(&phProv[3], v10, v11);
          if ( *(_BYTE *)v9 )
            v12 = strlen((const char *)v9);
          else
            v12 = 0;
          sub_11458A0(&phProv[11], v9, v12);
          sub_11418F0((int)phProv);             // 這里創建了key
                                                // 並進行了加密操作
          if ( phProv[10] )
            j_j_j___free_base((void *)phProv[10]);
          if ( phProv[18] )
            j_j_j___free_base((void *)phProv[18]);
          if ( phProv[19] )
            j_j_j___free_base((void *)phProv[19]);
          if ( phProv[1] )
            CryptDestroyKey(phProv[1]);
          if ( phProv[2] )
            CryptDestroyKey(phProv[2]);
          if ( phProv[0] )
            CryptReleaseContext(phProv[0], 0);
        }
        else
        {
          if ( phProv[10] )
            j_j_j___free_base((void *)phProv[10]);
          if ( phProv[18] )
            j_j_j___free_base((void *)phProv[18]);
          if ( phProv[19] )
            j_j_j___free_base((void *)phProv[19]);
          if ( phProv[1] )
            CryptDestroyKey(phProv[1]);
          if ( phProv[2] )
            CryptDestroyKey(phProv[2]);
          if ( phProv[0] )
            CryptReleaseContext(phProv[0], 0);
        }
        sub_11459A0(&phProv[11]);               // 釋放一些資源
        sub_11459A0(&phProv[3]);
        sub_11459A0(v20);
        LOBYTE(v26) = 1;
        sub_11459A0(Src);
      }
      else
      {
        LOBYTE(v26) = 1;
        sub_11459A0(Src);
      }
    }
    else
    {
      LOBYTE(v26) = 1;
      if ( v23 >= 0x10 )
      {
        v13 = Src[0];
        if ( v23 + 1 >= 0x1000 )
        {
          if ( ((int)Src[0] & 0x1F) != 0 )
            goto LABEL_4;
          v14 = (void *)*((_DWORD *)Src[0] - 1);
          if ( v14 >= Src[0] || (unsigned int)(Src[0] - v14) < 4 || (unsigned int)(Src[0] - v14) > 0x23 )
            goto LABEL_4;
          v13 = (void *)*((_DWORD *)Src[0] - 1);
        }
        j_j___free_base(v13);
      }
    }
  }
  sub_1146390(&v24);
  return 0;
}

重點看創建了key和加密部分的這個函數,跟進去:

char __thiscall sub_11418F0(int this)
{
  char v3; // bl
  int v4; // ecx
  BOOL v5; // eax
  int v6; // ecx
  unsigned int v7; // edi
  void *v8; // eax
  __int128 v9; // [esp+Ch] [ebp-84h] BYREF
  HCRYPTHASH phHash; // [esp+1Ch] [ebp-74h] BYREF
  int v11[23]; // [esp+20h] [ebp-70h] BYREF
  __int128 pbData; // [esp+7Ch] [ebp-14h] BYREF

  if ( !(unsigned __int8)sub_11410F0() )
    return 0;
  pbData = 0ui64;
  v9 = 0ui64;
  v11[0] = 0x67452301;                          // 這里像是key
                                                // 
  v11[1] = 0xEFCDAB89;
  v11[2] = 0x98BADCFE;
  v11[3] = 0x10325476;
  v11[4] = 0;
  v11[5] = 0;
  sub_1147290(0x41u);
  sub_11473F0(&v9, (int)v11);
  *(_QWORD *)&pbData = __PAIR64__(DWORD1(v9), HIDWORD(v9));
  HIDWORD(pbData) = v9;                         // 這里的具體操作是:
                                                // "0123456789abcdeffedcba9876543210" 轉碼:
                                                // v9="21e7b18e4fd4544b28c8aea3b22fc60e"
  DWORD2(pbData) = _time64(0);
  phHash = 0;
  v3 = 0;
  if ( CryptCreateHash(*(_DWORD *)this, 0x800Cu, 0, 0, &phHash) )// sha256
  {
    if ( CryptHashData(phHash, (const BYTE *)&pbData, 16u, 0) )// 應該是把key弄過去了
                                                // 對上面的16個字符進行sha256
    {
      v5 = CryptDeriveKey(*(_DWORD *)this, 0x660Eu, phHash, 0, (HCRYPTKEY *)(this + 4));// AES 660e
                                                // 
      v3 = 0;
      v4 = 1;
      if ( v5 )
        v3 = 1;
    }
  }
  if ( phHash )
    CryptDestroyHash(phHash);
  if ( !v3 )
    return 0;
  if ( !sub_11415D0((HCRYPTPROV *)this, v4) )   // 解密了一個公鑰?
                                                // 使用base64存的
                                                // 
    return 0;
  if ( !sub_1141700((void *)this, &pbData, v6) )// 加密
    return 0;
  v7 = 16 * ((*(_DWORD *)(this + 36) + 15) / 16 + 1);
  v8 = operator new[](v7, (const struct std::nothrow_t *)&unk_1175EB0);
  *(_DWORD *)(this + 72) = v8;
  if ( !v8 )
    return 0;
  memset(v8, 0, v7);
  memmove_0(*(void **)(this + 72), *(const void **)(this + 40), *(_DWORD *)(this + 36));
  if ( !sub_11417D0((_DWORD *)this) )           // 最后的對flag文件進行的加密
                                                // 
    return 0;
  sub_1141400((_DWORD *)this);                  // 寫文件
  return 1;
}

重點就是這個key是怎么來的,然后下面的aes 660e是查文檔知道的。

這個key有一部分是time(0)的時間戳,動調一下和輸入無關,這個地方我的第一想法是爆破,但是轉念一想好像沒必要,直接查了flag文件的創建時間就知道了時間戳,夾在里面就得到了key:

然后關注文件輸出的部分:

重點就是這三部分的內容,我自己寫flag試了一試,第一部分是文件加密的結果,第二部分是key加密的結果,key我們有了,不關心,最后還有4bytes的內容,也無所謂,最后直接對flag.bmp.ctf_encrypt解密然后去掉最后的東西就行了

腳本如下(寫的比較亂,很多測試數據在里面,將就一下):

from Crypto.Cipher import AES
import base64
import hashlib
import time 

# 字符類型的時間
tss1 = '2021-8-16 15:17:25'
tss1 = '2021-8-21 16:21:37'
timeArray = time.strptime(tss1, "%Y-%m-%d %H:%M:%S")
timeStamp = int(time.mktime(timeArray))
print(hex(timeStamp))


def fill(b, x):
	while len(b) % 16 != 0:
		b += x
	return b

#0x6120b08d
#0x611a1105 0x6120b791
# data= b'flag{12345678901234567890}'
data = b"\xa2K\x19.R\xac1\xcd0\xb1\x06\x86\t\x1b\x9d\xc1\xc854S\x88\x1a\x9a\xd9\xf0\xa1S\xc12\xa5.$\xadH\x03\x1fJ\xb5L'b\xdb'\x8cO4\xd4\x94"
data = open('flag.bmp.ctf_crypter','rb').read()
# key = bytes.fromhex('B22FC60E4FD4544B6bAE206121E7B18E')
#key = bytes.fromhex('B22FC60E4FD4544B8db0206121E7B18E')
key = bytes.fromhex('B22FC60E4FD4544B05111a6121E7B18E')  #flag
#key = bytes.fromhex('B22FC60E4FD4544B91b7206121E7B18E')
key = hashlib.new('sha256', key).digest()[:16]
print(key)
print(len(key))

aes = AES.new(key, AES.MODE_CBC, iv=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01')
_data = aes.decrypt(fill(data, b'\x00'))
#print(_data)
open('flag.bmp','wb').write(_data)

最后就是簡單的AES-CBC,但是我根據文件頭去掉多余信息以后圖片查看器還是打不開,但是ps能打開,就不管那么多了,直接拿flag:

Rev_Dizzy

簡單題,就是IDA會卡住,出來5000行代碼,對輸入進行+-^運算,把所有+換成-,-換成+,然后異或不變反着跑一下直接就能出來了,腳本太長不貼了,結果如下:

結語

后面還有一個macos的題,一個hardware的題,一個內核APC題,沒做出來,沒辦法,慢慢補了。

就這樣吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM