声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!
前言
在人工智能技术飞速迭代的今天,AI 大模型已突破传统技术边界,从基础的模式识别、数据解析,升级为具备自主学习、逻辑推理、复杂问题拆解能力的核心赋能工具,其强大的算力与智能分析能力,正重构各行业的技术路径,逆向工程领域也不例外。
曾经,协议逆向、接口解析、产品反编译等工作,往往依赖工程师长期的经验积累、繁琐的手工调试,不仅耗时耗力,更易在复杂代码、加密协议中陷入瓶颈,难以实现高效突破。
而如今,AI 大模型的介入,彻底改变了逆向工程的实战逻辑 —— 它能快速挖掘代码中的隐藏规律、自动解析未知协议的交互逻辑,借助 AI 工具的辅助,可大幅降低逆向门槛、提升分析效率,甚至能完成传统人工难以企及的复杂逆向任务。
在技术竞争日趋激烈、产品迭代不断加速的当下,逆向工程的核心诉求已从“能完成”转向“高效、精准、快速”,而拥抱 AI、善用 AI 大模型,不再是可选的加分项,而是立足行业、实现技术突破的必由之路。
(怪不得加入 OpenAI,属实给 “龙虾之父” 用爽了)
逆向目标
- 目标:某象刮刮卡验证码
- 网址:
aHR0cHM6Ly93d3cuZGluZ3hpYW5nLWluYy5jb20vYnVzaW5lc3MvY2FwdGNoYQ== - AI 模型:
GPT-5.5
抓包分析
进入网站,就是旗下产品样例在线体验页面,其中有个较为新颖的验证码类型 —— 刮刮卡,一开始会展示图案位置,需要刮出完整图案才能验证通过:
/api/a 接口响应返回 sid 参数值及验证码背景图片链接,type 2 即刮刮卡验证:
不过此时的背景图片是乱序的,需要还原,后文分析:
c1 接口请求了两次,一次 GET,一次 POST,第二次响应返回的 data 值就是最终验证接口的请求参数 c,两次请求都有个加密参数 Param,一长一短,后文分析:
/api/v3 为校验接口,ak 为验证码标识,c、sid 均由上文接口返回,aid 和主要加密参数 ac 后文分析:
- 验证通过:{“success”:true,“token”:“xxxxx”,“msg”:null,“tp”:null,“sv”:null,“retry”:0,“ot”:null}
- 识别错误:{“success”:false,“token”:null,“msg”:“retry”,“tp”:null,“sv”:null,“retry”:0,“ot”:null}
- 算法异常:{“success”:false,“token”:null,“msg”:“验证过程出现异常”,“tp”:null,“sv”:null,“retry”:0,“ot”:null}
AI & 古法逆向分析
乱序图片还原
接口返回的图片链接,下载下来是乱序的,想要识别目标图案位置,肯定是需要还原出完整图片的。网站也一样,后端返回乱序图片,前端根据正确的还原顺序,绘制出完整图片,然后渲染到页面上。
因此,我们需要找到还原顺序,从而复现出还原算法。验证码图片大概率是通过 canvas 绘制的,可以下个画布断点尝试下,重新获取验证码,成功断下了:
代码有点混淆,解完之后内容如下:
function d(n, t, r, e) {
var o, i = n.options.lineWidth || p.default_line_width, d = p["cover_color"], v = t["getElementsByTagName"]("canvas")[0]["getContext"]("2d");
return v["fillStyle"] = d,
v.fillRect(0, 0, r, e),
v.globalCompositeOperation = "destination-out",
v["lineWidth"] = i,
v.lineCap = "round",
v
}
将这部分丢给 AI 分析下,AI 直接看出了这是在绘制刮刮卡:
destination-out 的作用是:后续绘制的地方会把已有像素“擦掉”,不是画上颜色。所以这常见于验证码滑块、刮刮卡、手势擦除、canvas 遮罩揭露这类场景。
根据 AI 的分析,可以判断,这块是在绘制遮罩层,并非乱序还原部分。因此,F8,跳到下一个断点位置看看,如下图所示:
同样,解下混淆,可以让 AI 实现:
function _(n, t, i, e, r) {
var o = n.getContext("2d");
o["drawImage"](t, 0, 0, i, e);
var a = Math.floor(i / r['length']);
x(r, (function (n, i) {
var r = n * a
, c = a;
o.drawImage(t, r, 0, c, e, i * a, 0, c, e)
}
))
}
还是直接让 AI 分析一下:
综上可知,这部分就是我们要找的 “乱序切块还原” 部分,但是测试发现,还原顺序并不是定值,那是如何生成的呢?照以往,得开始往上跟栈分析了,但是大人,时代变了,现在直接交给 AI,然后去泡杯茶,看看新闻,欣赏 AI 的表演(描述需求,发网站链接,算法所在文件,AI 会自动调用 mcp 加载页面进行分析):
AI 不仅正确找到了相关算法的生成位置,还将还原逻辑用 python 复现了,表现的十分优秀,主要逻辑如下,相关算法会分享到知识星球中:
# uses the image URL filename stem, e.g. "5d6bbb8c70d449b7940f9b5d878b760a".
def generate_ranges(seed: str) -> list[int]:
order: list[int] = []
for index, char in enumerate(seed):
if index == 32:
break
value = ord(char)
while value % 32 in order:
value += 1
order.append(value % 32)
if len(order) != 32:
raise ValueError(f"seed must generate 32 ranges, got {len(order)}")
return order
aid
/api/a 接口的加密参数,这个直接手动扣就行了,从该接口的堆栈处,跟到 oneclick-Captcha-js.js 文件中,直接搜索 aid = 定位,下断,刮刮卡的 R 为 3,跟到函数 I 中,将算法扣下来用 python 还原即可:
timestamp = int(time.time() * 1000)
random_part = random.randint(0, 99999999)
aid = f"dx-{timestamp}-{random_part}-3"
_t
str(int(time.time() * 1000))[-6:-1]
Param
先从第一个 c1 的堆栈处,跟到 index.js 中(动态的,建议固定一套调试),下断,清空缓存,刷新网页,断住后往上跟栈到下图处,此时 Param 参数的值已经生成:
再往上跟一个栈就能找到生成位置,第二个 c1 的 Param 也一样:
按照以往的思路,定位到算法生成的位置,就该开始漫长且枯燥的扣代码了,感谢新时代,接下来交给 AI 就行了(其实上述过程都不需要,跟 AI 描述你需要哪个接口中哪个参数的生成算法,他就能直接分析出来),定位到了正确的位置:
最后,直接让 AI 用 python 复现算法(爽),根据 AI 分析及验证,两个 Param 的生成算法是一样的,入参不同所以长度有差别:
第二个 Param 的入参包含大量的环境校验,以下为 AI 分析结果:
field_sources = {
"can": "canvasFP,Canvas 指纹",
"cpt": "canPlayType,音视频格式支持",
"web": "webglFP,WebGL 指纹 hash",
"gi": "webgl,WebGL 原始信息",
"pr": "devicePixelRatio",
"dm": "navigator.deviceMemory",
"jf": "fonts,字体探测",
"hc": "navigator.hardwareConcurrency",
"ua": "navigator.userAgent",
"uad": "navigator.userAgentData",
"np": "navigator.platform",
"lug": "navigator.language",
"ce": "navigator.cookieEnabled",
"netType": "navigator.connection.effectiveType",
"ts": "touch,触摸能力",
"tz": "Intl.DateTimeFormat().resolvedOptions().timeZone",
"to": "new Date().getTimezoneOffset()",
"ls": "localStorage 支持",
"ss": "sessionStorage 支持",
"ind": "indexedDB 支持",
"od": "openDatabase 支持",
"cd": "screen.colorDepth",
"res": "screen.width/height",
"ar": "screen.availWidth/availHeight",
"vs": "viewportSize",
"ws": "windowSize",
"rp": "navigator.plugins",
"adb": "adblock 检测",
"hl": "history.length",
"cl": "cookieLength",
"st": "startTime",
"dt": "document.title",
"url": "location.href",
"bl": "bodyLength",
"hdl": "headLength",
"dr": "document.referrer",
"xp": "xpath",
"hsl": "performance.memory.jsHeapSizeLimit",
"in": "incognito 检测",
"qu": "storage quota",
"hev": "UA high entropy values",
"bt": "beginTime",
"ct": "collectTime",
"hlb": "hasLiedBrowser",
"hll": "hasLiedLanguages",
"hlo": "hasLiedOs",
"hlr": "hasLiedResolution",
"db": "debugger 检测",
"sm": "simulator 检测",
}
固定入参,将 AI 算法生成的值与网页生成的对比验证一下,结果一致(稳!):
版本号、自定义 base64 字符表匹配(动态 js)及相关算法,都会分享到知识星球中,以供学习交流。
ac
最后,来分析下某象最关键的加密参数 —— ac。
还是先从堆栈处下断,往上跟一下,定位到了下图位置:
M.getUA() 跟进去,就会跳转到 greenseer.js 文件中,知道大致的范围了,接下来,描述给 AI,看他发挥就行了(学习 AI 的思路),有问题调教一下,有些点还是会分析的不对,需要纠正:
AI 还能将各关键算法的位置全部清晰的罗列出来,便于自行分析:
顺便让 AI 解混淆(控制流平坦化还原、Webpack 模块拆分、静态调用解码等等),还原 greenseer.js 文件,代码同步到知识星球:
刮刮乐需要先检测出目标物品的位置,生成对应的轨迹,才能计算出正确的 ac 值,先让 AI 写出识别算法,找到目标物体的位置(已分享到知识星球):
研究轨迹,可以插桩分析:
(() => {
if (!window.__scratchStartTime || n.type === "mousedown" || n.type === "touchstart") {
window.__scratchStartTime = Date.now();
window.__scratchData = [];
}
const item = {
x: Y(n),
y: H(n),
t: Date.now() - window.__scratchStartTime
};
window.__scratchData.push(item);
return JSON.stringify(window.__scratchData);
})()
// copy(JSON.stringify(window.__scratchData))
结果验证
共同学习,写下你的评论
评论加载中...
作者其他优质文章

























