楚慧杯——复现babyre

发布于 2023-12-19  114 次阅读


1.分析文件:

把文件拖入DIE里面查看:

QQ图片20231217210730

发现文件被保护器OLLVM执行过,

使用控制流平坦化和指令替换混淆代码,加密算法采用xxtea进行加密,

控制流平坦化的解决办的是使用defla.py和am_graph.py脚本来解决这个问题,

2.拖入IDA,查找main函数的地址

int __cdecl main(int argc, const char **argv, const char **envp)
{
 int v3; // eax
 int v4; // eax
 int v5; // eax
 int v7; // [rsp+80h] [rbp-C0h]
 __int64 v8; // [rsp+84h] [rbp-BCh] BYREF
 int v9; // [rsp+8Ch] [rbp-B4h]
 void *ptr; // [rsp+90h] [rbp-B0h]
 int v11; // [rsp+9Ch] [rbp-A4h]
 int dest[20]; // [rsp+A0h] [rbp-A0h] BYREF
 __int64 v13[2]; // [rsp+F0h] [rbp-50h] BYREF
 char s[4]; // [rsp+100h] [rbp-40h] BYREF
 int v15; // [rsp+134h] [rbp-Ch]

 v15 = 0;
 printf("Plz input your flag:");
 v13[0] = 0x87654321DEADBEEFLL;
 v13[1] = 0xCAFEBABEFACEB00CLL;
 fgets(s, 50, _bss_start);
 memcpy(dest, &unk_400E90, 0x48uLL);
 v11 = (strlen(s) + 3) >> 2;
 ptr = malloc(8LL * v11);
 v9 = 0;
 v7 = 1382681843;
 while ( v7 != -1648711900 )
{
   switch ( v7 )
  {
     case -1318238338:
       v4 = -410445276;
       if ( v9 < 2 * v11 )
         v4 = 431781552;
       v7 = v4;
       break;
     case -1182181165:
       memset(&v8, 0, sizeof(v8));
       LODWORD(v8) = *(_DWORD *)&s[4 * v9];
       encode(32LL, &v8, v13);
       *((_QWORD *)ptr + v9) = v8;
       v7 = 1714824249;
       break;
     case -750079413:
       ++v9;
       v7 = -1318238338;
       break;
     case -410445276:
       printf("Congratulations\n");
       free(ptr);
       v15 = 0;
       v7 = -1648711900;
       break;
     case 107817298:
       v7 = -750079413;
       break;
     case 431781552:
       v5 = 107817298;
       if ( *((_DWORD *)ptr + v9) != dest[v9] )
         v5 = 1679507848;
       v7 = v5;
       break;
     case 1382681843:
       v3 = 1550668173;
       if ( v9 < v11 )
         v3 = -1182181165;
       v7 = v3;
       break;
     case 1550668173:
       v9 = 0;
       v7 = -1318238338;
       break;
     case 1679507848:
       printf("Error\n");
       v15 = 0;
       v7 = -1648711900;
       break;
     default:
       ++v9;
       v7 = 1382681843;
       break;
  }
}
 return v15;
}

我们可以看见main函数的可读性很差,查找main函数的地址:0x400950,所以就需要使用指令:python deflat.py babyre 0x400950python deflat.py + 名字 + main函数的地址

(注意,这里需要被操作的题与脚本在同一的路径下面cmd,不然我会出现查找不到的错误:

然后就会生成一个文件babyre_recovered,打开来就会发现文件的main函数可读性明显提升了:

3.查看加密的函数encode

点开encode函数,可以看见函数里面十分复杂,基本看不懂里面在干什么:

那么就可以猜测的里面会有指令替换,所以我们就需要一个IDA的插件来帮助我们来把这一个混淆去掉:

我们把这两个文件放入IDA里面的plugins文件夹里面,

然后打开IDA,进入到encode函数里面,在Edit,Plugins里面找到插件D-810:

然后点击start,待结束过后按F5重新加载一下,就可以看见函数变小了很多:

__int64 __fastcall encode(unsigned int a1, unsigned int *a2, __int64 a3)
{
  int v3; // eax
  __int64 result; // rax
  int v5; // [rsp+14h] [rbp-30h]
  unsigned int v6; // [rsp+1Ch] [rbp-28h]
  unsigned int v7; // [rsp+20h] [rbp-24h]
  unsigned int v8; // [rsp+24h] [rbp-20h]
  unsigned int v9; // [rsp+28h] [rbp-1Ch]

  v8 = *a2;
  v7 = a2[1];
  v6 = 0;
  v9 = 0;
  v5 = -541349338;
  while ( 1 )
  {
    while ( v5 == -541349338 )
    {
      v3 = -420430140;
      if ( v9 < a1 )
        v3 = 821547026;
      v5 = v3;
    }
    if ( v5 == -420430140 )
      break;
    if ( v5 == 401959373 )
    {
      ++v9;
      v5 = -541349338;
    }
    else
    {
      v8 += (v7 + ((16 * v7) ^ (v7 >> 5))) ^ (*(_DWORD *)(a3 + 4LL * (v6 & 3)) + v6);
      v6 -= 1640531527;
      v7 += (v8 + ((16 * v8) ^ (v8 >> 5))) ^ (*(_DWORD *)(a3 + 4LL * ((v6 >> 11) & 3)) + v6);
      v5 = 401959373;
    }
  }
  *a2 = v8;
  result = v7;
  a2[1] = v7;
  return result;
}

可以使用IDA的插件或者经验得出这一段加密是tea加密,然后根据unk_400E90里面的数据和key来解题,下面是找的解tea的脚本:

#include <iostream>
#include <stdio.h>
#include <stdint.h>
void jm(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], sum = 0, delta = 0x61C88647;
    for (i = 0; i < num_rounds; i++)
    {
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        sum -= delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
    }
    v[0] = v0;
    v[1] = v1;
}
void dm(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], delta = 0x61C88647, sum = 0xc6ef3720;
    for (i = 0; i < num_rounds; i++)
    {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
        sum += delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0] = v0;
    v[1] = v1;
}
int main()
{
    uint32_t enc[] = { 0x168f8672, 0x2dbd824, 0xcf647fca, 0xe6efa7ef, 0x4ae016f0, 0xc5832e1d, 0x455c0a05, 0xffeb8140, 0xbe9561ef, 0x7f819e23, 0x3bc04269, 0xc68b825b, 0xe6a5b1f0, 0xbd03cbbd, 0xa9b3ce0e, 0x6c85e6e7, 0x9f5c71ef, 0x3be4bd57 };
    uint32_t key[4] = { 0xDEADBEEF, 0x87654321, 0xFACEB00C, 0xCAFEBABE };
    unsigned int r = 32;
    int n = sizeof(enc) / sizeof(uint32_t);
    for (int i = 0; i < n / 2; i++)
    {
        dm(r, &enc[i * 2], key);
        printf("%s", &enc[i * 2]);
    }
    return 0;
}

解出的flag是DASCTF{Don't_forget_to_drink_tea}


The world's full of lonely people afraid to make the first move.