LuckyStar hctf2018

LuckyStar hctf2018

程序注册有TLS回调函数

char __stdcall TlsCallback_0(int a1, int a2, int a3)
{
  char result; // al
  HMODULE v4; // eax
  HMODULE v5; // eax
  HMODULE v6; // eax
  int (__usercall *ptr_main)@<eax>(int@<ebp>); // esi
  signed int v8; // edi
  HANDLE v9; // eax

  result = a2;
  if ( a2 == 1 )
  {
    v4 = GetModuleHandleA("ntdll.dll");
    dword_407378 = sub_401360(v4, "a7d7bcc95a86a6df3b0a1ccb3c69d440");//此处应该是获取库中的某个函数,我们动态调试的时候看一下
    v5 = GetModuleHandleA("ntdll.dll");
    dword_407380 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))sub_401360(v5, "8eb35a28209979fe6a9983cff0d23c5a");
    v6 = GetModuleHandleA("kernel32.dll");
    dword_407374 = sub_401360(v6, "05577e1568efa10b8166728bfb414c59");
    srand(0x61616161u);//设置随机数的种子(影响后面main函数中的rand)
    ptr_main = main_401780;//main函数,IDA载入发现已经加密,无法正常解析。
    v8 = 440;
    do
    {
      ptr_main = (int (__usercall *)@<eax>(int@<ebp>))((char *)ptr_main + 1);
      result = byte_417000[rand() % 8216];
      *((_BYTE *)ptr_main - 1) ^= result;//对main进行异或解密
      --v8;
    }
    while ( v8 );
  }
  else if ( a2 == 3 )
  {
    v9 = GetCurrentThread();
    result = dword_407380(v9, 17, 0, 0);
  }
  return result;
}

我们动态调试,查看前面要用到库中的哪些函数,并且在main函数解密完成后dump文件,以备后面IDA分析。

 发现前面获取的库函数与反调试相关。

重命名后的TLS

char __stdcall TlsCallback_0(int a1, int a2, int a3)
{
  char result; // al
  HMODULE v4; // eax
  HMODULE v5; // eax
  HMODULE v6; // eax
  int (__usercall *ptr_main)@<eax>(int@<ebp>); // esi
  signed int v8; // edi
  HANDLE v9; // eax

  result = a2;
  if ( a2 == 1 )
  {
    v4 = GetModuleHandleA("ntdll.dll");
    NtQuerySystemInformation = sub_401360((int)v4, "a7d7bcc95a86a6df3b0a1ccb3c69d440");
    v5 = GetModuleHandleA("ntdll.dll");
    NtSetInformationThread = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))sub_401360(
                                                                                  (int)v5,
                                                                                  "8eb35a28209979fe6a9983cff0d23c5a");
    v6 = GetModuleHandleA("kernel32.dll");
    *(_DWORD *)CheckRemoteDebuggerPresent = sub_401360((int)v6, "05577e1568efa10b8166728bfb414c59");
    srand(0x61616161u);
    ptr_main = main_401780;
    v8 = 440;
    do
    {
      ptr_main = (int (__usercall *)@<eax>(int@<ebp>))((char *)ptr_main + 1);
      result = byte_417000[rand() % 8216];
      *((_BYTE *)ptr_main - 1) ^= result;
      --v8;
    }
    while ( v8 );
  }
  else if ( a2 == 3 )
  {
    v9 = GetCurrentThread();
    result = NtSetInformationThread(v9, 17, 0, 0);
  }
  return result;
}
View Code

IDA分析mian解密完成时dump的文件

int __usercall sub_401780@<eax>(int a1@<ebp>, int a2@<edi>, int a3@<esi>)
{
  signed int v3; // esi
  int v4; // ST08_4
  int v5; // ST0C_4
  int v6; // ST10_4
  int v7; // ST14_4
  int v8; // ST18_4
  int v9; // ST1C_4
  int v10; // ST20_4
  int v11; // ST24_4
  int v12; // ST28_4
  int v13; // ST2C_4
  int v14; // ecx
  const char *v15; // eax
  int v17; // [esp-CCh] [ebp-D8h]
  int v18; // [esp-C8h] [ebp-D4h]
  int v19; // [esp-C4h] [ebp-D0h]
  int v20; // [esp-C0h] [ebp-CCh]
  int v21; // [esp-BCh] [ebp-C8h]
  int v22; // [esp-B8h] [ebp-C4h]
  int v23; // [esp-B4h] [ebp-C0h]
  int v24; // [esp-B0h] [ebp-BCh]
  int v25; // [esp-ACh] [ebp-B8h]
  int v26; // [esp-A8h] [ebp-B4h]
  int v27; // [esp-A4h] [ebp-B0h]
  int v28; // [esp-A0h] [ebp-ACh]
  int v29; // [esp-9Ch] [ebp-A8h]
  int v30; // [esp-98h] [ebp-A4h]
  int v31; // [esp-94h] [ebp-A0h]
  int v32; // [esp-90h] [ebp-9Ch]
  int v33; // [esp-8Ch] [ebp-98h]
  int v34; // [esp-88h] [ebp-94h]
  int v35; // [esp-84h] [ebp-90h]
  int v36; // [esp-80h] [ebp-8Ch]
  int v37; // [esp-7Ch] [ebp-88h]
  int v38; // [esp-78h] [ebp-84h]
  int v39; // [esp-74h] [ebp-80h]
  int v40; // [esp-70h] [ebp-7Ch]
  int v41; // [esp-6Ch] [ebp-78h]
  int v42; // [esp-68h] [ebp-74h]
  int v43; // [esp-64h] [ebp-70h]
  int v44; // [esp-60h] [ebp-6Ch]
  int v45; // [esp-5Ch] [ebp-68h]
  int v46; // [esp-58h] [ebp-64h]
  int v47; // [esp-54h] [ebp-60h]
  int v48; // [esp-50h] [ebp-5Ch]
  int v49; // [esp-4Ch] [ebp-58h]
  int v50; // [esp-48h] [ebp-54h]
  int v51; // [esp-44h] [ebp-50h]
  int v52; // [esp-40h] [ebp-4Ch]
  int v53; // [esp-3Ch] [ebp-48h]
  int v54; // [esp-38h] [ebp-44h]
  int v55; // [esp-34h] [ebp-40h]
  __int128 v56; // [esp-30h] [ebp-3Ch]
  __int64 v57; // [esp-20h] [ebp-2Ch]
  int v58; // [esp-18h] [ebp-24h]
  __int16 v59; // [esp-14h] [ebp-20h]
  unsigned int v60; // [esp-4h] [ebp-10h]
  int v61; // [esp+0h] [ebp-Ch]
  int v62; // [esp+4h] [ebp-8h]
  int retaddr; // [esp+Ch] [ebp+0h]

  v61 = a1;
  v62 = retaddr;
  v60 = (unsigned int)&v61 ^ __security_cookie;
  v17 = a3;
  CreateThread(0, 0, StartAddress, 0, 0, 0);    // 播放歌曲,
  printf_401020("%s
", (unsigned int)aMmmmmmmmmmmmmm);
  while ( !song_final_sign_40737C )
  {
    Sleep(0x7D0u);
    printf_401020(">");
  }
  printf_401020("
");
  v3 = 0;
  do
    *((_BYTE *)&loc_4015E0 + v3++) ^= byte_417000[rand() % 8216];// main中解密输入的加密处理函数
  while ( v3 < 383 );
  printf_401020("Shining!
", a2, v17);
  system("cls");
  v58 = 0;
  v56 = 0i64;
  v57 = 0i64;
  v59 = 0;
  memset(&v38, 0, 0x46u);
  printf_401020("My Darling Darling Please!
input your key!
");
  scanf_401050("%29s", &v56);
  ((void (__stdcall *)(__int128 *, int *, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, _DWORD))loc_4015E0)(
    &v56,
    &v38,
    v4,
    v5,
    v6,
    v7,
    v8,
    v9,
    v10,
    v11,
    v12,
    v13,
    v18,
    v19,
    v20,
    v21,
    v22,
    v23,
    v24,
    v25,
    v26,
    v27,
    v28,
    v29,
    v30,
    v31,
    v32,
    v33,
    v34,
    v35,
    v36,
    v37,
    v38,
    v39,
    v40,
    v41,
    v42,
    v43,
    v44,
    v45,
    v46,
    v47,
    v48,
    v49,
    v50,
    v51,
    v52,
    v53,
    v54,
    v55,
    v56);
  *(_OWORD *)&v20 = xmmword_403520;             // 0DEF0A07232EEBC954C11473ABD57E649
  *(_OWORD *)&v24 = xmmword_403530;             // 5CCC8CA3C67C5A6A96E49835683F2AC
  v36 = 0;
  LOWORD(v37) = 0;
  *(_OWORD *)&v28 = 0i64;
  *(_OWORD *)&v32 = 0i64;
  v14 = strcmp((const char *)&v38, (const char *)&v20);
  if ( v14 )
    v14 = -(v14 < 0) | 1;
  v15 = "Maybe next year";
  if ( !v14 )
    v15 = "Nice Job~";
  printf_401020(v15);
  system("pause");
  return 0;
}

发现main中对loc_4015E0函数进行了解密,后面用他来加密输入。动态调试,解密后dump

loc_4015E0函数

char __cdecl encode_4015E0(const char *myinput, const char *en_temp)
{
  int v2; // esi
  unsigned int size; // kr00_4
  signed int v4; // edi
  int v5; // ecx
  const char *v6; // eax
  int v7; // eax
  char v8; // al
  int v9; // ecx
  int v10; // ecx
  unsigned int v11; // ecx
  int v12; // eax
  char v13; // al
  signed int v14; // edi
  char result; // al
  signed int v16; // esi
  char v17; // al
  char v18; // cl
  signed int v19; // [esp+Ch] [ebp-8h]
  signed int v20; // [esp+10h] [ebp-4h]

  v2 = 0;
  size = strlen(myinput);
  v4 = 0;
  v20 = 4 * size / 3;
  if ( v20 > 0 )
  {
    do
    {
      v5 = v4 & 3;
      if ( v4 & 3 )
      {
        v8 = myinput[v2 - 1];
        if ( v5 == 1 )
        {
          v9 = myinput[v2++];
          v7 = (v9 >> 4) | 16 * (v8 & 3);
        }
        else if ( v5 == 2 )
        {
          v10 = myinput[v2++];
          v7 = (v10 >> 6) | 4 * (v8 & 0xF);
        }
        else
        {
          v7 = v8 & 0x3F;
        }
      }
      else
      {
        v6 = &myinput[v2++];
        v7 = *v6 >> 2;
      }
      en_temp[v4++] = base64_table_4033C8[v7];  // abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/
    }                          
    while ( v4 < v20 );
  }
  if ( strlen(myinput) % 3 == 1 )
  {
    v11 = 4 * size / 3;
    v12 = 16 * (myinput[v2 - 1] & 3);
    *(_WORD *)&en_temp[v20 + 1] = '==';
    v13 = base64_table_4033C8[v12];            //魔改base64,编码表将大写字母与小写字母替换了位置。
  }
  else
  {
    if ( strlen(myinput) % 3 != 2 )
      goto LABEL_15;
    v11 = 4 * size / 3;
    v13 = base64_table_4033C8[4 * (myinput[v2 - 1] & 0xF)];
    en_temp[v20 + 1] = 61;
  }
  en_temp[v11] = v13;
LABEL_15:
  en_temp[strlen(en_temp)] = 0;
  v14 = 0;
  v19 = strlen(en_temp);
  if ( v19 > 0 )
  {
    do
    {
      v16 = 6;
      do
      {
        v17 = rand() % 4;
        v18 = v16;
        v16 -= 2;
        result = v17 << v18;
        en_temp[v14] ^= result;                 // 获取伪随机序列,输入进行魔改base64编码后与伪随机序列进行了异或操作。
      }
      while ( v16 > -2 );
      ++v14;
    }
    while ( v14 < v19 );
  }
  return result;
}

最终main函数

int __usercall sub_401780@<eax>(int a1@<ebp>)
{
  signed int v1; // esi
  int v2; // ecx
  const char *v3; // eax
  __int128 tg; // [esp-C0h] [ebp-CCh]
  __int128 v6; // [esp-B0h] [ebp-BCh]
  __int128 v7; // [esp-A0h] [ebp-ACh]
  __int128 v8; // [esp-90h] [ebp-9Ch]
  int v9; // [esp-80h] [ebp-8Ch]
  __int16 v10; // [esp-7Ch] [ebp-88h]
  int temp_str; // [esp-78h] [ebp-84h]
  __int128 myinput; // [esp-30h] [ebp-3Ch]
  __int64 v13; // [esp-20h] [ebp-2Ch]
  int v14; // [esp-18h] [ebp-24h]
  __int16 v15; // [esp-14h] [ebp-20h]
  unsigned int v16; // [esp-4h] [ebp-10h]
  int v17; // [esp+0h] [ebp-Ch]
  int v18; // [esp+4h] [ebp-8h]
  int retaddr; // [esp+Ch] [ebp+0h]

  v17 = a1;
  v18 = retaddr;
  v16 = (unsigned int)&v17 ^ __security_cookie;
  printf_401020("%s
", aMmmmmmmmmmmmmm);
  printf_401020("
");
  v1 = 0;
  do
    *((_BYTE *)encode_4015E0 + v1++) ^= byte_417000[rand() % 8216];
  while ( v1 < 383 );
  printf_401020("Shining!
");
  system("cls");
  v14 = 0;
  myinput = 0i64;
  v13 = 0i64;
  v15 = 0;
  memset(&temp_str, 0, 0x46u);
  printf_401020("My Darling Darling Please!
input your key!
");
  scanf_401050("%29s", &myinput);
  encode_4015E0((const char *)&myinput, (const char *)&temp_str);// 魔改base64编码 +异或伪随机序列
  tg = xmmword_403520;                          // 0DEF0A07232EEBC954C11473ABD57E649
  v6 = xmmword_403530;                          // 5CCC8CA3C67C5A6A96E49835683F2AC
  v9 = 0;
  v10 = 0;
  v7 = 0i64;
  v8 = 0i64;
  v2 = strcmp((const char *)&temp_str, (const char *)&tg);// {
                                                // 0x49, 0xE6, 0x57, 0xBD, 0x3A, 0x47, 0x11, 0x4C, 0x95, 0xBC, 0xEE, 0x32, 0x72, 0xA0, 0xF0, 0xDE,
                                                // 0xAC, 0xF2, 0x83, 0x56, 0x83, 0x49, 0x6E, 0xA9, 0xA6, 0xC5, 0x67, 0x3C, 0xCA, 0xC8, 0xCC, 0x05
                                                // };
  if ( v2 )
    v2 = -(v2 < 0) | 1;
  v3 = "Maybe next year";
  if ( !v2 )
    v3 = "Nice Job~";
  printf_401020(v3);
  system("pause");
  return nullsub_2((unsigned int)&v17 ^ v16);
}

魔改base64与标准base64编码只存在字母大小写的不同,好解决,关键在于后面与伪随机序列的获取。

方案1、动态调试,在base64编码后,进行异或操作时,编写脚本,将每一位异或数据记录下来。

方案2、先获取魔改base64编码后的结果,然后在函数结束后获得异或加密结果,将二者进行异或,便可得到得到伪随机序列

程序最后将输入的加密结果进行比较,动态调试时dump比较数据。

wp:

import base64
tg=[0x49, 0xE6, 0x57, 0xBD, 0x3A, 0x47, 0x11, 0x4C, 0x95, 0xBC, 0xEE, 0x32, 0x72, 0xA0, 0xF0, 0xDE,
0xAC, 0xF2, 0x83, 0x56, 0x83, 0x49, 0x6E, 0xA9, 0xA6, 0xC5, 0x67, 0x3C, 0xCA, 0xC8, 0xCC, 0x05]
order=[0x08,0x81,0x39,0x8d,0x40,0x09,0x42,0x14,0xd0,0xf2,0x98,0x66,0x33,0xd6,0xc9,0xb2,0xc1,0x95,0xb6,0x1e,0xc7,0x2d,0x1c,0xef,0xd2,0xb2,0x5f,0x66,0x8c,0xb9,0xf1,0x38,0x14,0x08,0x8f,0xce,0xe9,0x7f,0x0d,0x05,]

b64=''
for i in range(len(tg)):
    b64+=chr(order[i]^tg[i])
print(b64)
t=''
for c in b64:
    n=ord(c)
    if n>=ord('A') and n<=ord('Z'):
        t+=chr(n|0x20)
    elif n>=ord('a') and n<=ord('z'):
        t+=chr(n&0xdf)
    else:
        t+=c
print(t)
flag=base64.b64decode(t.encode()).decode()
print(flag)

hctf{1zumi_K0nat4_Mo3}

攻防世界里提交失败 0.0 Orz

原文地址:https://www.cnblogs.com/DirWang/p/12289016.html