不太简单的简单逆向24(xxtea)

35 篇文章 5 订阅

开始

知识点:
1.xxtea解密
2.算法逆向

1.IDA打开:

__int64 __fastcall sub_1400011A0(__int64 a1, __int64 a2)
{
  unsigned __int64 v2; // rbx
  signed __int64 v3; // rax
  __int128 *v4; // rax
  char *v5; // r11
  __int128 *v6; // r14
  int v7; // edi
  BYTE *v8; // rsi
  BYTE v9; // r10
  int v10; // edx
  __int64 v11; // r8
  unsigned __int64 len; // rcx
  signed __int64 len_; // rcx
  unsigned __int64 v14; // rax
  unsigned __int64 i; // rax
  _BYTE *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 key; // [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_1400018C0(std::cin, a2, (__int64)Code);
  v2 = -1i64;
  v3 = -1i64;
  do
    ++v3;
  while ( *((_BYTE *)Code + v3) );
  if ( v3 != 19 )
  {
    sub_140001620(std::cout, "error\n");
    _exit((unsigned __int64)Code);
  }
  v4 = (__int128 *)sub_140001E5C(5ui64);
  v5 = *(char **)&::Code;                       // qwertyuiopasdfghjklzxcvbnm1234567890
  v6 = v4;
  v7 = 0;
  v8 = (BYTE *)v4;
  do
  {
    v9 = v8[(char *)Code - (char *)v4];         // Code
    v10 = 0;
    *v8 = v9;
    v11 = 0i64;
    len = -1i64;
    do
      ++len;
    while ( v5[len] );                          // len = strlen(::Code) = 36
    if ( len )
    {
      do
      {
        if ( v9 == v5[v11] )
          break;
        ++v10;
        ++v11;
      }                                         // v9(code)的前四位都要在::Code中
      while ( v10 < len );
    }
    len_ = -1i64;
    do
      ++len_;
    while ( v5[len_] );
    if ( v10 == len_ )
      _exit((int)v5);
    ++v8;
  }
  while ( v8 - (BYTE *)v4 < 4 );                // 执行4次
  *((_BYTE *)v4 + 4) = 0;
  do
    ++v2;
  while ( *((_BYTE *)Code + v2) );              // v2 = strlen(Code)
  v14 = 0i64;
  key = *v6;                                    // v6 = v4 = v8 = Coed[0:4](flag)
  while ( *((_BYTE *)&key + v14) )
  {
    if ( !*((_BYTE *)&key + v14 + 1) )
    {
      ++v14;
      break;
    }
    if ( !*((_BYTE *)&key + v14 + 2) )
    {
      v14 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&key + v14 + 3) )
    {
      v14 += 3i64;
      break;
    }
    v14 += 4i64;
    if ( v14 >= 0x10 )
      break;
  }
  for ( i = v14 + 1; i < 0x10; ++i )            // flag000000000000(128位2进制)
    *((_BYTE *)&key + i) = 0;
  v16 = sub_140001AB0((__int64)Code, v2, (unsigned __int8 *)&key, &Size);// xxtea
  v17 = Size;                                   // 加密后的长度
  v18 = v16;                                    // 加密后的结果
  v19 = sub_140001E5C(Size);                    // malloc(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 )   // 从第2个开始
  {
    v22 = 0i64;                                 // 亦或
    if ( v20 / 3 > 0 )
    {
      v23 = *v21;                               // v19 + 1
      do
      {
        v23 ^= v19[v22++];                      // v19[1] ^ v19[0]
        *v21 = v23;
      }
      while ( v22 < v20 / 3 );
    }
    ++v20;
  }
  *(_QWORD *)&key = 0xC0953A7C6B40BCCEi64;
  v24 = v19 - (_BYTE *)&key;
  *((_QWORD *)&key + 1) = 0x3502F79120209BEFi64;// 因为这里的赋值为int,要考虑大小端,小端(高位高地址),地位低地址
                                                // 0xCE,0xBC,0x40,0x6B,0x7C,0x3A,0x95,0xC0,0xEF,0x9B,0x20,0x20,0x91,0xF7,0x02,0x35
  v25 = 0i64;
  v30 = 0xC8021823;                             // 因为上面有16个字节,刚好就是绝对地址空间的路程。接着
  v31 = 0xFA5656E7;
  do
  {
    if ( *((_BYTE *)&key + v25) != *((_BYTE *)&key + v25 + v24) )// = *(v19 + v25)
      _exit(v7 * v7);
    ++v7;
    ++v25;
  }
  while ( v25 < 24 );
  v26 = sub_140001620(std::cout, "You win!");
  std::basic_ostream<char,std::char_traits<char>>::operator<<(v26, sub_1400017F0);
  return 0i64;
}

很长,但是别慌
按照一步一步分析,见代码注释
v19 = ’CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA‘

注意大小端的问题

写出逆向脚本,可是我这里遇到了很多问题,因为没有细看密码学,xxtea想使用工具,没找到在线工具。
了解到python库:xxteaxxtea-py
先使用的xxtea,可一直报错。最后报错说非法对齐
于是我用了xxtea-py
解码没有问题。

但是在逆向算法的时候,我发现python3在chr()转换后不会像python2那样转换不了字符串保留字节流,python3会使用扩展ascii码,通过调试,发现这会导致数据丢失。

但如果使用python,在使用xxtea时我又报错了:
在这里插入图片描述
捣鼓了半天,最后只能使用python2逆向,python3解码。

也可以全程使用python2,但是xxtea解码需要自己编写

先第一种方式的脚本:
python2:

# 转换为16进制
arr = 'CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA'.decode('hex')

dec = ''

# 因为加密时是正向加密,会用到加密之后的字符,因此解密需要逆向解密
for i in range(7,-1,-1):
    res = ''
    # 每3个为一组
    for j in range(3):
        temp = ord(arr[i*3+j])
        # 需要异或的值,例如第i组的值就是,arr[i*3+j]^(arr[n] for n in range(i))
        for m in range(i):
            temp ^= ord(arr[m])
        res += chr(temp)
    dec = res + dec


# 原来的v18到v19数组是被打乱排序了的
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]
enc = [0] * 24

# key需要是16位
key = 'flag'+'\x00'*12
for i in range(24):
    enc[num[i]] = dec[i]
dec2 = ''.join(enc)

在这里插入图片描述

python3:

import xxtea

p = b'\xbc\xa5\xce@\xf4\xb2\xb2\xe7\xa9\x12\x9d\x12\xae\x10\xc8[=\xd7\x06\x1d\xdcp\xf8\xdc'
#因为xxtea要输入字节流

key = "flag"
decrypt_data = xxtea.decrypt(p, key)
print(decrypt_data);

在这里插入图片描述

只是用python2:

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)

def xor(x ,y):
    return ord(x) ^ ord(y)

# 转换为16进制
arr = 'CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA'.decode('hex')

dec = ''

# 因为加密时是正向加密,会用到加密之后的字符,因此解密需要逆向解密
for i in range(7,-1,-1):
    res = ''
    # 每3个为一组
    for j in range(3):
        temp = ord(arr[i*3+j])
        # 需要异或的值,例如第i组的值就是,arr[i*3+j]^(arr[n] for n in range(i))
        for m in range(i):
            temp ^= ord(arr[m])
        res += chr(temp)
    dec = res + dec


# 原来的v18到v19数组是被打乱排序了的
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]
enc = [0] * 24

# key需要是16位
key = 'flag'+'\x00'*12
for i in range(24):
    enc[num[i]] = dec[i]
dec2 = ''.join(enc)
dec3 = decrypt(dec2, key)
print dec3

在这里插入图片描述

附件:
如果填入的是字符串形式需要使用
Python3中bytes类型转换为str类型

ascii码扩展表:

参考wp:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I Am Rex

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值