DASCTF 2024.8 RE非零解题 变化三维迷宫和c++异常处理
想成为安卓高手 发表于 湖北 CTF 160浏览 · 2024-11-06 17:28

Maze

题目分析

先查看main函数,可以输入6个方向,再看一下移动1,8,64就知道是一个三维的地图,且会一直移动直到遇到1.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+20h] [rbp-98h]
  char dir[112]; // [rsp+30h] [rbp-88h] BYREF

  v4 = 0;
  memset(dir, 0, 100);
  print((__int64)"Welcome to this sign in problem.\n", argv, envp);
  print((__int64)"Give me your input:");
  scanf("%s", dir);
  for ( i = 0; ; ++i )
  {
    if ( i >= strlen(dir) )
      wrong();
    Sleep(0x28u);
    switch ( dir[i] )
    {
      case 'a':
        while ( 1 )
        {
          if ( v4 % 8 - 1 < 0 )
            wrong();
          if ( *((_BYTE *)off_7FF63A4B6200 + v4 - 1) )
            break;
          --v4;
        }
        break;
      case 'd':
        while ( 1 )
        {
          if ( v4 % 8 + 1 >= 8 )
            wrong();
          if ( *((_BYTE *)off_7FF63A4B6200 + v4 + 1) )
            break;
          ++v4;
        }
        break;
      case 'n':
        while ( 1 )
        {
          if ( v4 - 64 < 0 )
            wrong();
          if ( *((_BYTE *)off_7FF63A4B6200 + v4 - 64) )
            break;
          v4 -= 64;
        }
        break;
      case 's':
        while ( 1 )
        {
          if ( v4 % 64 + 8 >= 64 )
            wrong();
          if ( *((_BYTE *)off_7FF63A4B6200 + v4 + 8) )
            break;
          v4 += 8;
        }
        break;
      case 'u':
        while ( 1 )
        {
          if ( v4 + 64 >= 512 )
            wrong();
          if ( *((_BYTE *)off_7FF63A4B6200 + v4 + 64) )
            break;
          v4 += 64;
        }
        break;
      case 'w':
        while ( 1 )
        {
          if ( v4 % 64 - 8 < 0 )
            wrong();
          if ( *((_BYTE *)off_7FF63A4B6200 + v4 - 8) )
            break;
          v4 -= 8;
        }
        break;
      default:
        wrong();
    }
    if ( v4 == 436 )
      break;
  }
  print((__int64)"Good job, the flag is md5_32_lower(your input)");
  return 0;
}

直接调试这个程序发现闪退,翻函数列表发现有TlsCallback回调函数。
这里对一个函数进行了解密。

int __fastcall TlsCallback_0(__int64 a1, int a2)
{
  int result; // eax
  int i; // [rsp+20h] [rbp-128h]
  DWORD flOldProtect[3]; // [rsp+24h] [rbp-124h] BYREF
  char v5[256]; // [rsp+30h] [rbp-118h] BYREF

  v5[0] = 27;
  v5[1] = -107;
  v5[2] = -120;
  v5[3] = -38;
  v5[4] = -112;
  v5[5] = -112;
  v5[6] = -87;
  v5[7] = -107;
  v5[8] = -98;
  v5[9] = -38;
  v5[10] = -112;
  v5[11] = -112;
  v5[12] = -28;
  v5[13] = -12;
  v5[14] = 27;
  v5[15] = -107;
  v5[16] = -106;
  v5[17] = -38;
  v5[18] = -112;
  v5[19] = -112;
  v5[20] = 25;
  v5[21] = -107;
  v5[22] = -108;
  v5[23] = -38;
  v5[24] = -112;
  v5[25] = -112;
  v5[26] = 19;
  v5[27] = -83;
  v5[28] = -103;
  v5[29] = -39;
  v5[30] = -112;
  v5[31] = -112;
  v5[32] = -111;
  v5[33] = -27;
  v5[34] = -102;
  v5[35] = 87;
  v5[36] = -44;
  v5[37] = -76;
  v5[38] = -80;
  v5[39] = -110;
  v5[40] = -112;
  v5[41] = -112;
  v5[42] = -112;
  v5[43] = 123;
  v5[44] = -104;
  v5[45] = 87;
  v5[46] = -44;
  v5[47] = -76;
  v5[48] = -80;
  v5[49] = -111;
  v5[50] = -112;
  v5[51] = -112;
  v5[52] = -112;
  v5[53] = 27;
  v5[54] = -44;
  v5[55] = -76;
  v5[56] = -80;
  v5[57] = 25;
  v5[58] = -107;
  v5[59] = 123;
  v5[60] = -40;
  v5[61] = -112;
  v5[62] = -112;
  v5[63] = 19;
  v5[64] = -83;
  v5[65] = 116;
  v5[66] = -40;
  v5[67] = -112;
  v5[68] = -112;
  v5[69] = -111;
  v5[70] = -27;
  v5[71] = -98;
  v5[72] = -40;
  v5[73] = 29;
  v5[74] = -107;
  v5[75] = 11;
  v5[76] = -44;
  v5[77] = -112;
  v5[78] = -112;
  v5[79] = -40;
  v5[80] = 25;
  v5[81] = -44;
  v5[82] = -76;
  v5[83] = -72;
  v5[84] = 123;
  v5[85] = -100;
  v5[86] = -40;
  v5[87] = 29;
  v5[88] = -107;
  v5[89] = 93;
  v5[90] = -42;
  v5[91] = -112;
  v5[92] = -112;
  v5[93] = -40;
  v5[94] = 25;
  v5[95] = -44;
  v5[96] = -76;
  v5[97] = -72;
  v5[98] = -40;
  v5[99] = 29;
  v5[100] = -107;
  v5[101] = 81;
  v5[102] = -42;
  v5[103] = -112;
  v5[104] = -112;
  v5[105] = -40;
  v5[106] = 27;
  v5[107] = -36;
  v5[108] = -76;
  v5[109] = -72;
  v5[110] = -40;
  v5[111] = 25;
  v5[112] = -40;
  v5[113] = 80;
  result = 0;
  memset(&v5[114], 0, 0x8Eui64);
  if ( a2 == 1 )
  {
    result = VirtualProtect(sub_7FF63A4B1A60, 0x2000ui64, 0x40u, flOldProtect);
    for ( i = 0; i < 114; ++i )
    {
      *((_BYTE *)sub_7FF63A4B1A60 + i + 182) ^= v5[i];
      result = i + 1;
    }
  }
  return result;
}

这里动调拿到解密完成后的反编译代码。

void __noreturn sub_7FF63A4B1A60()
{
  HANDLE CurrentThread; // rax
  HANDLE CurrentProcess; // rax
  int v2; // [rsp+20h] [rbp-508h]
  _QWORD *v3; // [rsp+28h] [rbp-500h]
  HMODULE hModule; // [rsp+30h] [rbp-4F8h]
  FARPROC ProcAddress; // [rsp+38h] [rbp-4F0h]
  struct _CONTEXT Context; // [rsp+40h] [rbp-4E8h] BYREF

  while ( 1 )
  {
    hModule = GetModuleHandleA("Ntdll");
    ProcAddress = GetProcAddress(hModule, aS_0);
    memset(&Context, 0, sizeof(Context));
    Context.ContextFlags = 1048592;
    CurrentThread = GetCurrentThread();
    GetThreadContext(CurrentThread, &Context);
    if ( Context.Dr0 || Context.Dr1 || Context.Dr2 || Context.Dr3 )
    {
      CurrentProcess = GetCurrentProcess();
      ((void (__fastcall *)(HANDLE, _QWORD))ProcAddress)(CurrentProcess, 0i64);
    }
    if ( i != i1 )
    {
      i1 = i;
      if ( dword_7FF63A4B6440 == 1 )
        v2 = 2;
      else
        v2 = 1;
      dword_7FF63A4B6440 = v2;
      if ( v2 == 1 )
        v3 = &unk_7FF63A4B6000;
      else
        v3 = qword_7FF63A4B6240;
      qword_7FF63A4B6240[-8] = v3;
    }
    Sleep(1u);
  }
}

这里有一个反调试(检测硬件断点,检测到了就调用Ntdll库的ZwTerminateProcess函数)。
它会隔一次切换一次地图,而416这个终点的位置在map2。

另外发现原本上面的字符发生了改变,查一下交叉引用发现另一个反调试的函数

__int64 __fastcall sub_7FF63A4B1810(__int64 a1)
{
  HANDLE CurrentThread; // rax
  int i; // [rsp+20h] [rbp-28h]
  int j; // [rsp+20h] [rbp-28h]
  int k; // [rsp+20h] [rbp-28h]
  HMODULE hModule; // [rsp+28h] [rbp-20h]
  FARPROC ProcAddress; // [rsp+30h] [rbp-18h]

  for ( i = 0; i < 5; ++i )
    aNtdll[i] = (aNtdll[i] - 100) ^ 0x55;
  for ( j = 0; j < 22; ++j )
    ProcName[j] = (ProcName[j] - 100) ^ 0x55;
  for ( k = 0; k < 18; ++k )
    aS_0[k] = (aS_0[k] - 100) ^ 0x55;
  hModule = GetModuleHandleA("Ntdll");
  ProcAddress = GetProcAddress(hModule, ProcName);
  CurrentThread = GetCurrentThread();
  ((void (__fastcall *)(HANDLE, __int64, _QWORD, _QWORD))ProcAddress)(CurrentThread, 17i64, 0i64, 0i64);
  return a1;
}

那就是走两个切换的迷宫,据此写出脚本

exp

map1 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
map2 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]


def dfs(cnt, pos, path):
    # 设置最大深度
    if cnt > 15:
        return
    if pos == 436:
        print(path)
    if cnt % 2 == 0:
        maze = map1
    else:
        maze = map2
    # a
    pos1 = pos
    if maze[pos - 1] != 1:
        while 1:
            if pos1 % 8 == 0:
                break
            if maze[pos1-1] == 1:
                dfs(cnt + 1, pos1, path + 'a')
            pos1 -= 1
    # d
    pos2 = pos
    if maze[pos + 1] != 1:
        while 1:
            if pos2 % 8 == 7:
                break
            if maze[pos2+1] == 1:
                dfs(cnt + 1, pos2, path + 'd')
            pos2 += 1
    # n
    pos3 = pos
    if maze[pos - 64] != 1:
        while 1:
            if pos3 < 64:
                break
            if maze[pos3-64] == 1:
                dfs(cnt + 1, pos3, path + 'n')
            pos3 -= 64
    # u
    pos4 = pos
    if maze[pos + 64] != 1:
        while 1:
            if pos4 + 64 >= 512:
                break
            if maze[pos4+64] == 1:
                dfs(cnt + 1, pos4, path + 'u')
            pos4 += 64
    # s
    pos5 = pos
    if maze[pos + 8] != 1:
        while 1:
            if pos5 % 64 >= 56:
                break
            if maze[pos5+8] == 1:
                dfs(cnt + 1, pos5, path + 's')
            pos5 += 8
    # w
    pos6 = pos
    if maze[pos - 8] != 1:
        while 1:
            if pos6 % 64 < 8:
                break
            if maze[pos6-8] == 1:
                dfs(cnt + 1, pos6, path + 'w')
            pos6 -= 8

dfs(0, 0, '')

得到路径sdwusanwduawus

flag:

DASCTF{1bb5fd78f2299f26ccc0630c5e7516b6}

ezcpp

题目分析

进入主函数
这里把输入转为了两个32位的数,可以猜到只接收了8个字符的输入。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  void *v3; // rax
  __int64 input_ur_flag; // rax
  char v6[8]; // [rsp+20h] [rbp-188h] BYREF
  void (__fastcall ***v7)(unsigned __int8 (__fastcall ***)(_QWORD)); // [rsp+28h] [rbp-180h]
  int v8; // [rsp+30h] [rbp-178h]
  _QWORD *v9; // [rsp+38h] [rbp-170h]
  __int64 *v10; // [rsp+40h] [rbp-168h]
  _QWORD *v11; // [rsp+48h] [rbp-160h]
  struct _TEB *v12; // [rsp+50h] [rbp-158h]
  struct _PEB *ProcessEnvironmentBlock; // [rsp+58h] [rbp-150h]
  void *Block; // [rsp+68h] [rbp-140h]
  __int64 v15; // [rsp+70h] [rbp-138h]
  char Src[24]; // [rsp+78h] [rbp-130h] BYREF
  __crt_locale_pointers input[17]; // [rsp+90h] [rbp-118h] BYREF

  v8 = 1;
  v12 = NtCurrentTeb();
  memset(input, 0, 0x100ui64);
  memset(v6, 0, 1ui64);
  v3 = j_memcpy(v6, Src, (size_t)envp);
  input_ur_flag = j_j_xor((__int64)v3);
  sub_7FF628672A40(std::cout, input_ur_flag);
  mbstrlen_l(std::cin, input);
  input1 = SBYTE3(input[0].locinfo) | (SBYTE2(input[0].locinfo) << 8) | (SBYTE1(input[0].locinfo) << 16) | (SLOBYTE(input[0].locinfo) << 24);
  input2 = SHIBYTE(input[0].locinfo) | (SBYTE6(input[0].locinfo) << 8) | (SBYTE5(input[0].locinfo) << 16) | (SBYTE4(input[0].locinfo) << 24);
  v9 = operator new(8ui64);
  if ( v9 )
  {
    memset(v9, 0, sizeof(_QWORD));
    v11 = sub_7FF6286721E0(v9);
  }
  else
  {
    v11 = 0i64;
  }
  v7 = (void (__fastcall ***)(unsigned __int8 (__fastcall ***)(_QWORD)))v11;
  v10 = (__int64 *)unknown_libname_17((__int64)v11);
  v15 = *v10;
  sub_7FF628671B20((__int64)v10, (__int64)sub_7FF628671A60, 0);
  (**v7)((unsigned __int8 (__fastcall ***)(_QWORD))v7);
  ProcessEnvironmentBlock = v12->ProcessEnvironmentBlock;
  if ( ProcessEnvironmentBlock->BeingDebugged == 1 )
    exit(0);
  sub_7FF628671B20((__int64)v10, (__int64)call_exception, 0);
  if ( ((unsigned __int8 (__fastcall *)(_QWORD))**v7)(v7) )
    sub_7FF628671080("YES!!");
  else
    sub_7FF628671080("Failed..");
  Block = v7;
  j_j_free(v7);
  system("pause");
  return 0;
}

这里打印的信息都是从内存中读取数据再进行xor操作得到的,包括后面的获取密文也是需要xor操作。
然后进行了hook操作,调用了sub_7FF628671A60和call_exception函数。
sub_7FF628671A60函数产生了异常,但是tab键看汇编并没有找到异常处理代码,仅仅用来抛出异常,让主函数进入异常处理。

void __noreturn sub_7FF628671A60()
{
  char pExceptionObject[40]; // [rsp+20h] [rbp-28h] BYREF

  sub_7FF6286715D0(pExceptionObject, "Memory allocation failed");
  CxxThrowException(pExceptionObject, (_ThrowInfo *)&_TI2_AVruntime_error_std__);
}

call_exception产生了除0异常。

_BOOL8 call_exception()
{
  return 5 / 0 != 0;
}

观察汇编可以看到一场处理调用了sub_7FF628671BA0这个函数并将之前由输入获得的两个32位数字传入作为参数。


进入这个函数,发现又抛出了异常,并且这里还执行了qmemcpy(v2, &unk_7FF628678090, 0x130ui64);这个操作。

char sub_7FF628671BA0()
{
  __int64 v0; // rax
  void *v2; // [rsp+28h] [rbp-E0h]
  char pExceptionObject[24]; // [rsp+60h] [rbp-A8h] BYREF

  v2 = VirtualAlloc(0i64, 0x130ui64, 0x3000u, 0x40u);
  if ( v2 )
  {
    qmemcpy(v2, &unk_7FF628678090, 0x130ui64);
    sub_7FF6286715D0(pExceptionObject, "Memory allocation failed");
    CxxThrowException(pExceptionObject, (_ThrowInfo *)&_TI2_AVruntime_error_std__);
  }
  v0 = sub_7FF628672A40(std::cerr, (__int64)"Memory allocation failed");
  std::ostream::operator<<(v0, sub_7FF628672DA0);
  return 1;
}

汇编找到异常处理,将unk_7FF628678090的值xor了0xDA。


这里脚本跑一下,发现最后的数据是0xcc就可以看出来是个函数。

import idc   
ea_start=0x7FF628678090
for i in range(304):
    tmp = idc.get_bytes(ea_start+i,1)
    tmp = 0xda ^ ord(tmp)
    idc.patch_byte(ea_start+i,tmp)
print("ok")

得到的函数反编译结果:是个魔改的xtea,重命名函数为xtea

再看sub_7FF628671BA0的汇编,在异常处理之后果然有调用xtea这个函数。


这里改一下汇编,再看sub_7FF628671BA0的反编译。

// positive sp value has been detected, the output may be wrong!
bool __fastcall sub_7FF628671BA0(int a1, int a2)
{
  __int64 v2; // rbp
  __int64 v3; // rdx
  __int64 v4; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  _QWORD v10[3]; // [rsp-28h] [rbp-138h] BYREF
  __int64 v11; // [rsp-10h] [rbp-120h]
  __int64 v12; // [rsp-8h] [rbp-118h]
  __int64 v13; // [rsp+0h] [rbp-110h]
  unsigned __int64 (__fastcall *v14)(unsigned int, unsigned int, int); // [rsp+8h] [rbp-108h]
  unsigned __int64 (__fastcall *v15)(unsigned int, unsigned int, int); // [rsp+10h] [rbp-100h]
  __int64 v16; // [rsp+30h] [rbp-E0h] BYREF
  __int64 v17; // [rsp+50h] [rbp-C0h] BYREF
  __int64 v18; // [rsp+70h] [rbp-A0h] BYREF
  _BYTE v19[75]; // [rsp+85h] [rbp-8Bh] BYREF
  unsigned int v20; // [rsp+D0h] [rbp-40h]
  int v21; // [rsp+F0h] [rbp-20h]
  int v22; // [rsp+F8h] [rbp-18h]

  v22 = a2;
  v21 = a1;
  v14 = (unsigned __int64 (__fastcall *)(unsigned int, unsigned int, int))VirtualAlloc(0i64, 0x130ui64, 0x3000u, 0x40u);
  if ( v14 )
  {
    qmemcpy(v14, xtea, 0x130ui64);
    v15 = 0i64;
    v11 = v3;
    v10[0] = v2;
    *(_QWORD *)(v3 + 48) = *(_QWORD *)(v3 + 40);
    for ( *(_DWORD *)(v3 + 36) = 0; *(int *)(v3 + 36) < 304; ++*(_DWORD *)(v3 + 36) )
      *(_BYTE *)(*(_QWORD *)(v3 + 40) + *(int *)(v3 + 36)) ^= 0xDAu;
    v11 = ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))v10[2])(
            *(unsigned int *)&v19[67],
            v20,
            (unsigned int)dword_7FF628678378);
    memset(v10, 0, 1ui64);
    v12 = ((__int64 (__fastcall *)(__int64 *, __int64))sub_7FF628671820)(&v16, v11);
    v13 = v12;
    v6 = ((__int64 (__fastcall *)(_QWORD *, __int64 *))sub_7FF628671DE0)(v10, &v18);
    v7 = ((__int64 (__fastcall *)(__int64))sub_7FF628672290)(v6);
    BYTE1(v10[0]) = ((__int64 (__fastcall *)(__int64, __int64))sub_7FF628672DF0)(v13, v7);
    ((void (__fastcall *)(__int64 *))sub_7FF628672310)(&v16);
    if ( BYTE1(v10[0]) )
    {
      return 1;
    }
    else
    {
      memset((char *)v10 + 2, 0, sizeof(char));
      v14 = (unsigned __int64 (__fastcall *)(unsigned int, unsigned int, int))((__int64 (__fastcall *)(__int64 *, __int64))sub_7FF628671820)(
                                                                                &v17,
                                                                                v11);
      v15 = v14;
      v8 = ((__int64 (__fastcall *)(char *, _BYTE *))sub_7FF628671E80)((char *)v10 + 2, v19);
      v9 = ((__int64 (__fastcall *)(__int64))sub_7FF628672250)(v8);
      BYTE3(v10[0]) = ((__int64 (__fastcall *)(unsigned __int64 (__fastcall *)(unsigned int, unsigned int, int), __int64))sub_7FF628672DF0)(
                        v15,
                        v9);
      ((void (__fastcall *)(__int64 *))sub_7FF628672310)(&v17);
      return BYTE3(v10[0]) != 0;
    }
  }
  else
  {
    v4 = sub_7FF628672A40(std::cerr, (__int64)"Memory allocation failed");
    std::ostream::operator<<(v4, sub_7FF628672DA0);
    return 1;
  }
}

其中这里是调用xtea函数,前两个参数是我们之前传入的input1和input2,也就是那两个32位数。那么第三个参数是什么呢。


动态调试的过程中,这里有一处很明显的反调试,但是我们调试时并没有退出。


查看这里的汇编,产生了异常并且发生了异常处理,导致没有exit,而这里将ProcessEnvironmentBlock->BeingDebugged的值赋给了cs: dword_7FF628678378,也就是我们刚刚xtea的第三个参数。


现在,就只差密文就可以解密了,在sub_7FF628671BA0函数里面,有两处xor产生密文并将密文字符形式转为二进制形式,这两个密文分别对应ProcessEnvironmentBlock->BeingDebugged等于0和等于1的情况,也就是调试和非调试情况。这里直接解非调试情况下的明文提交不正确,8位作为flag也确实太短了,再解调试情况下的明文,将两个输入拼接起来就是flag

exp

enc = b"6?<82>967 4:1=??468$\a"
mes = ""
for i in range(len(enc)):
    mes += chr(enc[i] ^ (i % 10 + 7))
print(mes)
enc = [  0x32, 0x36, 0x35, 0x33, 0x32, 0x34, 0x36, 0x34, 0x37, 0x35, 
  0x33, 0x32, 0x33, 0x34, 0x32, 0x36, 0x35, 0x36, 0x35, 0x30, 
  0x03]
mes = ""
for i in range(len(enc)):
    mes += chr(enc[i] ^ (i % 5 + 3))
print(mes)
from struct import pack

def decry(debuggerpresent, enc):
    prev = (enc ^ debuggerpresent) >> 32
    next = (enc ^ debuggerpresent) & 0xffffffff
    key = [0x42CA4455, 0x8E0AE93B, 0xA569C4D0, debuggerpresent + 0x523A855B]
    sum = 0xF3E56 * 32 & 0xffffffff

    for i in range(32):
        next -= (key[sum >> 11 & 3] + sum) ^ (prev + ((prev >> 5) ^ (prev << 4)))
        next &= 0xffffffff
        sum -= 0xF3E56
        sum &= 0xffffffff
        prev -= (key[sum & 3] + sum) ^ (next + ((next >> 5) ^ (16 * next)))
        prev &= 0xffffffff
    print(pack('>I', prev) + pack('>I', next))
decry(0, 17529248803287439874)
decry(1, 12055721120662551337)

flag

解密得到两个字符串,把他们拼接在一起,再用DASCTF{}包裹:DASCTF{G0g3tTea7up@fT3A}

0 条评论
某人
表情
可输入 255