人工智能技术的迭代速度令人目不暇接。从最初的基础模式识别,到如今具备自主学习与逻辑推理能力,AI大模型深刻影响着各行各业。逆向工程领域同样被重塑。以往依靠长期经验积累的协议逆向、接口解析等工作,耗时费力,且常因复杂加密协议而陷入困境。如今,AI大模型彻底改变了这一现状:它能够快速发现代码中的隐含规律,自动解析未知协议的交互逻辑,甚至完成以往难以想象的复杂逆向任务。在技术竞争日益激烈的时代,逆向工程的核心目标已从“能完成”转向“高效、精准、快速”。因此,拥抱并善用AI大模型不再是可选项,而是必由之路。
NhgLNO.png
前言
让我们先明确本次案例的具体目标:攻克某象的刮刮卡验证码(网址已提供),使用的AI模型为GPT-5.5。进入网站后,在线体验页面展示了一种新颖的验证码类型——刮刮卡。初始时会显示图案位置,用户需要刮出完整图案才能通过验证。这正是逆向分析的核心所在。
NgBeCt.png
抓包分析是第一步。接口响应返回了sid参数和验证码背景图片链接,其中type为2代表刮刮卡验证。但请注意,此时的背景图片是乱序的,需要后续还原。
NgTBRP.png
c1接口被请求了两次,一次GET,一次POST。第二次响应的data值即为最终验证接口的请求参数c。两个请求均包含加密参数Param,一长一短,后续将详细分析。
NgEGbG.png
校验接口为/api/v3,其中ak为验证码标识,c和sid由上一步接口返回,aid和主要加密参数ac留到后续处理。
NgTLDO.png
AI & 古法逆向分析
乱序图片还原
接口返回的图片链接下载后是乱序的,要识别目标图案,必须先还原出完整图片。网站本身的处理逻辑也是如此:后端返回乱序图片,前端依据正确的还原顺序绘制完整图片,再渲染到页面上。因此,找到这个还原顺序就能复现还原算法。
验证码图片大概率是通过canvas绘制的。下个画布断点试试,重新获取验证码后成功断下。
NgTAgs.png
代码经过混淆,解压后如下:
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分析,结果直接指出这是在绘制刮刮卡遮罩层,并非乱序还原部分。因此,继续跳到下一个断点位置看看。
NgmQEL.png
同样解混淆后,代码如下:
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,去泡杯茶、看看新闻,等着就行。
Ng7aoZ.png
AI不仅找到了生成算法,还用Python复现了逻辑。核心代码如下:
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实现。
NgEL0h.png
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参数的值已经生成。
NgN3yZ.png
再往上跟一个栈,就能找到生成位置。第二个c1的Param同理。
NgNlUU.png
传统做法是开始漫长枯燥的扣代码,感谢新时代,这一步直接交给AI。定位到正确位置后,让AI用Python复现算法。两个Param的算法相同,只是入参不同导致长度差异。
NgNOHf.png
第二个Param的入参包含大量环境校验,AI分析结果如下:
field_sources = {
"can": "canvasFP,Canvas 指纹",
"cpt": "canPlayType,音视频格式支持",
"web": "webglFP,WebGL 指纹 hash",
"gi": "webgl,WebGL 原始信息",
"pr": "devicePixelRatio",
"dm": "na vigator.deviceMemory",
"jf": "fonts,字体探测",
"hc": "na vigator.hardwareConcurrency",
"ua": "na vigator.userAgent",
"uad": "na vigator.userAgentData",
"np": "na vigator.platform",
"lug": "na vigator.language",
"ce": "na vigator.cookieEnabled",
"netType": "na vigator.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.a vailWidth/a vailHeight",
"vs": "viewportSize",
"ws": "windowSize",
"rp": "na vigator.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生成的值与网页生成的值进行对比验证,结果一致。
NgNS1c.png
ac
最后,分析最关键的加密参数ac。从堆栈处下断,往上跟,定位到了下图位置。
NgKTps.png
M.getUA()跟进去,跳转到greenseer.js文件。知道范围后,交给AI,看它发挥。有问题就调教,有些点确实需要纠正。
NgKD94.png
NgKSP9.png
AI还能将各关键算法的位置全部罗列出来,方便自行分析。
NgKt0q.png
顺便让AI解混淆,还原了greenseer.js文件。刮刮乐需要先检测出目标物品的位置,生成对应的轨迹,才能计算出正确的ac值。让AI写出识别算法,找到目标物体的位置。
NghYIf.png
研究轨迹可以插桩分析:
(() => {
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))
结果验证
Nghz53.png
