

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!
最近收到私信,询问关于某程滑块的解法,难度不大。经过分析,完全可以通过 AI 来完成逆向,本文将对该站进行相关分析。

抓包可知触发验证码是由 captcha/v4/risk_inspect 接口触发的,如下:

参与请求的值有 dimensions、extend_param、sign。验证后接口返回 token、rid 以及图片信息。验证接口相比图片接口多了一个verify_msg 参数:

通过校验后 token 被激活:

从 risk_inspect 包入口进入,定位到如下地方:

发现了载荷中要找的几个值,生成逻辑如下:
r = _0x342058(_0x311148[_("0x72")](n), 0),
a = {
resolution_width: M[_("0xa5")],
resolution_height: M.scrH,
language: P
},
c = _0x342058(_0x311148.stringify(a), 0),
o = _0x110baa[_("0x97")]("appid=" + s + _("0x10e") + f + "&version=" + D[_("0x4d")] + _("0x74") + r + _("0x3a") + c),
G(H[_("0x75")] + H[_("0x6c")], {
extend_param: encodeURIComponent(c),
appid: s,
business_site: f,
version: D[_("0x4d")],
dimensions: encodeURIComponent(r),
sign: o[_("0xad")]()第一个参数 extend_param 是通过 c = _0x342058(_0x311148.stringify(a), 0) 生成的,a 为常见的信息:
{
"resolution_width": 1512,
"resolution_height": 982,
"language": ""
}同时 dimensions 生成方式相同,也是通过 r = _0x342058(_0x311148[_("0x72")](n), 0) 生成。
n 大部分为指纹信息,这里做脱敏处理:
{
"rt": "fp=44779A-738C77-EF371C&vid=1779266823753.8bb8R2qxntXk&pageId=10320670296&r=06fed28fb6c0464c9201df7d452ba538&ip=223.104.124.240&rg
"ua":
**********************脱敏处理***********************************
"p": "pc",
"fp": "44779A-738C77-EF371C",
"vid": "1779266823753.8bb8R2qxntXk",
"identify": "a44779A-738C77-EF371C",
"guid": "09031151214445559123",
"h5_duid": null,
"pc_duid": null,
"hb_uid": null,
"pc_uid": null,
"h5_uid": null,
"infosec_openid": null,
**********************脱敏处理***********************************
"client_type": "PC",
"site": {
"type": "PC",
"url": "",
"ref": "https://www.ctrip.com/",
"title": "登录首页",
"keywords": ""
},
"device": {
"width": 1512,
"height": 982,
"os": "",
"pixelRatio": 2,
"did": ""
},
"user": {
"tid": "",
"uid": "",
"vid": ""
}
}sign 则是通过 o = _0x110baa[_("0x97")]("appid=" + s + _("0x10e") + f + "&version=" + D[_("0x4d")] + _("0x74") + r + _("0x3a") + c) 生成的,经过分析 _0x110baa[_("0x97")] 为 md5 算法。
所以现在就剩 _0x342058 需要分析,单步跟进可以发现是 new 了一个方法,然后经过 n 函数最终生成的:
n = new _0x254c65(128,1e3);
return 0 === e ? n[t("0xcd")](i, x) : n[t("0x108")](i, x)进入 n 函数中,发现是通过 encrypt 生成的,该 aes 也未经过魔改,标准算法:
return e[x("0x86")][x("0xcd")] = function(e, t) {
var i = x;
return _0x110baa[i("0x94")].encrypt(t, this.key, {
iv: _0x110baa[i("0xae")][i("0x2d")][i("0x2c")](e)
})[i("0x123")][i("0xad")](_0x110baa[i("0xae")][i("0xf")])
}
,最后一个校验函数与上述流程类似,多了一个 verify_msg 参数,定位到下图处,同样还是由 n 函数生成:

_0x13f650 包含了轨迹以及少部分浏览器信息,这些搞定后即可将整个验证码过掉。
实际上,手动登陆如果每次清空缓存是不会弹出验证码的,频繁点击后必出验证码。经过研究发现,dimensions 中的 fp 与 rt(即 rmstoken) 指纹参数很重要,决定了是否会触发验证码。
定位 rt 相对简单,rt 和 fp 参数都是从 M 中取值的,向上定位 M:
rt: M[_("0x71")],
ua: M.userAgent,
p: i,
fp: M.FP,最终找到下图位置:

跟进后发现最终生成逻辑是挂到 getRmsToken 上的:

同时还挂载到 window 里面,直接调用 rmstoken = window.RMS.getRmsToken() 即可:

rms 的定位也大同小异,trigger 中发现其被当参数传进去的,继续向上跟:

最终定位到下图处,由 cfp 函数生成:

至此,我们把环境补齐,直接调用这几个函数即可生成相关参数:

对于 AI 逆向的话,能不能搞出来取决于提示词,不管是 mcp 还是静态分析都是不错的方法,同样还是丢万能提示词:

再然后就可以解放双手了,等个几分钟看一下结果:

经过验证,与古法分析的结果完全一致。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。