[2019红帽杯]xx

查壳,莫得,64位,载入 IDA 简单分析一下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 v3; // rbx
  __int64 v4; // rax
  __int128 *v5; // rax
  __int64 v6; // r11
  __int128 *v7; // r14
  int v8; // edi
  __int128 *v9; // rsi
  char v10; // r10
  int v11; // edx
  __int64 v12; // r8
  unsigned __int64 v13; // rcx
  __int64 v14; // rcx
  unsigned __int64 v15; // rax
  unsigned __int64 i; // rax
  _BYTE *v17; // rax
  size_t v18; // rsi
  _BYTE *v19; // 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 v30; // [rsp+28h] [rbp-40h] BYREF
  int v31; // [rsp+38h] [rbp-30h]
  int v32; // [rsp+3Ch] [rbp-2Ch]
  int user_input[4]; // [rsp+40h] [rbp-28h] BYREF
  int v34; // [rsp+50h] [rbp-18h]

  *(_OWORD *)user_input = 0i64;
  v34 = 0;
  sub_1400018C0(std::cin, argv, user_input);    // 输入
  v3 = -1i64;
  v4 = -1i64;
  do
    ++v4;
  while ( *((_BYTE *)user_input + v4) );        // 计算输入长度
  if ( v4 != 19 )                               // 长度为19
  {
    sub_140001620(std::cout, "error\n");
    _exit((int)user_input);
  }
  v5 = (__int128 *)operator new(5ui64);
  v6 = *(_QWORD *)&Code;                        // Code=qwertyuiopasdfghjklzxcvbnm1234567890
  v7 = v5;
  v8 = 0;
  v9 = v5;                                      // v7=v9=v5
  do
  {
    v10 = *((_BYTE *)v9 + (char *)user_input - (char *)v5);
    v11 = 0;
    *(_BYTE *)v9 = v10;
    v12 = 0i64;
    v13 = -1i64;
    do
      ++v13;
    while ( *(_BYTE *)(v6 + v13) );
    if ( v13 )
    {
      do
      {
        if ( v10 == *(_BYTE *)(v6 + v12) )
          break;
        ++v11;
        ++v12;
      }
      while ( v11 < v13 );
    }
    v14 = -1i64;
    do
      ++v14;
    while ( *(_BYTE *)(v6 + v14) );
    if ( v11 == v14 )                           // 验证输入的内容是否在Code范围内,即输入的内容均为小写字母或0~9的数字
      _exit(v6);
    v9 = (__int128 *)((char *)v9 + 1);
  }
  while ( (char *)v9 - (char *)v5 < 4 );
  *((_BYTE *)v5 + 4) = 0;                       // v5存储了输入的前四位以及一个0
  do
    ++v3;
  while ( *((_BYTE *)user_input + v3) );
  v15 = 0i64;
  v30 = *v7;
  while ( *((_BYTE *)&v30 + v15) )
  {
    if ( !*((_BYTE *)&v30 + v15 + 1) )
    {
      ++v15;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 2) )
    {
      v15 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 3) )
    {
      v15 += 3i64;
      break;
    }
    v15 += 4i64;
    if ( v15 >= 0x10 )
      break;
  }
  for ( i = v15 + 1; i < 0x10; ++i )
    *((_BYTE *)&v30 + i) = 0;
  v17 = xxtea((__int64)user_input, v3, (unsigned __int8 *)&v30, &Size);
  v18 = Size;
  v19 = v17;
  v20 = operator new(Size);
  v21 = 1;
  *v20 = v19[2];
  v22 = v20 + 1;
  v20[1] = *v19;
  v20[2] = v19[3];
  v20[3] = v19[1];
  v20[4] = v19[6];
  v20[5] = v19[4];
  v20[6] = v19[7];
  v20[7] = v19[5];
  v20[8] = v19[10];
  v20[9] = v19[8];
  v20[10] = v19[11];
  v20[11] = v19[9];
  v20[12] = v19[14];
  v20[13] = v19[12];
  v20[14] = v19[15];
  v20[15] = v19[13];
  v20[16] = v19[18];
  v20[17] = v19[16];
  v20[18] = v19[19];
  v20[19] = v19[17];
  v20[20] = v19[22];
  v20[21] = v19[20];
  v20[22] = v19[23];                            // 加密后的数据变换位置存到v20中
  for ( v20[23] = v19[21]; v21 < v18; ++v22 )   // v22=v20+1
  {
    v23 = 0i64;
    if ( v21 / 3 > 0 )                          // 决定异或的次数
    {
      v24 = *v22;
      do
      {
        v24 ^= v20[v23++];
        *v22 = v24;
      }
      while ( v23 < v21 / 3 );
    }
    ++v21;
  }
  *(_QWORD *)&v30 = 0xC0953A7C6B40BCCEui64;     // 注意为小端序
  v25 = v20 - (_BYTE *)&v30;
  *((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
  v26 = 0i64;
  v31 = 0xC8021823;
  v32 = 0xFA5656E7;
  do
  {
    if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )// v30和v20比较
      _exit(v8 * v8);
    ++v8;
    ++v26;
  }
  while ( v26 < 24 );
  v27 = sub_140001620(std::cout, "You win!");
  std::ostream::operator<<(v27, sub_1400017F0);
  return 0;
}

总体思路大致就是:

输入 ——> 取输入的前四个字符 ——> XXTEA加密 ——> 置换顺序 ——> 循环异或 ——> 与明文比较

先解异或和位置变换得到加密后的密文

a=[0xCE,0xBC,0x40,0x6B,0x7C,0x3A,0x95,0xC0,0xEF,0x9B,0x20,0x20,0x91,0xF7,0x02,0x35,0x23,0x18,0x02,0xC8,0xE7,0x56,0x56,0xFA]
b=a
for v21 in range(len(b)-1,-1,-1):
	tmp=v21//3
	if tmp>0:
		for i in range(tmp):
			b[v21]^=b[i]
print(b)
c=[0]*len(b)
d=[2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
e=[]
for i in range(len(b)):
	c[d[i]]=b[i]
for i in range(len(c)):
	e.append(hex(c[i]))
print(e)

得到

然后解 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 xrange(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 xrange(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)

if __name__ == "__main__":  
    key = "flag"
    data1 = [0xbc,0xa5,0xce,0x40,0xf4,0xb2,0xb2,0xe7,0xa9,0x12,0x9d,0x12,0xae,0x10,0xc8,0x5b,0x3d,0xd7,0x6,0x1d,0xdc,0x70,0xf8,0xdc]
    s = "".join(map(chr, data1))
    s = decrypt(s, key)
    print(repr(s))

得到

flag{CXX_and_++tea}

posted @ 2022-01-14 18:08  Moominn  阅读(431)  评论(0编辑  收藏  举报