!
声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!
前言
近期查看星球群聊,发现有群友讨论关于某验蝌蚪文的问题,根据以往经验来看,绝对不仅仅是单纯的 js 混淆,而逻辑不变。最近也有很多粉丝提问,表示验证通过返回值却用不了,极大可能是这次更新增加了一个动态参数的缘故,虽然可以通过,但是却被标记,导致无法通过校验:
此外,也有粉丝在群里发布某交易所相关验证码的需求,正好,本文就对这个站点进行分析,同时也是对某验系列的一个补充:
逆向目标
- 目标:gate 登录页
- 网址:
aHR0cHM6Ly93d3cuZ2F0ZS5pby96aC9sb2dpbg==
抓包分析
进入登录页面,随机输入账号、密码,点击登录,会发现抓到了两次 /load
数据包,其中第一次 load 包返回的验证码类型为无感 ai
:
第二次 load 包返回验证码类型为滑块 slide
:
无感验证通过后返回 continue
,同时返回 lot_number、payload、process_token 等参数:
这些参数同时又是第二次 load 包中的请求参数,验证通过后,即会返回最终所需的参数。
逆向分析
往期文章也详细讲过 4 代的相关算法流程,没有了解过 4 代的小伙伴可以先去看一下:
某验四代滑块验证码逆向分析:https://mp.weixin.qq.com/s/vlPH-6YpGo7jBGhg1fzMng
在以往,定位 w 的方式为搜索 "\u0077"
,最新版本中,可以通过 w:
来定位,位置如下:
发现 w 由 _ᖚᕿᕹᖙ
赋值,参数如下:
{
"device_id": "",
"lot_number": "省略",
"pow_msg": "",
"pow_sign": "省略",
"geetest": "captcha",
"lang": "zh",
"ep": "123",
"biht": "1426265548",
"gee_guard": {
"roe": {
"aup": "3",
"sep": "3",
"egp": "3",
"auh": "3",
"rew": "3",
"snh": "3",
"res": "3",
"cdc": "3"
}
},
"2WvY": "SQjH",
"fa18b6": "1414",
"em": {
"ph": 0,
"cp": 0,
"ek": "11",
"wd": 1,
"nt": 0,
"si": 0,
"sc": 0
}
}
可以看到,多了一个键值对参数,"fa18b6": "1414"
。那么我们分析一下这个参数是如何生成的。在 w 之前我们发现该键值对参数为 a:
a 参数是由 i 参数与 r 参数生成的,其逻辑如下:
var i = (0,_ᖘᕹᖆᖗ[_ᕴᖉᕾᕾ(37)])(_ᕴᖙᖀᖆ["lot"], _ᕴᖙᖀᖆ[_ᕴᖉᕾᕾ(414)])
, r = (0,_ᖘᕹᖆᖗ[_ᕸᖗᖁᖆ(37)])(_ᕴᖙᖀᖆ["lotRes"], _ᕴᖙᖀᖆ[_ᕴᖉᕾᕾ(414)])
_ᕴᖙᖀᖆ[_ᕴᖉᕾᕾ(414)]
参数为 load 接口返回的 lotNumber,那么 lot 与 lotRes 是如何得来的?我们向前跟栈,找到相关标志位置如下:
关键代码如下:
var _ᖙᕺᖀᕷ = this
, _ᖆᕹᖈᕾ = window[_ᕴᖉᕾᕾ(22)] ? window[_ᕸᖗᖁᖆ(22)][_ᕴᖉᕾᕾ(1)] : {
};
for (var i in _ᖆᕹᖈᕾ)
if (_ᖆᕹᖈᕾ[_ᕴᖉᕾᕾ(60)](i)) {
var r = _ᖆᕹᖈᕾ[i];
_ᖙᕺᖀᕷ["options"]["lot"] = (0, _ᖘᕹᖆᖗ[_ᕸᖗᖁᖆ(64)])(i),
_ᖙᕺᖀᕷ["options"]["lotRes"] = (0,_ᖘᕹᖆᖗ[_ᕸᖗᖁᖆ(64)])(r)
}
在这里有明显的赋值 var _ᖙᕺᖀᕷ = this
,this 指向的是 window,这里将 window 赋值给了 _ᖙᕺᖀᕷ
,然后取了 window 下面的一个属性值 _ᖆᕹᖈᕾ = window[ "lib" ] ? window["lib"]["_abo"]
,值如下:
{
"n[7:9]+n[22:24]": "n[9:12]"
}
之后进行 for 循环中遍历,经过函数 _ᖘᕹᖆᖗ[_ᕸᖗᖁᖆ(64)]
得到 lot 与 lotRes,那么这个函数我们可以选择扣算法,也可以导函数,当然也可以算法模拟,这里就选择直接扣算法,进入该方法,结构如下:
将该方法整体拿下,依旧还是将头部函数也一起全部拿下,如下:
运行后发现提示报错,ReferenceError: _ᖙᕺᖀᕷ is not defined
:
将代码全部拿到 nodepad,观察代码结构,发现仍是熟悉的往原型上添加方法,_ᕸᖗᖁᖆ(29)
无疑是 prototype:
把该方法同样打包拿下,最终复现如下:
除了扣算法以外,函数导出也是不错的选择,将整体代码全部拿下,直接在该函数部分将该函数导出给全局:
然后将老生常谈的 window、document 进行补齐即可复现,效果同上。
将 lot 与 lotRes 进行处理后,就剩下最后一个函数 _ᖘᕹᖆᖗ[_ᕴᖉᕾᕾ(37)]
需要处理,处理方法依旧如上,发现依旧这个方法是属于 _ᖁᕴᕿᖄ
下的方法:
也是将其扣下,最终复现如下:
// 头部解密函数省略
function _ᖙᕺᖀᕷ(_ᖚᕿᕹᖙ) {
var _ᖁᕴᕿᖄ = _ᖗᖉᖙᕹ.$_DR()[0][6];
for (; _ᖁᕴᕿᖄ !== _ᖗᖉᖙᕹ.$_DR()[2][5]; ) {
switch (_ᖁᕴᕿᖄ) {
case _ᖗᖉᖙᕹ.$_DR()[4][6]:
this[_ᕸᖗᖁᖆ(34