好久没写文章了,最近刚转正比较忙,今天有空把业务中写过的一个滑块来给大家讲讲吧。
话不多说直接上网站:aHR0cHMlM0EvL2FjY291bnQueW91emFuLmNvbS9sb2dpbg==
直接开搞:
第一步;抓包分析:
我们多刷新抓几次包分析可以得到下面这些结论:
token:统一请求标识
bizType:固定
bizData:
captchaType:固定
userBechaviorData:轨迹加密**
我们发现token是前面返回的那么整个接口加密就剩一个userBehaviorData了
那就简单了啊 我们直接全局搜索:
找到位置打上断点,在滑一次滑块。
在控制台输出一下加密的值:
然后输出一下加密后的结果:
果然是这个地方,那我们只需要构造出来加密参数,和扣出加密算法就行了。
来
喽他!
加密参数的分析:
“{“cx”:230,“cy”:43,“scale”:0.5,“slidingEvents”:[{“mx”:40,“my”:211,“ts”:1595474135296},{“mx”:1,“my”:0,“ts”:39},{“mx”:3,“my”:0,“ts”:8},{“mx”:5,“my”:0,“ts”:9},{“mx”:5,“my”:0,“ts”:7},{“mx”:7,“my”:0,“ts”:9},{“mx”:9,“my”:-1,“ts”:7},{“mx”:14,“my”:-1,“ts”:9},{“mx”:14,“my”:-1,“ts”:7},{“mx”:14,“my”:-2,“ts”:9},{“mx”:14,“my”:-2,“ts”:7},{“mx”:17,“my”:-1,“ts”:9},{“mx”:20,“my”:-1,“ts”:8},{“mx”:20,“my”:-1,“ts”:8},{“mx”:24,“my”:0,“ts”:8},{“mx”:20,“my”:-2,“ts”:8},{“mx”:20,“my”:-1,“ts”:8},{“mx”:17,“my”:-1,“ts”:8},{“mx”:13,“my”:0,“ts”:8},{“mx”:11,“my”:0,“ts”:8},{“mx”:15,“my”:0,“ts”:7},{“mx”:11,“my”:0,“ts”:8},{“mx”:9,“my”:0,“ts”:8},{“mx”:6,“my”:0,“ts”:8},{“mx”:3,“my”:1,“ts”:10},{“mx”:3,“my”:0,“ts”:6},{“mx”:1,“my”:0,“ts”:8}]}”
我们观察到他的json格式都为x,y,t 格式
“cx”:230,“cy”:43,“scale”:0.5
前面这里我们猜测cx=230为滑块缺口,cy=43为鼠标点击高度,scale=0.5为滑动时间。
[{“mx”:40,“my”:211,“ts”:1595474135296}
后面这一部分json我们猜测是在一段时间是收集x和y和t的移动距离
ts在[6,7,8,9,10]这个区间里,那么我们只需要将全部x坐标加起来等于230,就知道他是不是这样检测的。
我们发现结果不等于,所以我们暂时不知道他是检测什么的遇到这种情况我们直接写死试试,最后发现果然
他自己都不会检测这个轨迹。
所以我们直接保存一条轨迹出来,替换里面的时间戳和终点坐标就行。
def distcance(juli):
x='{"cx":'+str(int((juli)/2))+',"cy":18,"scale":0.5,"slidingEvents":[{"mx":40,"my":196,"ts":'+str(int(time.time()*1000))+'}' \
',{"mx":1,"my":0,"ts":1},{"mx":1,"my":-1,"ts":8},{"mx":1,"my":0,"ts":8},{"mx":4,"my":0,"ts":9},{"mx":3,"my":-1,"ts":7},' \
'{"mx":7,"my":-1,"ts":8},{"mx":12,"my":-1,"ts":7},{"mx":12,"my":-1,"ts":9},{"mx":19,"my":-2,"ts":7},{"mx":22,"my":-1,"ts":9},' \
'{"mx":31,"my":-2,"ts":7},{"mx":33,"my":-1,"ts":8},{"mx":35,"my":-2,"ts":8},{"mx":38,"my":0,"ts":8},{"mx":42,"my":-2,"ts":8},' \
'{"mx":43,"my":0,"ts":8},{"mx":43,"my":0,"ts":8},{"mx":44,"my":0,"ts":8},{"mx":46,"my":0,"ts":8},{"mx":38,"my":0,"ts":8},' \
'{"mx":38,"my":0,"ts":8},{"mx":33,"my":-1,"ts":8},{"mx":25,"my":-2,"ts":8},{"mx":19,"my":0,"ts":8},{"mx":15,"my":0,"ts":8},' \
'{"mx":9,"my":-1,"ts":8},{"mx":11,"my":0,"ts":8},{"mx":4,"my":-1,"ts":8},{"mx":6,"my":0,"ts":8},{"mx":1,"my":0,"ts":8}]}'
with open(r'get_data.js', 'r', encoding='UTF-8')as f:
ua_js = f.read().encode().decode("gbk", 'ignore')
js_data = execjs.compile(ua_js)
key = js_data.call('get', x)
return key
参数分析完了 ,我们来分析加密函数:
逆向userBechaviorData算法
为对称加密AES,采用cbc填充方式,iv为偏移值
我们可用python进行改写,也可以直接扣js
这里我们采用直接扣去js的方法
我们跟进去发现:
他所有的方法都在这个里面
但是我们直接抠下来并不能直接用,因为他被
void 0 === (r = function(t, e, n) {})
包着的我们需要自己稍微改写下:
var wGdk = function(t, e, n) {
var r;
var r, o, i = i || function(t, e) {
var n = {}, r = n.lib = {}, o = function() {}, i = r.Base = {
extend: function(t) {
o.prototype = this;
var e = new o;
return t && e.mixIn(t), e.hasOwnProperty("init") || (e.init = function() {
e.$super.init.apply(this, arguments)
}), e.init.prototype = e, e.$super = this, e
},
create: function() {
var t = this.extend();
return t.init.apply(t, arguments), t
},
init: function() {},
mixIn: function(t) {
for (var e in t)
t.hasOwnProperty(e) && (this[e] = t[e]);
t.hasOwnProperty("toString") && (this.toString = t.toString)
},
clone: function() {
return this.init.prototype.extend(this)
}
}, u = r.WordArray = i.extend({
init: function(t, e) {
t = this.words = t || [], this.sigBytes = null != e ? e : 4 * t.length
},
toString: function(t) {
return (t || c).stringify(this)
},
concat: function(t) {
var e = this.words,
n = t.words,
r = this.sigBytes;
if (t = t.sigBytes, this.clamp(), r % 4) for (var o = 0; o < t; o++)
e[r + o >>> 2] |= (n[o >>> 2] >>> 24 - o % 4 * 8 & 255) << 24 - (r + o) % 4 * 8;
else if (65535 < n.length) for (o = 0; o <