逆向实录 | 6小时干碎 808GPS 屎山防线:一次“人机协同”的极限排雷
熟悉我的人都知道,我是一个彻头彻尾的“数字斯多葛主义者”。在客运企业搞数字化转型,我极度厌恶那些臃肿的客户端和必须鼠标点来点去的繁琐 UI。能用终端和脚本跑全自动解决的事情,我绝不妥协。
最近,我盯上了公司里一套基于 CMSv6 架构的老旧 808GPS 车联网平台。每天要查车辆上下线报表,还要忍受极慢的页面响应。我决定写个脚本,直接在浏览器控制台一键把底层数据全量拉出来,并自动完成逆地理编码导出 CSV。
我唤醒了我的 AI 助手(Gemini)。原本以为这只是一次轻松的 API 搬运,没想到,一场长达 6 小时、与前人“屎山代码”斗智斗勇的极限拉锯战就此打响。
💥 第一关:幽灵拦截器与 111008 号报错
逆向的第一步是分析原生请求。通过抓包,我看到了目标接口和加密后的动态令牌: POST /report/StandardReportLoginAction_detail.action?Rx9erBzM7wI3wb/CiUg5KA==
AI 很快给出了第一版代码,标准得像教科书,用 $.ajax 把我构造好的 Payload 发了出去。 一秒钟后,控制台无情地砸回一个红色的报错: {"key":"param_must_encry","message":"参数必须加密传输","result":111008}
我眉头一皱。我传进去的 Body 明明已经是 Base64 加密后的密文了,凭什么说我没加密? 我切到 Network 面板去查发出去的真实报文,瞬间惊出一身冷汗: 我写死在代码里的 URL ?Rx9erBzM...,在发出去的瞬间,居然变成了 ?3r4qtdoLx1lAMb/4LEVSEizotSUXyPl9RgEBqDiitMI=!
破局推理: 系统的底裤里藏着“内鬼”!前端被埋了一颗 jQuery.ajaxPrefilter 全局拦截器的雷。只要走 $.ajax,拦截器就会自作主张把 URL 里的参数再加密一次。它把我的密文当成了明文,搞出了致命的“二次加密套娃”。
不仅如此,比对原生 cURL 后我发现,AI 漏掉了一个极其隐蔽的 Header:Newv: 1。这显然是后端的一个“暗号”,没有这个暗号,后端直接拒绝解密。
降维打击: 惹不起我还躲不起吗?我果断让 AI 弃用 jQuery,换用原生 fetch。fetch 就像一把隐形匕首,直接绕过全局拦截器。同时补齐暗号,成功拿到服务器回包!
💥 第二关:@ttxs2@ 阴间协议与信封脱壳
拿到回包后,真正的折磨才刚开始。 调用系统暴露在全局的解密函数 window.getdecryptRes() 时,脚本直接死机抛异常。
我打印出服务器的原始响应,竟然长这样: {"result":0,"encry":1,"data":"7HjsiqkE2Bnz5/bODtm6FIngv2n2kH..."}
为了弄清为什么报错,我扎进被 Webpack 混淆得亲妈都不认识的 public.js 屎山中,硬生生抠出了它的解密源码: ƒ (t){return t&&(t.encry&&1==t.encry?(t=i(t.data))&&JSON.parse(t):t)}
这行代码让我直呼好家伙!这是一种“信封包裹(Envelope)”结构,真正的 AES 密文只藏在 data 里。原厂代码极其狂野,一旦网络抖动或返回异常,没有任何 try-catch 的 JSON.parse(t) 会直接让整个页面原地爆炸。
与此同时,我手动解密了原始的请求 Payload,看到了让我倒吸一口凉气的阴间转义协议: "json":"@ttxs2@7B@ttxs2@22vehiIdnos@ttxs2@22@ttxs2@3A@ttxs2@22*@ttxs2@22@ttxs2@7D" 这帮外包开发者为了防注入,用 @ttxs2@7B 代替 {,@ttxs2@22 代替 "。
破局战术: 我立刻让 AI 1:1 像素级复刻了这套 @ttxs2@ 阴间协议,并重写了带防御性编程的信封脱壳逻辑。绝不信任原厂函数,精准剥离 data 字段后单独解密。
💥 第三关:手扒底裤,打造纯血 AES 引擎
逆向的最高境界,是把对方的发动机拆下来装在自己的车上。既然看透了业务逻辑,我为什么还要依赖它前端环境里的 window.enEncrycrypt?
我在源码中继续深挖,找到了开发者用来隐藏密钥的无聊把戏——自执行函数字符串拼接: c = "ttx" + (function(){for(var t="",n=1;n<7;n++)t+=n;return t}()) + "Aes" + ...
在控制台跑完这段代码,系统的终极机密——16 位硬编码密钥 ttx****Aes**** 直接躺在了我面前。
明确了 AES-128-ECB + Pkcs7 填充机制后,我指挥 AI 彻底踢开平台自带的业务函数,直接调用底层的 CryptoJS,手搓了加解密引擎:
JavaScript
const AES_KEY = window.CryptoJS.enc.Utf8.parse("ttx****Aes****");
// 纯血解密引擎:直击密文核心,免疫平台魔改
const myDecrypt = (ciphertext) => {
const decrypted = window.CryptoJS.AES.decrypt(ciphertext, AES_KEY, {
mode: window.CryptoJS.mode.ECB,
padding: window.CryptoJS.pad.Pkcs7
});
return window.CryptoJS.enc.Utf8.stringify(decrypted).toString();
};
这一步爽感极强。脚本获得了绝对的“环境免疫”,哪怕明天平台把加密函数改名,我的自动化工具依然坚不可摧。
💥 第四关:JSON 解析地狱,最后的暴力扫荡
加密大山推平了,并发地址解析的 API 也通了,但我打开导出的 CSV,地址栏全是刺眼的“解析失败”。
我在代码中加入拦截日志,抓出了后端返回的真实变异数据。这帮后端的接口极其不规范,时而返回对象,时而返回数组。最让人血压飙升的是,它竟然会返回被双重引号包裹的字符串化数组! "[ {\"address\": \"吉林省四平市梨树县...\"} ]"
标准的 data.address 在这种“大杂烩屎山”面前毫无还手之力。
暴力美学: 面对不讲武德的数据结构,我和 AI 敲定了一个野蛮但极度有效的战术:DFS(深度优先搜索)暴力递归提取。 无视任何奇葩层级,哪怕你包了十层数组、被恶心转义成了纯文本,只要字典里包含 address 这个 Key,老子强行把你挖出来!
JavaScript
const findAddrDeep = (obj) => {
if (!obj) return "";
// 降维打击:应对双重 String 化的恶心操作
if (typeof obj === "string") {
try {
const parsed = JSON.parse(obj);
if (typeof parsed === "object" && parsed !== null) return findAddrDeep(parsed);
} catch(e) {}
return "";
}
// 递归扫荡:只要带有 address,无视层级直接挖出
if (typeof obj === "object") {
if (obj.address) return obj.address;
if (obj.formatted_address) return obj.formatted_address;
for (let key in obj) {
let res = findAddrDeep(obj[key]);
if (res) return res;
}
}
return "";
};
当这台暴力引擎接入的那一刻,进度条瞬间跑满,完美的中文地址稳稳落入 CSV 表格。完美下车。
🧠 终极反思:人机协同(Human-AI Symbiosis)的真相
这 6 个小时的拉锯战,是对当下火热的“AI 辅助编程”最真实的一次祛魅。
很多人以为,扔一句“帮我破解这个系统”,AI 就能奇迹般地吐出代码。这是纯粹的扯淡。在真实的逆向工程中,AI 是火力无限的“重机枪”,能把手搓并发和 CryptoJS 配置的工作量压缩到几秒钟;但 AI 是个瞎子。
它看不到 DevTools 里那个被偷偷篡改的 URL,它猜不到外包公司会在全局挂一个 jQuery 拦截器,它更预料不到后台会返回双重字符串化的奇葩 JSON。
面对混淆代码、恶心拦截器和变异的脏数据,人类工程师敏锐的抓包嗅觉、对异常流的直觉判断,以及死磕到底的极客耐心,才是真正能撕开系统防线、扣动扳机的那根手指。
客观地说,在这片东北的黑土地上,在四平的 IT 圈子里,能用“顶级逆向直觉 + 高维 Prompt 架构能力”完成这种 P6+ 级别爬虫攻防、实现环境免疫的人,绝对是极少数派。
数字化转型从来都不是请客吃饭,不是 PPT 上的宏大叙事,而是一行行代码硬核凿出来的。这 6 小时,极度烧脑,但也极度痛快。
发表回复