[GDOUCTF2023]tea

查壳是64位无壳,ida64直接查看字符串
img
交叉引用一下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}

posted @ 2023-04-18 14:47  Tree_24  阅读(81)  评论(0编辑  收藏  举报