[GDOUCTF2023]tea
查壳是64位无壳,ida64直接查看字符串
交叉引用一下you are right,定位到关键函数
__int64 sub_140016230()
{
char *v0; // rdi
__int64 i; // rcx
char v3[32]; // [rsp+0h] [rbp-20h] BYREF
char v4; // [rsp+20h] [rbp+0h] BYREF
int v5; // [rsp+24h] [rbp+4h]
int v6; // [rsp+44h] [rbp+24h]
int v7[12]; // [rsp+68h] [rbp+48h] BYREF
_DWORD v8[16]; // [rsp+98h] [rbp+78h] BYREF
int v9[31]; // [rsp+D8h] [rbp+B8h] BYREF
int j; // [rsp+154h] [rbp+134h]
int k; // [rsp+174h] [rbp+154h]
int l; // [rsp+194h] [rbp+174h]
v0 = &v4;
for ( i = 102i64; i; --i )
{
*(_DWORD *)v0 = -858993460;
v0 += 4;
}
sub_14001137F(&unk_140023009);
v5 = 32;
v6 = 0;
v7[0] = 1234;
v7[1] = 5678;
v7[2] = 9012;
v7[3] = 3456;
memset(v8, 0, 0x28ui64);
v9[15] = 0;
v9[23] = 0;
sub_1400113E8();
for ( j = 0; j < 10; ++j )
sub_1400111FE("%x", &v8[j]); // 读入16进制数组v8
sub_140011339(v7); // v7 = [2233,4455,6677,8899]
sub_140011145(v8, v9); // v8赋值给v9
sub_1400112B7(v8, v7); // xtea加密v8,v7为key
v6 = sub_140011352(v8);
// 判断v8是否等于[0x1A800BDA,0xF7A6219B,0x491811D8,0xF2013328,0x156C365B,
//0x3C6EAAD8,0x84D4BF28,0xF11A7EE7,0x3313B252,0xDD9FE279]
if ( v6 )
{
sub_140011195("you are right\n");
for ( k = 0; k < 10; ++k )
{
for ( l = 3; l >= 0; --l )
sub_140011195("%c", (unsigned __int8)((unsigned int)v9[k] >> (8 * l)));// 输出flag
}
}
else
{
sub_140011195("fault!\nYou can go online and learn the tea algorithm!");
}
sub_140011311(v3, &unk_14001AE90);
return 0i64;
}
简单分析如上,重点看一下xtea加密函数
__int64 __fastcall sub_140011900(__int64 a1, __int64 a2)
{
__int64 result; // rax
int v3; // [rsp+44h] [rbp+24h]
int i; // [rsp+64h] [rbp+44h]
unsigned int v5; // [rsp+84h] [rbp+64h]
unsigned int v6; // [rsp+C4h] [rbp+A4h]
result = sub_14001137F(&unk_140023009);
for ( i = 0; i <= 8; ++i )
{
v5 = 0;
v6 = 256256256 * i;
v3 = i + 1;
do
{
++v5;
*(_DWORD *)(a1 + 4i64 * i) += v6 ^ (*(_DWORD *)(a1 + 4i64 * v3)
+ ((*(_DWORD *)(a1 + 4i64 * v3) >> 5) ^ (16 * *(_DWORD *)(a1 + 4i64 * v3)))) ^ (v6 + *(_DWORD *)(a2 + 4i64 * (v6 & 3)));
*(_DWORD *)(a1 + 4i64 * v3) += (v6 + *(_DWORD *)(a2 + 4i64 * ((v6 >> 11) & 3))) ^ (*(_DWORD *)(a1 + 4i64 * i)
+ ((*(_DWORD *)(a1 + 4i64 * i) >> 5) ^ (16 * *(_DWORD *)(a1 + 4i64 * i))));
v6 += 256256256;
}
while ( v5 <= 0x20 );
result = (unsigned int)(i + 1);
}
return result;
}
32次迭代的变体xtea加密,可以看出来delta值被魔改了,是v6=256256256
exp
def xtea_decrypt(data,key):
for j in range(8,-1,-1):
i = 0
delta = 256256256
sum = delta * (32 + j)
n = j + 1
while i <= 32:
i += 1
data[n] = (data[n] - (((key[(sum >> 11) & 3]) + sum) ^ (((data[j] << 4) ^ (data[j] >> 5)) + data[j]))) & 0xffffffff
data[j] = (data[j] - (((key[sum & 3] + sum) ^ ((data[n] << 4) ^ (data[n] >> 5)) + data[n]) ^ sum)) & 0xffffffff
sum -= delta
return data
v8 = [0x1A800BDA,0xF7A6219B,0x491811D8,0xF2013328,0x156C365B,
0x3C6EAAD8,0x84D4BF28,0xF11A7EE7,0x3313B252,0xDD9FE279]
key = [2233,4455,6677,8899]
flag = xtea_decrypt(v8,key)
for i in range(10):
for j in range(3,-1,-1):
print(chr((flag[i] >> (j * 8)) & 0xFF), end='')
有个地方要特别注意的就是读入的v8是16进制无符号32位整数
如果不进行& 0xffffffff
,运行结果是乱码
这耗费了我好多时间检查,问题出在C和Python对无符号整数的处理方式不同。在C中,当无符号整数溢出时,它会回绕到0。但是,在Python中,当整数溢出时,它们会自动升级为长整数。所以需要通过& 0xffffffff
来保证解密出来是无符号32位整数。
最终运行结果HZCTF{hzCtf_94_re666fingcry5641qq}
根据题目要求flagNSSCTF{hzCtf_94_re666fingcry5641qq}
本文来自博客园,作者:{Tree_24},转载请注明原文链接:{https://www.cnblogs.com/Tree-24/}