本文主要是介绍顶象滑块的js逆向分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
顶象滑块的js逆向分析
- 一、引言
- 1.1 声明
- 1.2 简介
- 1.3 待办
- 二、验证步骤
- 2.1 c1请求,获取data
- 2.2 a请求,获取图片地址
- 2.3 v1请求,滑块验证
- 三、过程解析
- 3.1 图片还原
- 3.2 缺口识别
- 3.3 ac参数分析
- 3.3.1 定位ac参数的位置
- 3.3.2 js解混淆
- 3.3.3 关键步骤简释
- 四、参考资料
- 五、补充内容
- 5.1 AST解析动态js
一、引言
1.1 声明
声明:
本文章仅供学习交流使用,不提供完整代码,严禁用于商业用途和非法用途,否则由此产生的一切后果均与本人无关,请各位自觉遵守相关法律法规。
本文章未经许可禁止转载,禁止任何二次修改(加工)后的传播;若有侵权,联系删除。
交流、合作请留言,24小时内回复!
1.2 简介
曾经遇到到顶象的滑块验证,一时没能解决,时间和学习资源不充足的情况下,便搁置了。后来在解决掉极验、数美等滑块验证码之后,想起了 曾经被劝退的顶象滑块,便想着抽空继续逆向一下试试。
测试用例地址:aHR0cHM6Ly93d3cuZGluZ3hpYW5nLWluYy5jb20vYnVzaW5lc3MvY2FwdGNoYQ==
本文最后放了一些逆向过程中搜寻到的文章链接,在逆向的过程中,这些文章或多或少的提供了一些帮助和思路,在此对作者做出感谢,有需者 可自行查看原文。
接下来放一张验证通过的截图,然后开始进入逆向。
1.3 待办
生成ac参数的js文件,每天更新,此处的解析还未完成自动化,目前只是手动还原了一版。
二、验证步骤
通过在浏览器中的操作,可以看出 验证码的生成、验证分为3个步骤。
获取data----> 利用data获取验证码图片信息 ----> 移动缺口图片到正确位置。
2.1 c1请求,获取data
博客园-顶象验证码破解与研究
请求头中携带param参数,此处应该是指纹信息。请求成功返回的数据中会包含"data",在第二步的a请求中使用。c1的返回的data值,不会每次都变化,在同一天多次请求会相同,可省略第一步的c1请求,直接在第二步的a请求中固定c参数(data)。
2.2 a请求,获取图片地址
与c1不同,a请求中头部都是常规内容,复制浏览器的即可。
a请求的载荷参数解释 和响应数据解释:
========================载荷参数解释========================
w: 380 // 请求的验证码宽度(固定)
h: 165 // 请求的验证码高度(固定)
s: 50 // (可固定)
ak: 99de95ad1f23597c23b3558d932ded3c // 验证码类型,此值对应滑块验证(固定)
c: 64cb3891q2g6HKWUKBagSF686FQjel8FqliLPgG1 // c1请求返回的data数据,可省略c1请求,固定此值
jsv: 6.0.0 // (按照版本,可固定)
aid: dx-1691630871643-14897481-3 // dx-时间戳-随机数-3/5 (可固定、v1请求的值同此处)
wp: 1 // 返回的图片格式(固定) 1:webp格式;0:jpg格式
de: 0 // (可固定)
uid:
lf: 0 // (可固定)
tpc:
t: C63E361F4AAB90D5FB969C27FB21F9CD07B6470BCC857D08D67E5ECE0493BC4E88DA0E5DAC80844A8C52748D905DB97461291982AE1D349B7E5945A31175E18333D5C0C4E6EA741A68DA7838D5FB62C1 // 未研究此值是生成(可固定)
cid: 49671984 // (可固定)
_r: 0.40174027448017546 // 随机数
========================响应数据解释========================
"sid": "9382a85ee87ce75e7ed6868645b4000f", // 第3步v1验证时使用;且作为token值 生成ac值使用
"cid": "49671984", // 第3步v1验证时使用"y": 52, // 第3步v1验证时使用;且在sendTemp时传参 计算ac值"p1": "/dx/ViTI2EMiXa/zib3/2e6c19f6d15449819c472b1863d7ce80.webp", // 背景图url地址(乱序,需还原)"p2": "/dx/ViTI2EMiXa/zib3/789f3b9a1df74d23ab42386f2645dfab.webp", // 缺口小图url地址"p3": null,
... //其他省略
此时获取到的背景图片是乱序的,需要找到还原数组,按照顺序进行图片还原。
2.3 v1请求,滑块验证
将指纹信息、缺口识别信息、鼠标轨迹信息 结合生成ac参数,请求v1,验证相关过程和结果是否正确,验证成功则会返回token值。ac参数的分析是整个逆向过程中的最重要部分。
三、过程解析
3.1 图片还原
根据经验 图片还原的方式之一,浏览器在画布(canvas)中进行重新绘图。因此可以进入控制台,点击顶部的"源代码",点击右侧的"事件监听器断点",勾选"画布",若采用canvas还原的方式 则此时在渲染验证码图片时 会被断住。(引申:极验在天眼查登录验证时,使用的就不是canvas还原乱序图的方式)
通过以下截图可知,顶象滑块还原乱序图的方式就是根据一个还原数组,使用canvas重新绘图。
上图中的B值就是还原数组,多运行几次,可知每张图片的还原数组值都不一样,因此还需要跟栈,向上分析,找到还原数组的生成位置。
B = n[‘ranges’],因此需要找到n的传入/生成位置。
进入L函数,如下图,可以看到 “ranges”:r,猜测 自执行函数r就是生成还原数组的位置。打断点,分析下图可知:r函数内部 通过en函数 对e(背景图url地址)进行处理 得到r的返回值是一个32位的数组。
此时已拿到一个32位的数组值,按F8,继续执行到下一个断点处 B = n[g(“72,61,6e,67,65,73”)] 。
对比可知 两个数组值是一样的,此时便可确定乱序背景图的还原数组是由背景图的url地址经过en函数得到的。
在浏览器中扣出的相应js代码有30行左右,由于js中含有无用的僵尸代码,且逻辑并不复杂,本人利用python还原此算法,加上def function()、return、注释 等语句 其实只需10行即可实现。
此处不是难点,因此不贴出 计算还原数组的代码。
得到还原数组之后,即可对乱序图进行还原,还原乱序图可以使用python中的PIL库。
from PIL import Image# 读取乱序图
# url = 'https://static.dingxiang-inc.com/picture/dx/ViTI2EMiXa/zib3/2e6c19f6d15449819c472b1863d7ce80.webp'
_img = Image.open("还原之前的乱序图片.webp")
# 乱序图还原数组(图片与数组一一对应,此数组 对应上方的url背景图)
arr = [18, 5, 22, 3, 17, 25, 6, 23, 4, 19, 21, 20, 24, 26, 27, 28, 29, 7, 30, 31, 0, 2, 1, 8, 9, 10, 11, 12, 13, 14, 15, 16]# 创建一个新的背景图
new_img = Image.new('RGB', (400, 200)) # 宽400 高200for index in range(len(arr)):c = arr[index] * 12# 从背景图中扣出相应的小图l = _img.crop((c, 0, c + 12,200)) # 图片剪切crop(x,y,x1,y1) 四个坐标# 将扣出的小图 还原到正确的位置new_x = index * 12new_img.paste(l, (new_x, 0))
new_img.paste(_img.crop((384, 0, 400,200)),(384,0)) # 最后的边框 32*12=384
new_img.save("还原之后的图片.jpg")
3.2 缺口识别
还原背景图之后,python中利用cv2库,即可精确识别出缺口位置,在做ac参数加密时,需要用到缺口距离值,注意图片缩放。 下载下来的图片尺寸为400×200,网页中的验证码尺寸为380×165。
3.3 ac参数分析
3.3.1 定位ac参数的位置
查看v1请求的启动器,可以从上到下点击,进入js页面,查看是否含有ac参数;也可通过Xhr断点等方式。
观察可知:ac = pn.getUA() ,pn=n.ua 。pn的位置 相继打上断点。
pn=n.ua 赋值之后,pn.getUA() 即有相应的值。
执行 pn.sendSA() 和 pn.sendTemp() 之后 pn.getUA() 获取到的值的长度都有所增加。
进入到 pn.getUA() 的定义位置查看。调用 getUA()时,返回的是 this.ua 。且生成ac的js代码是混淆的。
3.3.2 js解混淆
使用AST技术对js进行解混淆之后,可以看到有一大堆函数,这时再分析起来就比较方便。
网上有大佬开源的AST代码,此处不多说
3.3.3 关键步骤简释
首先 new一个对象,需要传入的是图片对应的token,在第二步的a请求中已经返回了这个值。
通过分析源码可知,在创建对象的时候,会执行 reload、init、recordSA等方法。
后面的分析 只需要按照这个思路和顺序进行下去即可理解ua的生成过程。
function oo(r)(this["reload"](true);this["init"](r);this["recordSA"] = this["eventThrottle"](this["recordSA"], {"counter": "sa","max": "maxSALog"});
)
start方法内会执行一系列的环境检测,这部分补相应的环境即可。
oo["prototype"]["start"] = function () {this["getTM"](); // 时间戳this["getBR"](); // 浏览器版本this["getLO"](); // locationthis["getCF"](); // 从函数列表中随机选择一个参与计算this["getDI"](); // 是否开启控制台(8开启;1未开启)this["getEM"](); // 检测自动化软件 webdriver等this["getJSV"](); // jsv版本this["getTK"](); // token this["getSC"](); // 屏幕信息Pr["default"](function () {this["bindDomEvents"]();} // 绑定事件监听(鼠标移动、点击等等)}
ua的更新是在app方法内实现的,几乎所有的方法都会调用app。
oo["prototype"]["app"] = function (u, f) {var m = (0, Vr["toStr"])([u]["concat"]((0, Dr["bs2"])(f["length"])));this["_ua"] += [m, f]["join"]("");this["ua"] = [Wr["default"]["version"], "#", (0, Ir["btoa"])(this["_ua"])]["join"]("");this["option"]["form"] && this["syncToForm"](this["ua"]);
}
oo["prototype"]["process"] = function (r) {var a = []["slice"]["call"](arguments);return r = a["length"] === 1 && (0, Vr["isArray"])(r) ? r : a, r = (0, Vr["flatten"])(r), (0, Vr["toStr"])(r);
}
sendSA 是对移动轨迹进行处理,然后更新ua的值。
recordSA对轨迹进行记录,将轨迹值push到this._sa中;调用sendSA时,是从this._sa取值进行处理。
sendTemp 对缺口位置、滑块dom信息进行处理,再次更新ua的值,就是最终的ac参数,即getUA()的返回值。
调试过程中,若对ac的生成不够清楚,可以在浏览器中插入日志点 辅助理解、分析!!!
四、参考资料
以下参考到的文章 按照发表/编辑时间倒序排列,且对文章进行了说明,可根据需要查阅原文。
知乎-顶象滑块ac参数逆向思路 2023-05 评论区解释了轨迹问题
CSDN-dx滑块逆向及ac参数逆向 2023-05 解释了ua的生成步骤、标注了每次请求的载荷参数含义
稀土掘金-顶象滑块逆向分析 2022-07 只有背景图的还原算法分析
CSDN-网络爬虫-破解顶象滑块验证码 2022-01 说明了顶象滑块的难点、ac生成的三个步骤
CSDN-DX验证码分析 2022-01 全局的思路说明
腾讯云-D象滑动验证码加密分析 2021-12 无图只文字、含有向sa中push轨迹数据的说明
博客园-顶象验证码破解与研究 2019-05 对环境检测函数进行了功能标注
五、补充内容
5.1 AST解析动态js
[1.3 中的代办] 关于js每天更新的问题,已经解决。
每次运行滑块代码之前,会检测网站最新的js与本地的js是否一致。
若一致,则直接可以进行滑块验证。
若不一致,则会保存一份最新的js,通过AST对其解析,并且会将解析之后的js备份一下,然后进行滑块验证。
至此,顶象滑块的js逆向已全部完成。
这篇关于顶象滑块的js逆向分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!