buu 红帽杯 XX
一.拖入ida,静态分析
__int64 __fastcall sub_7FF65D4511A0(__int64 a1, __int64 a2)
{
signed __int64 v2; // rbx
signed __int64 v3; // rax
__int64 v4; // rax
__int64 v5; // r11
__int128 *v6; // r14
int v7; // edi
_BYTE *v8; // rsi
char v9; // r10
int v10; // edx
__int64 v11; // r8
unsigned __int64 v12; // rcx
signed __int64 v13; // rcx
unsigned __int64 v14; // rax
unsigned __int64 i; // rax
__int64 v16; // rax
size_t v17; // rsi
_BYTE *v18; // rbx
_BYTE *v19; // r9
signed int v20; // er11
char *v21; // r8
signed __int64 v22; // rcx
char v23; // al
signed __int64 v24; // r9
signed __int64 v25; // rdx
__int64 v26; // rax
size_t Size; // [rsp+20h] [rbp-48h]
__int128 v29; // [rsp+28h] [rbp-40h]
int v30; // [rsp+38h] [rbp-30h]
int v31; // [rsp+3Ch] [rbp-2Ch]
int Code[4]; // [rsp+40h] [rbp-28h]
int v33; // [rsp+50h] [rbp-18h]
*(_OWORD *)Code = 0i64;
v33 = 0;
sub_7FF65D4518C0(std::cin, a2, Code); //根据cin,知道是在输入字符串,存入Code里面
v2 = -1i64;
v3 = -1i64;
do
++v3;
while ( *((_BYTE *)Code + v3) );
if ( v3 != 19 ) //字符串长度为19
{
sub_7FF65D451620(std::cout, "error\n");
_exit((unsigned __int64)Code);
}
v4 = sub_7FF65D451E5C(5ui64); //根据后面的判断是申请内存空间
v5 = *(_QWORD *)&::Code; //这里有点迷惑性,看似是输入的字符串,实际点进去就知道是个常量
v6 = (__int128 *)v4;
v7 = 0;
v8 = (_BYTE *)v4;
do
{
v9 = v8[(_QWORD)Code - v4];
v10 = 0;
*v8 = v9;
v11 = 0i64;
v12 = -1i64;
do
++v12;
while ( *(_BYTE *)(v5 + v12) );
if ( v12 )
{
do
{
if ( v9 == *(_BYTE *)(v5 + v11) )
break;
++v10;
++v11;
}
while ( v10 < v12 );
}
v13 = -1i64;
do
++v13;
while ( *(_BYTE *)(v5 + v13) );
if ( v10 == v13 )
_exit(v5);
++v8;
}
while ( (signed __int64)&v8[-v4] < 4 );
*(_BYTE *)(v4 + 4) = 0; //判断字符串的前四位在字符串常量中,基本判断出是flag
do
++v2;
while ( *((_BYTE *)Code + v2) ); //字符串常量长度为36
v14 = 0i64;
v29 = *v6;
while ( *((_BYTE *)&v29 + v14) )
{
if ( !*((_BYTE *)&v29 + v14 + 1) )
{
++v14;
break;
}
if ( !*((_BYTE *)&v29 + v14 + 2) )
{
v14 += 2i64;
break;
}
if ( !*((_BYTE *)&v29 + v14 + 3) )
{
v14 += 3i64;
break;
}
v14 += 4i64;
if ( v14 >= 0x10 )
break;
} //测试那段内存空间字符串的长度
for ( i = v14 + 1; i < 0x10; ++i ) //补齐16位,也就是128bits
*((_BYTE *)&v29 + i) = 0;
v16 = sub_7FF65D451AB0(Code, v2, &v29, &Size); //结合题目,和上面的基本判定是xxtea加密
v17 = Size;
v18 = (_BYTE *)v16;
v19 = (_BYTE *)sub_7FF65D451E5C(Size);
v20 = 1;
*v19 = v18[2];
v21 = v19 + 1;
v19[1] = *v18;
v19[2] = v18[3];
v19[3] = v18[1];
v19[4] = v18[6];
v19[5] = v18[4];
v19[6] = v18[7];
v19[7] = v18[5];
v19[8] = v18[10];
v19[9] = v18[8];
v19[10] = v18[11];
v19[11] = v18[9];
v19[12] = v18[14];
v19[13] = v18[12];
v19[14] = v18[15];
v19[15] = v18[13];
v19[16] = v18[18];
v19[17] = v18[16];
v19[18] = v18[19];
v19[19] = v18[17];
v19[20] = v18[22];
v19[21] = v18[20];
v19[22] = v18[23];
for ( v19[23] = v18[21]; v20 < v17; ++v21 ) //打乱了下加密字符串的顺序
{
v22 = 0i64;
if ( v20 / 3 > 0 )
{
v23 = *v21;
do
{
v23 ^= v19[v22++];
*v21 = v23;
}
while ( v22 < v20 / 3 );
}
++v20;
}
*(_QWORD *)&v29 = -4569681940847739698i64;
v24 = v19 - (_BYTE *)&v29;
*((_QWORD *)&v29 + 1) = 3819887636644928495i64;
v25 = 0i64;
v30 = -939386845;
v31 = -95004953;
do
{
if ( *((_BYTE *)&v29 + v25) != *((_BYTE *)&v29 + v25 + v24) ) //比较是否正确
_exit(v7 * v7);
++v7;
++v25;
}
while ( v25 < 24 );
v26 = sub_7FF65D451620(std::cout, "You win!");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v26, sub_7FF65D4517F0);
return 0i64;
}
思路;
先找到最终正确的加密字符串
逆向那个异或的算法
再移位回来
再xxtea的解密,
得出flag
然后写脚本逆向回去就好了。
import struct
_DELTA = 0x9E3779B9
def _long2str(v, w):
n = (len(v) - 1) << 2
if w:
m = v[-1]
if (m < n - 3) or (m > n): return ''
n = m
s = struct.pack('<%iL' % len(v), *v)
return s[0:n] if w else s
def _str2long(s, w):
n = len(s)
m = (4 - (n & 3) & 3) + n
s = s.ljust(m, "\0")
v = list(struct.unpack('<%iL' % (m >> 2), s))
if w: v.append(n)
return v
def encrypt(str, key):
if str == '': return str
v = _str2long(str, True)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
sum = 0
q = 6 + 52 // (n + 1)
while q > 0:
sum = (sum + _DELTA) & 0xffffffff
e = sum >> 2 & 3
for p in range(n):
y = v[p + 1]
v[p] = (v[p] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
z = v[p]
y = v[0]
v[n] = (v[n] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[n & 3 ^ e] ^ z))) & 0xffffffff
z = v[n]
q -= 1
return _long2str(v, False)
def decrypt(str, key):
if str == '': return str
v = _str2long(str, False)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
q = 6 + 52 // (n + 1)
sum = (q * _DELTA) & 0xffffffff
while (sum != 0):
e = sum >> 2 & 3
for p in range(n, 0, -1):
z = v[p - 1]
v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
y = v[p]
z = v[n]
v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff
y = v[0]
sum = (sum - _DELTA) & 0xffffffff
return _long2str(v, True)
res=[0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B, 0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8, 0xE7, 0x56, 0x56,0xFA]
dec=""
for i in range(7,-1,-1):
a=""
for j in range(3):
tmp=res[i*3+j]
for w in range(i):
tmp^=res[w]
a+=chr(tmp)
dec=a+dec
print(dec)
key="flag"+"\x00"*12
num=[2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
n=[0 for i in range(24)]
for i in range(24):
n[num[i]]=dec[i]
dec2="".join(n)
dec3=decrypt(dec2,key)
print(dec3)