Buuctf-Reverse(逆向) 2019RedHat(红帽杯)-xx

Posted 水番正文

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Buuctf-Reverse(逆向) 2019RedHat(红帽杯)-xx相关的知识,希望对你有一定的参考价值。

0x00 日常查壳

无壳64位

0x01 分析主函数

考的主要还是正向开发

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 flaglen2; // rbx
  __int64 flaglen1; // rax
  __int128 *malloc5; // rax
  __int64 data; // r11
  __int128 *malloc7; // r14
  int v8; // edi
  __int128 *malloc9; // rsi
  char tmp; // r10
  int v11; // edx
  __int64 v12; // r8
  unsigned __int64 datalen; // rcx
  __int64 v14; // rcx
  unsigned __int64 v15; // rax
  unsigned __int64 i; // rax
  _BYTE *encodeflag; // rax
  size_t v18; // rsi
  _BYTE *enflag; // rbx
  _BYTE *v20; // r9
  int v21; // er11
  char *v22; // r8
  __int64 v23; // rcx
  char v24; // al
  __int64 v25; // r9
  __int64 v26; // rdx
  __int64 v27; // rax
  size_t Size; // [rsp+20h] [rbp-48h] BYREF
  __int128 malloc30; // [rsp+28h] [rbp-40h] BYREF
  int v31; // [rsp+38h] [rbp-30h]
  int v32; // [rsp+3Ch] [rbp-2Ch]
  int flag[4]; // [rsp+40h] [rbp-28h] BYREF
  int v34; // [rsp+50h] [rbp-18h]

  *(_OWORD *)flag = 0i64;
  v34 = 0;
  sub_7FF7D13618C0(std::cin, argv, flag);       // 获取flag
  flaglen2 = -1i64;
  flaglen1 = -1i64;
  do
    ++flaglen1;
  while ( *((_BYTE *)flag + flaglen1) );
  if ( flaglen1 != 19 )                         // flag长度为19
  {
    sub_7FF7D1361620(std::cout, "error\\n");
    _exit((int)flag);
  }
  malloc5 = (__int128 *)operator new(5ui64);    // 申请了5字节内存
  data = *(_QWORD *)&Code;
  malloc7 = malloc5;
  v8 = 0;
  malloc9 = malloc5;
  do
  {
    tmp = *((_BYTE *)malloc9 + (char *)flag - (char *)malloc5);// 取flag的第一位到tmp中
    v11 = 0;
    *(_BYTE *)malloc9 = tmp;
    v12 = 0i64;
    datalen = -1i64;
    do
      ++datalen;
    while ( *(_BYTE *)(data + datalen) );       // 数据段的长度
    if ( datalen )
    {
      do
      {
        if ( tmp == *(_BYTE *)(data + v12) )
          break;
        ++v11;
        ++v12;
      }
      while ( v11 < datalen );
    }
    v14 = -1i64;
    do
      ++v14;
    while ( *(_BYTE *)(data + v14) );           // 数据段的长度
    if ( v11 == v14 )
      _exit(data);
    malloc9 = (__int128 *)((char *)malloc9 + 1);// malloc9指向后一位长度
  }
  while ( (char *)malloc9 - (char *)malloc5 < 4 );
  *((_BYTE *)malloc5 + 4) = 0;
  do
    ++flaglen2;
  while ( *((_BYTE *)flag + flaglen2) );        // flag的长度
  v15 = 0i64;
  malloc30 = *malloc7;
  while ( *((_BYTE *)&malloc30 + v15) )
  {
    if ( !*((_BYTE *)&malloc30 + v15 + 1) )
    {
      ++v15;
      break;
    }
    if ( !*((_BYTE *)&malloc30 + v15 + 2) )
    {
      v15 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&malloc30 + v15 + 3) )
    {
      v15 += 3i64;
      break;
    }
    v15 += 4i64;
    if ( v15 >= 0x10 )
      break;
  }
  for ( i = v15 + 1; i < 0x10; ++i )            // 把四位之后的都赋值成0
    *((_BYTE *)&malloc30 + i) = 0;
  encodeflag = sub_7FF7D1361AB0((__int64)flag, flaglen2, (unsigned __int8 *)&malloc30, &Size);// xxtea
  v18 = Size;                                   // 加密后的长度
  enflag = encodeflag;
  v20 = operator new(Size);
  v21 = 1;
  *v20 = enflag[2];
  v22 = v20 + 1;
  v20[1] = *enflag;
  v20[2] = enflag[3];
  v20[3] = enflag[1];
  v20[4] = enflag[6];
  v20[5] = enflag[4];
  v20[6] = enflag[7];
  v20[7] = enflag[5];
  v20[8] = enflag[10];
  v20[9] = enflag[8];
  v20[10] = enflag[11];
  v20[11] = enflag[9];
  v20[12] = enflag[14];
  v20[13] = enflag[12];
  v20[14] = enflag[15];
  v20[15] = enflag[13];
  v20[16] = enflag[18];
  v20[17] = enflag[16];
  v20[18] = enflag[19];
  v20[19] = enflag[17];
  v20[20] = enflag[22];
  v20[21] = enflag[20];
  v20[22] = enflag[23];
  for ( v20[23] = enflag[21]; v21 < v18; ++v22 )
  {
    v23 = 0i64;
    if ( v21 / 3 > 0 )
    {
      v24 = *v22;
      do
      {
        v24 ^= v20[v23++];
        *v22 = v24;
      }
      while ( v23 < v21 / 3 );
    }
    ++v21;
  }
  *(_QWORD *)&malloc30 = 0xC0953A7C6B40BCCEui64;
  v25 = v20 - (_BYTE *)&malloc30;
  *((_QWORD *)&malloc30 + 1) = 0x3502F79120209BEFi64;
  v26 = 0i64;
  v31 = -939386845;
  v32 = -95004953;
  do
  {
    if ( *((_BYTE *)&malloc30 + v26) != *((_BYTE *)&malloc30 + v26 + v25) )
      _exit(v8 * v8);
    ++v8;
    ++v26;
  }
  while ( v26 < 24 );
  v27 = sub_7FF7D1361620(std::cout, "You win!");
  std::ostream::operator<<(v27, sub_7FF7D13617F0);
  return 0;
}

有些部分确实也要猜,就比如头四位的flag作为秘钥

理一下思路:

1. 将用户的前四位 输入和Code字符串进行比较 如果不在Code字符串里就会退出

2. 将前四位作为秘钥 findCrypto找到是tea 根据题目或者看一下加密算法 判断是xxtea

3. 然后就行位置混淆操作

4. 三位一组异或

第三步和第四步问题倒不是很大 关键是要识别这个函数

TEA、XTEA、XXTEA加密解密算法_gsls200808的专栏-CSDN博客_tea加密

0x02 GetFlag

读完代码其实只要逆回去就好了

首先是解异或 然后是根据混淆下标

#include <stdio.h>

void Print(int *, int);

int main(void)
{
	int key[] = 		//注意小端存储 
	{
		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 i, j;
	int tmp;
	int data[24];
	int index[24] =
	{
		2, 0, 3, 1, 6, 4, 7, 5, 10, 8, 11, 9, 14, 12, 15, 13, 18, 16, 19, 17, 22, 20, 23, 21	
	}; 
	
//	for ( i = 23, j = 6; i >= 3; i-- )
//	{
//		tmp = j;
//		do
//		{
//			key[i] ^= key[tmp--];	 逐位异或				
//		} while ( tmp >= 0);
//		
//		if ( i % 3 == 0)		过了一个3位少异或一位
//			j--;
//	}
	
	for ( i = 23; i >= 3; i-- )
	{
		for ( j = 6 - tmp; j >= 0; j-- ) 
		{
			key[i] ^= key[j];		
		}
		if (i % 3 == 0)
		{
			tmp++;
		}	
	}
	Print(key, 24);
	
	for (i = 0; i < 24; i++)
		data[index[i]] = key[i];
	Print(data, 24);
	
	return 0; 
} 

void Print(int * ar, int n)
{
	int i;
	
	for ( i = n - 1; i >= 0; i--)
	{
		if((i + 1) % 4 == 0 )
			printf(" 0x");
		printf("%2x", ar[i]);
	}
		
	puts("\\n");
}

得到加密后的数据后 进行xxtea解密

#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
 
void btea(uint32_t *v, int n, uint32_t const key[4])
{
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1)            /* Coding Part */
    {
        rounds = 6 + 52 / n;
        sum = 0;
        z = v[n - 1];
        do
        {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for ( p = 0; p < n - 1; p++ )
            {
                y = v[p + 1];
                z = v[p] += MX;
            }
            y = v[0];
            z = v[n - 1] += MX;
        }
        while (--rounds);
    }
    else if (n < -1)      /* Decoding Part */
    {
        n = -n;
        rounds = 6 + 52 / n;
        sum = rounds * DELTA;
        y = v[0];
        do
        {
            e = (sum >> 2) & 3;
            for (p = n - 1; p > 0; p--)
            {
                z = v[p - 1];
                y = v[p] -= MX;
            }
            z = v[n - 1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        while (--rounds);
    }
}
 
 
int main()
{
    uint32_t v[6]= 
	{ 
		(unsigned int)0x40cea5bc, (unsigned int)0xe7b2b2f4, (unsigned int) 0x129d12a9, 
		(unsigned int)0x5bc810ae, (unsigned int)0x1d06d73d, (unsigned int) 0xdcf870dc
	};
    uint32_t const k[4]= 
	{ 
		(unsigned int)0x67616c66, (unsigned int)0x0, (unsigned int)0x0, (unsigned int)0x0
	};
    
    int n = 6; 	//n的绝对值表示v的长度,取正表示加密,取负表示解密
    			// v为要加密的数据是两个32位无符号整数
    			// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    
    printf("加密前原始数据:%x %x %x %x %x %x\\n", v[0], v[1], v[2], v[3], v[4], v[5]);
 //   btea(v, n, k);
 //   printf("加密后的数据:%u %u %u %u %u %u\\n", v[0], v[1], v[2], v[3], v[4], v[5]);
 
    btea(v, -n, k);
    printf("解密后的数据:%x %x %x %x %x %x\\n", v[0], v[1], v[2], v[3], v[4], v[5]);
    //最后一位舍弃因为是19位长度 

    puts("\\n");
    
	char flag[] = "67616c665858437b646e615f742b2b5f7d6165";
	int i, j;
	
	for ( i = 1; i < 6; i++ )
	{
		for ( j = 0; j < 8; j += 2)
		{
			if ( j == 0 && i == 5 )
				continue;
			printf("0x%c%c, ", flag[i * 8 - j - 2], flag[i * 8 - j - 1]);
		}
	} 
	
	puts("\\n");
	
	int PoZ[] =
	{
		0x66, 0x6c, 0x61, 0x67, 0x7b, 0x43, 0x58, 0x58, 0x5f, 0x61, 0x6e, 
		0x64, 0x5f, 0x2b, 0x2b, 0x74, 0x65, 0x61, 0x7d
	};
	for ( i = 0; i < 19; i++ )
		printf("%c", PoZ[i]);
    
    return 0;
}

GetFlag!

以上是关于Buuctf-Reverse(逆向) 2019RedHat(红帽杯)-xx的主要内容,如果未能解决你的问题,请参考以下文章

Buuctf-Reverse(逆向) 网鼎杯 2020 青龙组-singal Write up

Buuctf-Reverse(逆向) Crackme Write up

Buuctf-Reverse(逆向) Zer0pts2020-easy strcmp Write up

RE-1 逆向分析基础

逆向工程权威指南

BugkuCTF RE部分题解