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题,没做出来,没办法,慢慢补了。

就这样吧。

posted @ 2021-08-22 13:31  Mz1  阅读(517)  评论(0编辑  收藏  举报