开始
知识点:
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库:xxtea,xxtea-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:
转