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