手脱壳 base64

能看到是ASProtect壳 然后程序入口还有pushad 我们直接使用esp定律来脱壳

image

脱壳完成后

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Buffer[1024]; // [esp+8h] [ebp-C04h] BYREF
  char v5[1024]; // [esp+408h] [ebp-804h] BYREF
  char v6[1024]; // [esp+808h] [ebp-404h] BYREF

  memset(v5, 0, sizeof(v5));
  memset(v6, 0, sizeof(v6));
  printf("input code:");
  scanf("%s", v5);
  if ( !sub_7511F0(v5) )
  {
    printf("invalid input\n");
    exit(0);
  }
  sub_751240(v6);
  memset(Buffer, 0, sizeof(Buffer));
  sprintf(Buffer, "DDCTF{%s}", v6);
  if ( !strcmp(Buffer, aDdctfReverse) )
    printf("You've got it !!! %s\n", Buffer);
  else
    printf("Something wrong. Try again...\n");
  return 0;
}

很简单的操作 一个数字和大写字符判断

char __usercall sub_7511F0@<al>(const char *a1@<esi>)
{
  int v1; // eax
  int v2; // edx
  int v3; // ecx
  char v4; // al

  v1 = strlen(a1);
  v2 = v1;
  if ( v1 && v1 % 2 != 1 )
  {
    v3 = 0;
    if ( v1 <= 0 )
      return 1;
    while ( 1 )
    {
      v4 = a1[v3];
      if ( (v4 < '0' || v4 > '9') && (v4 < 'A' || v4 > 'F') )
        break;
      if ( ++v3 >= v2 )
        return 1;
    }
  }
  return 0;
}

加密函数

int __usercall sub_751240@<eax>(const char *a1@<esi>, int a2)
{
  int v2; // edi
  int v3; // edx
  char v4; // bl
  char v5; // al
  char v6; // al
  unsigned int v7; // ecx
  char v9; // [esp+Bh] [ebp-405h]
  _BYTE v10[1024]; // [esp+Ch] [ebp-404h] BYREF

  v2 = strlen(a1);
  memset(v10, 0, sizeof(v10));
  v3 = 0;
  if ( v2 > 0 )
  {
    v4 = v9;
    do
    {
      v5 = a1[v3];
      if ( (unsigned __int8)(v5 - 48) > 9u )
      {
        if ( (unsigned __int8)(v5 - 65) <= 5u )
          v9 = v5 - 55;
      }
      else
      {
        v9 = a1[v3] - 48;
      }
      v6 = a1[v3 + 1];
      if ( (unsigned __int8)(v6 - 48) > 9u )
      {
        if ( (unsigned __int8)(v6 - 65) <= 5u )
          v4 = v6 - 55;
      }
      else
      {
        v4 = a1[v3 + 1] - 48;
      }
      v7 = (unsigned int)v3 >> 1;
      v3 += 2;
      v10[v7] = v4 | (16 * v9);
    }
    while ( v3 < v2 );
  }
  return sub_751000(v2 / 2, a2);
}

再往下看 一个base64 xor 了0x76

int __cdecl sub_751000(int a1, void *a2)
{
  char *v2; // ecx
  int v3; // ebp
  char *v4; // edi
  int v5; // esi
  unsigned __int8 v6; // bl
  int i; // esi
  int v8; // edi
  int v9; // edi
  size_t v10; // esi
  void *v11; // edi
  const void *p_Src; // eax
  unsigned __int8 v14; // [esp+14h] [ebp-38h] BYREF
  unsigned __int8 v15; // [esp+15h] [ebp-37h]
  unsigned __int8 v16; // [esp+16h] [ebp-36h]
  char v17; // [esp+18h] [ebp-34h]
  char v18; // [esp+19h] [ebp-33h]
  char v19; // [esp+1Ah] [ebp-32h]
  char j; // [esp+1Bh] [ebp-31h]
  void *v21; // [esp+1Ch] [ebp-30h]
  char v22[4]; // [esp+20h] [ebp-2Ch] BYREF
  void *Src; // [esp+24h] [ebp-28h] BYREF
  size_t Size; // [esp+34h] [ebp-18h]
  unsigned int v25; // [esp+38h] [ebp-14h]
  int v26; // [esp+48h] [ebp-4h]

  v3 = a1;
  v4 = v2;
  v21 = a2;
  std::string::string(v22);
  v5 = 0;
  v26 = 0;
  if ( a1 )
  {
    do
    {
      *(&v14 + v5) = *v4;
      v6 = v15;
      ++v5;
      --v3;
      ++v4;
      if ( v5 == 3 )
      {
        v17 = v14 >> 2;
        v18 = (v15 >> 4) + 16 * (v14 & 3);
        v19 = (v16 >> 6) + 4 * (v15 & 0xF);
        j = v16 & 0x3F;
        for ( i = 0; i < 4; ++i )
          std::string::operator+=(v22, (unsigned __int8)byte_753020[(unsigned __int8)*(&v17 + i)] ^ 0x76);
        v5 = 0;
      }
    }
    while ( v3 );
    if ( v5 )
    {
      if ( v5 < 3 )
      {
        memset(&v14 + v5, 0, 3 - v5);
        v6 = v15;
      }
      v18 = (v6 >> 4) + 16 * (v14 & 3);
      v17 = v14 >> 2;
      v19 = (v16 >> 6) + 4 * (v6 & 0xF);
      v8 = 0;
      for ( j = v16 & 0x3F; v8 < v5 + 1; ++v8 )
        std::string::operator+=(v22, (unsigned __int8)byte_753020[(unsigned __int8)*(&v17 + v8)] ^ 0x76);
      if ( v5 < 3 )
      {
        v9 = 3 - v5;
        do
        {
          std::string::operator+=(v22, 61);
          --v9;
        }
        while ( v9 );
      }
    }
  }
  v10 = Size;
  v11 = v21;
  memset(v21, 0, Size + 1);
  p_Src = Src;
  if ( v25 < 0x10 )
    p_Src = &Src;
  memcpy(v11, p_Src, v10);
  v26 = -1;
  return std::string::~string(v22);
}

我们直接xor回来发现是标准的base64表

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

那我们直接解码下面的reverse+ 那为什么没有进行sub_751240@&lt;eax&gt; 的操作呢 其实是

hex字符串 -> 原始字节 也就是hex解码 所以流程可以看成这样

输入 hex
   
sub_751240hex  bytes
   
sub_751000 bytes  Base64 编码
   
得到 reverse+
   
比较DDCTF{reverse+}

exp

import base64

s = b"reverse+"
code = base64.b64decode(s)

print(code.hex().upper())

flag

flag{ADEBDEAEC7BE}