最近我在逆向某个JavaScript,我的目的是将其中的加密函数还原成Python代码。
JavaScript源代码:
function i(n) {
return 4294967295 & n
}
function o(n, e, t, r, i, o) {
return (t >>> 5 ^ e << 2) + (e >>> 3 ^ t << 4) ^ (n ^ e) + (o[3 & r ^ i] ^ t)
}
function(n, e) {
var t, r, a, s, c, l, d = n.length, u = d - 1;
for (r = n[u],
a = 0,
l = 0 | Math.floor(6 + 52 / d); l > 0; --l) {
for (s = (a = i(a + 2654435769)) >>> 2 & 3,
c = 0; c < u; ++c)
t = n[c + 1],
r = n[c] = i(n[c] + o(a, t, r, c, s, e));
t = n[0],
r = n[u] = i(n[u] + o(a, t, r, u, s, e))
}
return n
}
经过一段时间的分析,这段JS代码的加密方式是TEA。
十分感谢lifanxin的博文:python实现tea/xtea/xxtea加密算法___lifanxin的博客-CSDN博客_python xxtea
该博文在Python环境下借助ctype库的c_uint32()函数实现了TEA加密解密算法。由于Python对整数型没有限制,而JavaScript对32位整数的处理是有符号型(signed 32bit int),超出范围的数会变成负数,而Python运算后都是正数。为了使Python运行结果与JavaScript一样有正数也有负数,需要对Python运算后的结果稍微处理一下:
for i in range(len(v)):
v[i]=c_int32(v[i]).value
测试TEA加密的完整Python代码如下:
主程序中的data是将加密前的字符串经过某个加密算法转换成一组整数列表。
key是将密钥字符串经过同样的算法而成的整数列表。
data和key的数是怎么来的,这里不作赘述,因为它们都可以在JavaScript里找得到,而且加密比较简单,本文讲解的是TEA加密算法,需要将这两个列表代入参数进行加密运算。
## TEA加密算法原文:https://blog.csdn.net/A951860555/article/details/120120400
## 下面是我在上述博主原文基础上稍加修改的代码
from ctypes import c_uint32, c_int32
def MX(z, y, total, key, p, e):
temp1 = (z.value>>5 ^ y.value<<2) + (y.value>>3 ^ z.value<<4)
temp2 = (total.value ^ y.value) + (key[(p&3) ^ e.value] ^ z.value)
return c_uint32(temp1 ^ temp2)
def encrypt(n, v, key):
# delta是TEA加密算法的重要参数
delta = 2654435769
rounds = 6 + 52//n
total = c_uint32(0)
z = c_uint32(v[n-1])
e = c_uint32(0)
while rounds > 0:
total.value += delta
e.value = (total.value >> 2) & 3
for p in range(n-1):
y = c_uint32(v[p+1])
v[p] = c_uint32(v[p] + MX(z,y,total,key,p,e).value).value
z.value = v[p]
y = c_uint32(v[0])
v[n-1] = c_uint32(v[n-1] + MX(z,y,total,key,n-1,e).value).value
z.value = v[n-1]
rounds -= 1
# 这是我改进的地方:把unsigned int处理成signed int,超出32bit范围的正整数会变成负数。
for i in range(len(v)):
v[i]=c_int32(v[i]).value
return v
if __name__ == "__main__":
# 加密前的源字符串
ss='appid=201807308440|ctxid=9d23cc620e0dfb601f27711dcec30c64|r=0.48592600736230795'
# data是将加密前的字符串经过下面简单的加密算法转换成一组整数列表。
# 这加密算法比较简单,可以在JavaScript里扒出来。
data = []
ss_len = len(ss)
data = [0]*((ss_len>>2)+2)
data[-1] = ss_len
for i in range(ss_len):
data[i >> 2] |= ord(ss[i]) << ((3 & i) << 3)
'''
data = [1768976481, 808598884, 925906993, 876097587, 1669083188, 1684633716, 845429053, 912483123, 811937842, 912418404, 845558064, 825308983, 1667588964, 912470067, 1030913076, 942943792, 909261109, 859254832, 808661558, 3488055, 79]
'''
# key是密钥经过加密算法后而成的四个整数
key = [1631074661, 926431333, 909271864, 1698128180]
# key的数是怎么来的,这里不作赘述,因为它们都可以在JavaScript里找得到。
# 本文讲解的是TEA加密算法,需要将这两个列表代入encrypt参数进行加密运算。
length = len(data)
# TEA加密
res=encrypt(length, data, key)
print(res)
'''
输出结果:
[716085371, -477396898, 91038733, -105793381, -1817301194, -535430222, 1390850599, 140015488, -1430794631, 1855466254, -24428639, 1179447845, -1111913346, 586757153, -37658271, 1089200005, 848481124, 1301543136, -1437420864, -183487679, 1196366267]
'''