极验验证码(6.0.9)破解(四) 之 'aa' 参数调试和分析
文章目录
文章目录
1. 回顾
2. 1 针对aa参数的js断点调试
3. 总结
1. 回顾
上篇文章[1] 介绍了'userresponse' 参数调试和分析,并将js执行过程整理出来,整理成python代码。 今天我们继续进行极验破解,这次我们介绍 'aa'参数的生成,距离上篇文章,已经过去快三个月了,工作很忙,又忙着结婚,一直抽不出来空,或者静不下心来写博客,今天总算是忙里偷闲,也让自己沉淀一下,准备更新极验破解第4篇 正当我撸起袖子准备大干一番的时候,发现我的目标网站,关闭了相关功能页面,不过还好基础页面还在,我还能接着用它的极验滑块接着干,哈哈
不废话了,这次我们直接进入正题
2. 针对aa参数的js断点调试
根据前面的分析,我们先看一下文件geetest.6.0.9.js的第1387行,不知道为啥直接定位这一行的,可以看下之前的文章我们先在1382行处打一个断点,期望能够获取变量‘F7z ’的值,而由
F7z = p7B["t"](V7z["A"] + p7B["B"]("REFb0UEJ") + F7z
我们知道,这里已经有了右侧F7z的值,因此,我们尝试在geetest.6.0.9.js文件中搜索'F7z' ,看能否找到F7z的变量声明的地方,我们找到了 1410行因此这里也需要打上断点此时就可以开始js调试了,根据调试过程和变量追踪,还是要自己耐住性子一步步来,关于断点调试要说的东西太多,这里还是跳过调试过程,直接给出我整理出'aa'参数生成的js代码(用反混淆之后的js代码)
//V7z["b"] = 1562138812095 2019-07-03 15:26:52
// F7z = "B-/./.(!!Bs(y((((yyysssssssss(!!($)L34434343443B3VB$.3e$)G$,V"
""
// B-/./.(!!BsR(y((((yyysssssssss(!!($)L344343(43443B3VVB$.3e$)G$,V
// var g7z = parseInt(a7z), F7z = e7B["t"](V7z["b"]);
function e7B_t(K1z) {
var X8r = 27;
while (X8r !== 19) {
switch (X8r) {
case 27:
var o5r = 6;
X8r = 24;
break;
case 24:
var N1z, X1z = s6z(c7B["a"]("arr", K1z)), f1z = [], B1z = [], o1z = [], t1z = 0, j1z = X1z["length"];
X8r = 13;
break;
case 13:
X8r = o5r * (o5r + 1) % 2 + 8 && t1z < j1z ? 2 : 20;
break;
case 2:
N1z = u6z(X1z[t1z]),
N1z ? B1z["push"](N1z) : (f1z["push"](O6z(X1z[t1z][0])),
B1z["push"](O6z(X1z[t1z][1]))),
o1z["push"](O6z(X1z[t1z][2]));
o5r = o5r >= 17705 ? o5r / 3 : o5r * 3;
X8r = 28;
break;
case 20:
return f1z["join"]("") + "!!" + B1z["join"]("") + "!!" + o1z["join"]("");
X8r = 19;
break;
case 28:
t1z++;
X8r = 13;
break;
}
}
};
c7B["a"] = function(X2z, B2z) {
var V0r = 27;
while (V0r !== 24) {
switch (V0r) {
case 27:
return c7B["Na"][B2z][X2z];
V0r = 24;
break;
}
}
};
// F6z = [-21, -21, 0], [0, 0, 0], [1, 0, 96], [5, 0, 106], [8, 0, 117], [14, 0, 128], [19, 0, 138], [25, 0, 149], [30, 0, 159], [33, 0, 170], [36, 0, 180], [39, 0, 191], [40, 0, 202], [41, 0, 212], [42, 0, 233], [43, 0, 243], [44, 0, 284], [45, 0, 305], [46, 0, 640], [47, 0, 691], [48, 0, 782], [48, 0, 1018]
s6z = function(F6z) {
var R1r = 27;
while (R1r !== 19) {
switch (R1r) {
case 27:
var N5r = 9;
R1r = 24;
break;
case 13:
R1r = J6z < l6z && N5r * (N5r + 1) % 2 + 7 ? 2 : 20;
break;
case 2:
Y6z = Math["round"](F6z[J6z + 1][0] - F6z[J6z][0]),
g6z = Math["round"](F6z[J6z + 1][1] - F6z[J6z][1]),
a6z = Math["round"](F6z[J6z + 1][2] - F6z[J6z][2]),
P6z["push"]([Y6z, g6z, a6z]),
0 == Y6z && 0 == g6z && 0 == a6z || (0 == Y6z && 0 == g6z ? D6z += a6z : (E6z["push"]([Y6z, g6z, a6z + D6z]),
D6z = 0));
N5r = N5r > 34958 ? N5r / 6 : N5r * 6;
R1r = 28;
break;
case 24:
var Y6z, g6z, a6z, E6z = [], D6z = 0, P6z = [], J6z = 0, l6z = F6z["length"] - 1;
R1r = 13;
break;
case 28:
J6z++;
R1r = 13;
break;
case 20:
return 0 !== D6z && E6z["push"]([Y6z, g6z, D6z]),
E6z;
R1r = 19;
break;
}
}
};
// R6z = [21, 21, 0]
u6z = function(R6z) {
var t8r = 27;
while (t8r !== 21) {
switch (t8r) {
case 2:
t8r = R6z[0] == z6z[h6z][0] && R6z[1] == z6z[h6z][1] ? 38 : 28;
break;
case 24:
var z6z = [[1, 0], [2, 0], [1, -1], [1, 1], [0, 1], [0, -1], [3, 0], [2, -1], [2, 1]]
, h6z = 0
, C6z = z6z["length"];
t8r = 13;
break;
case 27:
var f5r = 9;
t8r = 24;
break;
case 38:
return "stuvwxyz~"[h6z];
t8r = 21;
break;
case 13:
t8r = h6z < C6z && f5r * (f5r + 1) % 2 + 7 ? 2 : 19;
break;
case 20:
h6z++;
t8r = 13;
break;
case 19:
return 0;
t8r = 21;
break;
case 28:
f5r = f5r >= 62252 ? f5r - 6 : f5r + 6;
t8r = 20;
break;
}
}
};
//r6z = 26
O6z = function (r6z) {
var C1r = 27;
while (C1r !== 38) {
switch (C1r) {
case 27:
var d6z = "()*,-./0123456789:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqr"
, m6z = d6z["length"]
, Z6z = ""
, H6z = Math["abs"](r6z)
, W6z = parseInt(H6z / m6z);
W6z >= m6z && (W6z = m6z - 1),
W6z && (Z6z = d6z["charAt"](W6z)),
H6z %= m6z;
var q6z = "";
return r6z < 0 && (q6z += "!"),
Z6z && (q6z += "$"),
q6z + Z6z + d6z["charAt"](H6z);
C1r = 38;
break;
}
}
};
var F7z = e7B_t(V7z["b"]);
//v1z = [12, 58, 98, 36, 43, 95, 62, 15, 12]
// T1z = "764b354e"
F7z = e7B["u"](F7z, V7z["d"]["c"], V7z["d"]["s"]);
function e7B_u(Q1z, v1z, T1z) {
var B8r = 27;
while (B8r !== 14) {
switch (B8r) {
case 20:
x1z += 2;
var n1z = parseInt(i1z, 16)
, M1z = String["fromCharCode"](n1z)
, I1z = (y1z * n1z * n1z + k1z * n1z + L1z) % Q1z["length"];
c1z = c1z["substr"](0, I1z) + M1z + c1z["substr"](I1z);
B8r = 31;
break;
case 27:
var K5r = 2;
var j5r = 4;
B8r = 13;
break;
case 13:
B8r = (!v1z || !T1z) && j5r * (j5r + 1) * j5r % 2 == 0 ? 2 : 38;
break;
case 2:
return Q1z;
B8r = 14;
break;
case 31:
K5r = K5r > 10375 ? K5r / 8 : K5r * 8;
B8r = 28;
break;
case 28:
B8r = (i1z = T1z["substr"](x1z, 2)) && K5r * (K5r + 1) * K5r % 2 == 0 ? 20 : 23;
break;
case 38:
var i1z, x1z = 0, c1z = Q1z, y1z = v1z[0], k1z = v1z[2], L1z = v1z[4];
B8r = 28;
break;
case 23:
return c1z;
B8r = 14;
break;
}
}
};
将js逻辑改写成pyhon代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/7/4 9:41
# @Author : SpiritedAway1106
# @File : aa
# @Software: PyCharm
# @Description : 获取aa参数的值
# 对aa 进行二次加密,拿到最后结果
def e7B_u(Q1z=None, v1z=None, T1z=None):
'''TODO
对aa进行二次加密
参数:
Q1z 首次加密的aa值 eg 'B-/./.(!!Bs(y((((yyysssssssss(!!($)L34434343443B3VB$.3e$)G$,V'
v1z 极验配置的c参数 eg [12, 58, 98, 36, 43, 95, 62, 15, 12]
T1z 极验配置的参数 eg '764b354e'
返回值:
aa二次加密结果 eg
'''
Q1z, v1z, T1z = 'B-/./.(!!Bs(y((((yyysssssssss(!!($)L34434343443B3VB$.3e$)G$,V',[12, 58, 98, 36, 43, 95, 62, 15, 12],'764b354e'
if v1z and T1z :
i1z = ''
x1z = 0
c1z = Q1z
y1z = v1z[0]
k1z = v1z[2]
L1z = v1z[4]
while 1:
i1z = T1z[x1z:x1z+2]
if i1z:
x1z += 2
n1z = int(i1z, 16)
M1z = chr(n1z)
I1z = (y1z * n1z * n1z + k1z * n1z + L1z) % len(Q1z)
c1z = c1z[:I1z] + M1z + c1z[I1z:]
else:
return c1z
else:
return Q1z
# 返回aa的首次加密值,传入滑动轨迹tracks
def e7B_t(tracks=[]):
'''TODO
对aa 进行首次加密
参数:
tracks 滑动路径,三元组列表[[x,y,time]] eg [[-21, -21, 0], [0, 0, 0], [1, 0, 96], [5, 0, 106], [8, 0, 117], [14, 0, 128], [19, 0, 138], [25, 0, 149],
[30, 0, 159], [33, 0, 170], [36, 0, 180], [39, 0, 191], [40, 0, 202], [41, 0, 212], [42, 0, 233],
[43, 0, 243], [44, 0, 284], [45, 0, 305], [46, 0, 640], [47, 0, 691], [48, 0, 782], [48, 0, 1018]]
返回值:
'''
o5r = 6
N1z = ''
tracks = [[-21, -21, 0], [0, 0, 0], [1, 0, 96], [5, 0, 106], [8, 0, 117], [14, 0, 128], [19, 0, 138], [25, 0, 149],
[30, 0, 159], [33, 0, 170], [36, 0, 180], [39, 0, 191], [40, 0, 202], [41, 0, 212], [42, 0, 233],
[43, 0, 243], [44, 0, 284], [45, 0, 305], [46, 0, 640], [47, 0, 691], [48, 0, 782], [48, 0, 1018]]
X1z = s6z(tracks)
f1z = []
B1z = []
o1z = []
for t1z, X in enumerate(X1z):
if o5r * (o5r + 1) % 2 + 8:
N1z = u6z(X)
if N1z:
B1z.append(N1z)
else:
f1z.append(O6z(X[0]))
B1z.append(O6z(X[1]))
o1z.append(O6z(X[2]))
o5r = o5r / 3 if o5r >= 17705 else o5r * 3
return ''.join(f1z) + "!!" + ''.join(B1z) + "!!" + ''.join(o1z)
def O6z(r6z=26):
'''TODO
按规则映射数字和字符
参数:
r6z eg 26
返回值:
目标字符 G
'''
d6z = "()*,-./0123456789:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqr"
m6z = len(d6z)
Z6z = ""
H6z = abs(r6z)
W6z = int(H6z / m6z)
if W6z >= m6z:
W6z = m6z - 1
if W6z:
Z6z = d6z[W6z]
H6z %= m6z
q6z = ""
if r6z < 0:
q6z += "!"
if Z6z:
q6z += "$"
return q6z + Z6z + d6z[H6z]
def u6z(R6z=[]):
'''TODO
将路径映射成单个字符
参数:
R6z 处理后路径中的其中一个元组 eg [21, 21, 0]
返回值:
映射结果 eg 0
'''
R6z = [21, 21, 0]
z6z = [[1, 0], [2, 0], [1, -1], [1, 1], [0, 1], [0, -1], [3, 0], [2, -1], [2, 1]]
for h6z ,z in enumerate(z6z):
if R6z[0] == z6z[h6z][0] and R6z[1] == z6z[h6z][1]:
return "stuvwxyz~"[h6z]
return 0
def s6z(F6z=[]):
'''TODO
规整滑动路径列表,整理成[x移动距离,y移动距离,时间间隔]元组
参数:
F6z 滑动路径 eg [[-21, -21, 0], [0, 0, 0], [1, 0, 96], [5, 0, 106], [8, 0, 117], [14, 0, 128], [19, 0, 138], [25, 0, 149],
[30, 0, 159], [33, 0, 170], [36, 0, 180], [39, 0, 191], [40, 0, 202], [41, 0, 212], [42, 0, 233],
[43, 0, 243], [44, 0, 284], [45, 0, 305], [46, 0, 640], [47, 0, 691], [48, 0, 782], [48, 0, 1018]]
返回值:
规整后路径位移元组 eg [[21, 21, 0], [1, 0, 96], [4, 0, 10], [3, 0, 11], [6, 0, 11], [5, 0, 10], [6, 0, 11], [5, 0, 10], [3, 0, 11], [3, 0, 10], [3, 0, 11], [1, 0, 11], [1, 0, 10], [1, 0, 21], [1, 0, 10], [1, 0, 41], [1, 0, 21], [1, 0, 335], [1, 0, 51], [1, 0, 91], [0, 0, 236]]
'''
# F6z = [[-21, -21, 0], [0, 0, 0], [1, 0, 96], [5, 0, 106], [8, 0, 117], [14, 0, 128], [19, 0, 138], [25, 0, 149],
# [30, 0, 159], [33, 0, 170], [36, 0, 180], [39, 0, 191], [40, 0, 202], [41, 0, 212], [42, 0, 233],
# [43, 0, 243], [44, 0, 284], [45, 0, 305], [46, 0, 640], [47, 0, 691], [48, 0, 782], [48, 0, 1018]]
Y6z = 0
g6z = 0
a6z = 0
E6z = []
D6z = 0 # 滑动消耗总时间
P6z = []
l6z = len(F6z) - 1
for J6z, F in enumerate(F6z):
if J6z < l6z:
Y6z = round(F6z[J6z + 1][0] - F6z[J6z][0])
g6z = round(F6z[J6z + 1][1] - F6z[J6z][1])
a6z = round(F6z[J6z + 1][2] - F6z[J6z][2])
P6z.append([Y6z, g6z, a6z])
if 0 == Y6z and 0 == g6z and 0 == a6z:
pass
else:
if 0 == Y6z and 0 == g6z:
D6z += a6z
else:
E6z.append([Y6z, g6z, a6z + D6z])
D6z = 0
else:
if 0 != D6z:
E6z.append([Y6z, g6z, D6z])
return E6z
def main():
print(e7B_u())
if __name__ == '__main__':
main()
3. 总结
❝❞
再次强调,反混淆之后的js文件很重要,如果有耐心,甚至可以不在线调试js,直接剥离出‘aa’参数的相关js和执行顺序 调试一定要有耐心!!!!,几乎每次都会在总结里说 代码中的注释还算详细,调试过程中,可根据js中实际变量值,替换py文件中的变量,验证代码是否有效和正确
Reference
极验验证码(6.0.9)破解(三) 之 'userresponse' 参数调试和分析: https://blog.csdn.net/SpiritedAway1106/article/details/98958925
评论