系列篇第一篇抓包分析我们就讲到,破解w参数,是我们破解极验的关键,抓包过程也没有发现userresponse参数的踪迹,那为什么我们要介绍userresponse参数生成呢?如果你之前有过极验(一代)的破解经验,对这个参数肯定不陌生。我们在第二篇反混淆解密十六进制字符串的过程中,尝试搜索gt,曾经意外发现主了人公w,那我们在利用Google浏览器进行js调试之前,先简单看一下这段反混淆代码(第1424行)
这块代码很简单,‘w’ = r7z + H7z,而r7z 和 H7z 是由变量Y7z和V7z经过相关函数处理生成的,我们先尝试找下Y7z和V7z这两个变量的定义
根据前面的分析,我们需要在geetest.6.0.9.js文件的第1384行处打断点,具体调试过程不再演示
根据调试过程,整理出’userresponse’参数生成的js代码
'\x75\x73\x65\x72\x72\x65\x73\x70\x6f\x6e\x73\x65': i7B[M9r.R8z(722)](g7z, V7z[M9r.C8z(190)][M9r.R8z(425)]);
i7B[M9r.C8z(722)] = function(L0z, o0z) {
var c1r = M9r.k9r()[2][7][21];
while (c1r !== M9r.L9r()[18][12][0]) {
switch (c1r) {
case M9r.L9r()[15][39][27]:
X0z++;
c1r = M9r.k9r()[13][28][42];
break;
case M9r.L9r()[6][22][30]:
return x0z;
c1r = M9r.L9r()[44][40][0];
break;
case M9r.k9r()[32][7][37][17]:
X0z++;
c1r = M9r.L9r()[31][47][3];
break;
case M9r.L9r()[20][9][15]:
n0z = o0z[M9r.R8z(169)](X0z),
Q0z[n0z] || (Q0z[n0z] = 1,
f0z[N0z][M9r.C8z(340)](n0z),
N0z++,
N0z = 5 == N0z ? 0 : N0z);
Y4r = Y4r >= 19614 ? Y4r / 7 : Y4r * 7;
c1r = M9r.L9r()[29][13][28][35];
break;
case M9r.L9r()[16][14][18]:
c1r = v0z > 0 && g4r * (g4r + 1) * g4r % 2 == 0 ? M9r.k9r()[19][35][39] : M9r.k9r()[18][46][30];
break;
case M9r.L9r()[26][25][3]:
c1r = X0z < i0z && Y4r * (Y4r + 1) * Y4r % 2 == 0 ? M9r.k9r()[31][19][15] : M9r.k9r()[20][33][39];
break;
case M9r.L9r()[14][47][21]:
var n0z, f0z = [[], [], [], [], []], Q0z = {}, N0z = 0;
X0z = 0;
c1r = M9r.L9r()[15][19][15];
break;
case M9r.k9r()[20][42][30]:
var j0z = o0z[M9r.C8z(504)](32)
, c0z = []
, X0z = 0;
c1r = M9r.L9r()[43][16][42];
break;
case M9r.L9r()[43][27][15]:
var i0z = o0z[M9r.C8z(40)];
c1r = M9r.L9r()[0][45][3];
break;
case M9r.L9r()[27][8][1][20]:
o0z = o0z[M9r.C8z(504)](0, 32);
c1r = M9r.L9r()[1][9][21];
break;
case M9r.L9r()[42][40][36]:
var K0z = j0z[M9r.R8z(458)](X0z);
c0z[X0z] = K0z > 57 ? K0z - 87 : K0z - 48;
F4r = F4r >= 10020 ? F4r / 5 : F4r * 5;
c1r = M9r.L9r()[0][21][27];
break;
case M9r.k9r()[3][26][0]:
g4r = g4r > 32264 ? g4r / 5 : g4r * 5;
c1r = M9r.k9r()[25][44][18];
break;
case M9r.k9r()[44][23][33]:
j0z = 36 * c0z[0] + c0z[1];
var k0z = Math[M9r.R8z(47)](L0z) + j0z;
c1r = M9r.k9r()[47][0][18];
break;
case M9r.L9r()[35][3][39]:
var y0z, v0z = k0z, B0z = 4, x0z = M9r.C8z(346), I0z = [1, 2, 5, 10, 50];
c1r = M9r.k9r()[35][40][18];
break;
case M9r.k9r()[26][7][17][13]:
var g4r = 6;
var Y4r = 7;
var F4r = 3;
c1r = M9r.k9r()[46][22][30];
break;
case M9r.L9r()[21][44][42]:
c1r = X0z < j0z[M9r.R8z(40)] && F4r * (F4r + 1) % 2 + 6 ? M9r.k9r()[6][16][36] : M9r.k9r()[36][7][33];
break;
case M9r.L9r()[8][25][39]:
v0z - I0z[B0z] >= 0 ? (y0z = parseInt(Math[M9r.R8z(12)]() * f0z[B0z][M9r.R8z(40)], 10),
x0z += f0z[B0z][y0z],
v0z -= I0z[B0z]) : (f0z[M9r.C8z(448)](B0z, 1),
I0z[M9r.R8z(448)](B0z, 1),
B0z -= 1);
c1r = M9r.L9r()[31][34][0];
break;
}
}
}
是不是一脸懵逼??????我们来看下反混淆之后的
'userresponse': i7B["C"](g7z, V7z["d"]["challenge"]);
i7B["C"] = function(L0z, o0z) {
var c1r = 27;
while (c1r !== 0) {
switch (c1r) {
case 21:
X0z++;
c1r = 38;
break;
case 34:
return x0z;
c1r = 0;
break;
case 39:
X0z++;
c1r = 45;
break;
case 17:
n0z = o0z["charAt"](X0z),
Q0z[n0z] || (Q0z[n0z] = 1,
f0z[N0z]["push"](n0z),
N0z++,
N0z = 5 == N0z ? 0 : N0z);
Y4r = Y4r >= 19614 ? Y4r / 7 : Y4r * 7;
c1r = 39;
break;
case 30:
c1r = v0z > 0 && g4r * (g4r + 1) * g4r % 2 == 0 ? 9 : 34;
break;
case 45:
c1r = X0z < i0z && Y4r * (Y4r + 1) * Y4r % 2 == 0 ? 17 : 41;
break;
case 43:
var n0z, f0z = [[], [], [], [], []], Q0z = {}, N0z = 0;
X0z = 0;
c1r = 1;
break;
case 2:
var j0z = o0z["slice"](32)
, c0z = []
, X0z = 0;
c1r = 38;
break;
case 1:
var i0z = o0z["length"];
c1r = 45;
break;
case 14:
o0z = o0z["slice"](0, 32);
c1r = 43;
break;
case 28:
var K0z = j0z["charCodeAt"](X0z);
c0z[X0z] = K0z > 57 ? K0z - 87 : K0z - 48;
F4r = F4r >= 10020 ? F4r / 5 : F4r * 5;
c1r = 21;
break;
case 32:
g4r = g4r > 32264 ? g4r / 5 : g4r * 5;
c1r = 30;
break;
case 31:
j0z = 36 * c0z[0] + c0z[1];
var k0z = Math["round"](L0z) + j0z;
c1r = 14;
break;
case 41:
var y0z, v0z = k0z, B0z = 4, x0z = "", I0z = [1, 2, 5, 10, 50];
c1r = 30;
break;
case 27:
var g4r = 6;
var Y4r = 7;
var F4r = 3;
c1r = 2;
break;
case 38:
c1r = X0z < j0z["length"] && F4r * (F4r + 1) % 2 + 6 ? 28 : 31;
break;
case 9:
v0z - I0z[B0z] >= 0 ? (y0z = parseInt(Math["random"]() * f0z[B0z]["length"], 10),
x0z += f0z[B0z][y0z],
v0z -= I0z[B0z]) : (f0z["splice"](B0z, 1),
I0z["splice"](B0z, 1),
B0z -= 1);
c1r = 32;
break;
}
}
}
很明显,反混淆之后,代码逻辑很容易就可以读明白,我们把代码用python改写下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# // var Y7z = {
# // 'userresponse': i7B["C"](42, V7z["d"]["challenge"]),
# // 'passtime': c7B["a"]("endTime", V7z["b"])["getTime"]() - c7B["a"]("startTime", V7z["b"]),
# // 'imgload': c7B["a"]("imgload", V7z["b"]),
# // 'aa': F7z,
# // 'ep': i7B["Vb"](V7z)
# // };
import random
def get_userresponse(L0z, o0z):
'''TODO
获取userresponse
参数:
L0z 滑动的最后x坐标位置
o0z 极验配置的challenge参数 eg '22ff2f326624b638791dfdef7892700d9w'
返回值:
userresponse eg 4114411168e
'''
g4r = 6
Y4r = 7
F4r = 3
j0z = o0z[32:]
c0z = []
for j in j0z:
K0z = ord(j)
c0z.append(K0z - 87 if K0z > 57 else K0z - 48)
F4r = F4r / 5 if F4r >= 10020 else F4r * 5
j0z = 36 * c0z[0] + c0z[1]
k0z = round(L0z) + j0z
o0z = o0z[:32]
n0z = 0
f0z = [[], [], [], [], []]
Q0z = {}
N0z = 0
i0z = len(o0z)
for i in o0z:
n0z = i
if not Q0z.get(n0z):
Q0z[n0z] = 1
f0z[N0z].append(n0z)
N0z += 1
N0z = 0 if 5 == N0z else N0z
Y4r = Y4r / 7 if Y4r >= 19614 else Y4r * 7
y0z, v0z = 0, k0z
B0z = 4
x0z = ""
I0z = [1, 2, 5, 10, 50]
while 1:
if v0z > 0:
if v0z - I0z[B0z] >= 0:
y0z = int(random.random() * len(f0z[B0z]))
x0z += f0z[B0z][y0z]
v0z -= I0z[B0z]
else:
f0z.pop(B0z)
I0z.pop(B0z)
B0z -= 1
g4r = g4r / 5 if g4r > 32264 else g4r * 5
else:
return x0z
def main():
o0z = '22ff2f326624b638791dfdef7892700d9w'
L0z = 58
print(get_userresponse(L0z,o0z))
if __name__ == '__main__':
main()
- 我们首先简单看下反混淆之后的代码,能够很快的帮助我们定位调试断点的位置
- 'userresponse’参数的生成相对简单,js反混淆之后也能很容易的读明白其中的逻辑
- 至于生成userresponse值的两个参数L0z和 o0z,可以到后期在做分析,这里主要是说明userresponse的生成,其他的值,可看做常量
- js和python代码的执行结果有差异,是因为代码中有用到随机值,拿到的结果,即便写入的L0z和 o0z参数值相同,也会得到不同的结果,是正常情况
- 其他参数’passtime’, ‘imgload’, ‘aa’, ‘ep’,调试方式和 'userresponse’大差不差,后续在介绍的时候,不再这么详细的赘述,感兴趣的伙伴后续的可以自行研究了。
- 下一篇我们将介绍’aa’参数值的生成。
文档仅作学习和记录使用,请不要用于商业和违法用途,如有侵权,请告知删除。