BUUCTF Reverse/[2019红帽杯]xx

BUUCTF Reverse/[2019红帽杯]xx

BUUCTF Reverse/[2019红帽杯]xx_第1张图片

先看下文件信息:没有加壳、64位程序

BUUCTF Reverse/[2019红帽杯]xx_第2张图片

看别人wp时候发现个好东东,就是这个findcrypt插件,可以看加密算法的,具体安装可以看这个IDA7.5安装findcrypt3插件

BUUCTF Reverse/[2019红帽杯]xx_第3张图片

可以看到这是tea加密

BUUCTF Reverse/[2019红帽杯]xx_第4张图片

先一点点分析代码,输入flag,flag的长度必须为19

 sub_7FF7A98718C0(std::cin, argv, flag);       // 输入flag
  v3 = -1i64;
  v4 = -1i64;
  do
    ++v4;
  while ( *((_BYTE *)flag + v4) );
  if ( v4 != 19 )                               // 长度为19
  {
    sub_7FF7A9871620(std::cout, "error\n");
    _exit((int)flag);

这里给v6赋值为qwertyuiopasdfghjklzxcvbnm1234567890

这行代码看上去挺麻烦的,一眼唬住,但是仔细看下,前面有个v9 = v5,后面又减去了个v5,所以这行代码就变成了v10 = *flag
v10 = *((_BYTE *)v9 + (char *)flag - (char *)v5);

这段代码比较的是输入的flag的前四个字符是否在qwertyuiopasdfghjklzxcvbnm1234567890之间,顺便把flag的前四个字符赋值给v5

 v5 = (__int128 *)operator new(5ui64);
  v6 = *(_QWORD *)&Code;
  v7 = v5;
  v8 = 0;
  v9 = v5;
  do
  {
    v10 = *((_BYTE *)v9 + (char *)flag - (char *)v5);
    v11 = 0;
    *(_BYTE *)v9 = v10;
    v12 = 0i64;
    v13 = -1i64;
    do
      ++v13;
    while ( *(_BYTE *)(v6 + v13) );
    if ( v13 )
    {
      do
      {
        if ( v10 == *(_BYTE *)(v6 + v12) )
          break;
        ++v11;
        ++v12;
      }
      while ( v11 < v13 );
    }
    v14 = -1i64;
    do
      ++v14;
    while ( *(_BYTE *)(v6 + v14) );
    if ( v11 == v14 )
      _exit(v6);
    v9 = (__int128 *)((char *)v9 + 1);
  }
  while ( (char *)v9 - (char *)v5 < 4 );

将v5扩展成16位,不足补0,前四位应该是 ‘flag’,补完后就是 ‘flag000000000000’

 v30 = *v7;
  while ( *((_BYTE *)&v30 + v15) )
  {
    if ( !*((_BYTE *)&v30 + v15 + 1) )
    {
      ++v15;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 2) )
    {
      v15 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 3) )
    {
      v15 += 3i64;
      break;
    }
    v15 += 4i64;
    if ( v15 >= 0x10 )
      break;
  }
  for ( i = v15 + 1; i < 0x10; ++i )
    *((_BYTE *)&v30 + i) = 0;

这一段就是给输入的flag进行xxtea加密,前面扩展的v5就是它的秘钥,然后再变换位置

 v17 = sub_7FF7A9871AB0((__int64)flag, v3, (unsigned __int8 *)&v30, &Size);// tea加密
  v18 = Size;
  v19 = v17;
  v20 = operator new(Size);
  v21 = 1;
  *v20 = v19[2];
  v22 = v20 + 1;
  v20[1] = *v19;
  v20[2] = v19[3];
  v20[3] = v19[1];
  v20[4] = v19[6];
  v20[5] = v19[4];
  v20[6] = v19[7];
  v20[7] = v19[5];
  v20[8] = v19[10];
  v20[9] = v19[8];
  v20[10] = v19[11];
  v20[11] = v19[9];
  v20[12] = v19[14];
  v20[13] = v19[12];
  v20[14] = v19[15];
  v20[15] = v19[13];
  v20[16] = v19[18];
  v20[17] = v19[16];
  v20[18] = v19[19];
  v20[19] = v19[17];
  v20[20] = v19[22];
  v20[21] = v19[20];
  v20[22] = v19[23];

xxtea里面还有一段拆分的代码,将32位的数拆分成4个8位的数

    if ( v40 )
    {
      do
      {
        v42[v13] = v11[v13 >> 2] >> (8 * (v13 & 3));
        ++v13;
      }
      while ( v13 < v40 );
    }

异或

  for ( v20[23] = v19[21]; v21 < v18; ++v22 )
  {
    v23 = 0i64;
    if ( v21 / 3 > 0 )
    {
      v24 = *v22;
      do
      {
        v24 ^= v20[v23++];                      // 与前面的数异或
        *v22 = v24;
      }
      while ( v23 < v21 / 3 );
    }
    ++v21;
  }

变换后的字符串要等于v30中的字符串

 *(_QWORD *)&v30 = 0xC0953A7C6B40BCCEui64;
  v25 = v20 - (_BYTE *)&v30;
  *((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
  v26 = 0i64;
  v31 = 0xC8021823;
  v32 = 0xFA5656E7;
  do
  {
    if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )
      _exit(v8 * v8);
    ++v8;
    ++v26;
  }
  while ( v26 < 24 );

梳理下:
输入flag->取前四位扩展成16位作秘钥-> xxtea加密->拆分 ->移位 ->异或

然后写脚本挨个逆就行,先异或

int v20[] = {  0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B,
                        0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8,
                        0xE7, 0x56, 0x56, 0xFA};

   for(int v22 = 23,v21 = 23; v21 >= 1; v22--)
   {
       int v23 = 0;
       if( v21 / 3 > 0)
       {
           //int v24 = v20[v22];
           do
           {
               //v24 ^= v20[v23 ++];
               //v20[v22] = v24;
               v20[v22] ^= v20[v23++];
           }
           while(v23 < v21 / 3);
       }
       --v21;
   }

移位

int v19[25] = {0};

   v19[0] = v20[1];
   v19[2] = v20[0];
   v19[3] = v20[2];
   v19[1] = v20[3];
   v19[6] = v20[4];
   v19[4] = v20[5];
   v19[7] = v20[6];
   v19[5] = v20[7];
   v19[10] = v20[8];
   v19[8] = v20[9];
   v19[11] = v20[10];
   v19[9] = v20[11];
   v19[14] = v20[12];
   v19[12] = v20[13];
   v19[15] = v20[14];
   v19[13] = v20[15];
   v19[18] = v20[16];
   v19[16] = v20[17];
   v19[19] = v20[18];
   v19[17] = v20[19];
   v19[22] = v20[20];
   v19[20] = v20[21];
   v19[23] = v20[22];
   v19[21] = v20[23];

合并

    unsigned int flag[10] = {0};
    for(int i = 0 ; i < 0x18 ; i++)
    {
        //printf("%d, %d\n",i , 4 * (i / 4 + 1) - (i %  4) - 1);
        flag[i >>2] <<= 8;
        flag[i >> 2] += v19[4 * (i / 4 + 1) - i % 4 - 1];

    }

xxtea解密

xxtea秘钥是4个32位数,小端排序

#define MX ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)))
#define DELTA 0x61C88647

int key[5] = {0x67616c66,0x00,0x00,0x00};

 unsigned int sum = 0 , n = 6;
  int rounds = 52 / n + 6;
  int i,j,k;
  unsigned int z,y,e,p;


    rounds = 6 + 52/n;
    sum = rounds * DELTA * (-1);
    y = flag[0];
    do
    {
       // if(rounds < 0) break;
        e = (sum >> 2) & 3;
        for (p=n-1; p>0; p--)
        {
            z = flag[p-1];
                //y = v2[p] -= ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)));
            y = flag[p] -= MX;
            printf("p = %d\n",p);
        }
        z = flag[n-1];
            //y = v2[0] -= ((v2[0] ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * v2[0]) ^ (z >> 5)) + ((v2[0] >> 3) ^ (16 * z)));
        y = flag[0] -= MX;
        sum += DELTA;
        printf("rounds = %d\n",rounds);

    }
    while(--rounds);


总代码

#include 
#include 
#include 
#include 
#define MX ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)))
#define DELTA 0x61C88647

int main()
{

   int v20[] = {  0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B,
                        0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8,
                        0xE7, 0x56, 0x56, 0xFA};

   int key[5] = {0x67616c66,0x00,0x00,0x00};

      for(int v22 = 23,v21 = 23; v21 >= 1; v22--)
   {
       int v23 = 0;
       if( v21 / 3 > 0)
       {
    
           do
           {
               v20[v22] ^= v20[v23++];
           }
           while(v23 < v21 / 3);
       }
       --v21;
   }

   int v19[25] = {0};

   v19[0] = v20[1];
   v19[2] = v20[0];
   v19[3] = v20[2];
   v19[1] = v20[3];
   v19[6] = v20[4];
   v19[4] = v20[5];
   v19[7] = v20[6];
   v19[5] = v20[7];
   v19[10] = v20[8];
   v19[8] = v20[9];
   v19[11] = v20[10];
   v19[9] = v20[11];
   v19[14] = v20[12];
   v19[12] = v20[13];
   v19[15] = v20[14];
   v19[13] = v20[15];
   v19[18] = v20[16];
   v19[16] = v20[17];
   v19[19] = v20[18];
   v19[17] = v20[19];
   v19[22] = v20[20];
   v19[20] = v20[21];
   v19[23] = v20[22];
   v19[21] = v20[23];

    unsigned int flag[10] = {0};
    for(int i = 0 ; i < 0x18 ; i++)
    {
        //printf("%d, %d\n",i , 4 * (i / 4 + 1) - (i %  4) - 1);
        flag[i >>2] <<= 8;
        flag[i >> 2] += v19[4 * (i / 4 + 1) - i % 4 - 1];

    }

unsigned int sum = 0 , n = 6;
  int rounds = 52 / n + 6;
  int i,j,k;
  unsigned int z,y,e,p;

//xxtea

    rounds = 6 + 52/n;
    sum = rounds * DELTA * (-1);
    y = flag[0];
    do
    {
       // if(rounds < 0) break;
        e = (sum >> 2) & 3;
        for (p=n-1; p>0; p--)
        {
            z = flag[p-1];
     
            y = flag[p] -= MX;
        }
        z = flag[n-1];
        y = flag[0] -= MX;
        sum += DELTA;

    }
    while(--rounds);
    //输出
   char *tmp = flag;
   for(int i = 0 ; i < 19 ; i++)
   {
       printf("%c",*tmp++);
   }
   return 0;
}


输出

BUUCTF Reverse/[2019红帽杯]xx_第5张图片

最终flag:flag{CXX_and_++tea}

你可能感兴趣的:(CTF,#,BUUCTF,Reverse,CTF,BUUCTF,reverse)