逆向工程实战手册 第 13 章

第 13 章 前端 JS 逆向

JS 逆向 = 找到网页里的签名/加密参数怎么算出来的。目标不是"破解"而是复现:把浏览器里的算法搬回 Node,让你能自己生成合法参数。

📍 知识点地图 | 主题:前端JS逆向 | 前置:第9章 | 后续:第100章 | 核心概念:Observe-Capture-Rebuild、补环境、AST

13.1 核心原则(Observe-first)

Observe-first    先观察,不猜环境
Hook-preferred   优先 Hook,不盲目断点
Breakpoint-last  断点作为最后手段
Rebuild-oriented 一切为了本地复现
Evidence-first   证据先行,每个补丁有依据

13.2 五阶段工作流(本仓库方法论核心)

阶段 1: Observe(观察)

目标:确认目标请求、相关脚本、候选函数。

1. 打开目标页面
2. 看网络请求列表,找到目标请求(带签名的那个)
3. 看请求的 Initiator(调用来源)
4. 列出页面脚本,缩小范围
5. 产出: 目标 URL、initiator 线索、可疑脚本 URL

阶段 2: Capture(采样)

目标:最小侵入地拿到参数样例、调用顺序、运行时证据。

1. break_on_xhr 在 XHR 发送时断下
2. 看调用栈/暂停状态
3. 定位到生成签名的函数
4. 在函数入口/出口打印参数和返回值

阶段 3: Rebuild(重建)

目标:把页面证据整理成 Node 可跑的复现代码。

规则:
- 补环境必须基于页面观测证据
- 不允许空想式补 window/document/navigator/crypto/storage
- 每次只记录一个最小因果补丁决策

阶段 4: Patch(补环境)

目标:按报错和"第一个差异点"驱动补环境,直到本地稳定产出目标参数。

规则:
- 先看缺什么,再补什么
- 一次只做一个最小补丁
- 每次补丁后立即复测
- 每次补丁写入任务记录

阶段 5: DeepDive(深挖)

目标:本地跑通后做去混淆、控制流还原、业务逻辑提纯。

- 任务只出签名 → 此阶段可跳过
- 要长期复用算法 → 必须做 AST 去混淆 + 逻辑还原

13.3 常用工具面

能力 工具
网络请求观察 DevTools / anything-analyzer / jshookmcp
XHR 断点 DevTools / jshookmcp break_on_xhr
脚本源码 list_scripts / get_script_source / search_in_sources
运行时 Hook jshookmcp evaluate_script
补环境复现 Node + jsdom/自制环境
AST 去混淆 Babel / webcrack / jsnice
请求重放 Burp / mitmproxy / 自己写 fetch

13.4 定位签名函数的黄金链路

1. 找目标请求 → Initiator 里往上翻调用栈
2. 常见藏身处:
   - 拦截器层(axios/fetch 拦截器)
   - 统一封装 request.js
   - webpack chunk 里的工具函数
   - 独立加密 JS(加密参数生成)
3. 断在 XHR send/header 设置处,往回看参数来源
4. 打印关键函数入参出参(Hook 优先)
5. SourceMap 有就恢复源码(有时 map 直接公开)

13.5 补环境实战要点

Node 里跑浏览器代码常见的缺失:window document navigator localStorage crypto

// 最小补丁示例(有依据地补!)
global.window = global;
global.navigator = { userAgent: "Mozilla/5.0 ..." };
global.document = { createElement: () => ({ getContext: () => null }) };
// crypto: Node 20+ 有 globalThis.crypto,老代码用 require("crypto") 填

关键纪律:页面观察证据显示什么,才补什么。逐字段补,逐字段验证。

13.6 AST 去混淆入门

混淆常见形态:
- 字符串数组 + 下标访问(数组化字符串)
- 控制流平坦化
- 死代码/冗余包裹
- 变量名混淆(对逻辑无影响,可跳过)

工具链: Babel parser → transform → generator
思路: 提取字符串数组 → 全局替换下标引用 → 手动化简主要函数

13.7 常见前端签名模式

模式 识别 复现
MD5/SHA1 拼接 字符串拼接 + 标准哈希 crypto-js/node crypto 复现
HMAC 固定 key crypto.createHmac
AES 加密参数 crypto-js AES 找 key 和 iv(常硬编码或可预测)
RSA 加密 JSEncrypt 找公钥(通常明文在 JS 里)
时间戳+随机数 服务端校验 模拟时间戳格式
自定义混淆算法 乱函数名 AST 去混淆还原
风控指纹 设备信息采集 补环境模拟指纹

13.8 常见失败与回退

□ 页面一直 429/验证码 → 检查频率/代理(ProxyCat 轮换 IP)
□ Hook 不到函数 → 换 breakpoint / 看 SourceMap / 全局搜特征字符串
□ 本地跑不通 → 对比页面与 Node 输出的第一个差异点(first divergence)
□ 混淆太重 → 换 AST 方案 / 直接浏览器内执行复现(走 Playwright)

动手练习

  1. 找一个带签名参数的公开网站(或教学站),完成 Observe → Capture:定位签名函数。
  2. 把签名函数带回 Node,用补环境跑通,产出和你浏览器里一样的参数。
  3. 用 Babel 对一段数组化字符串混淆代码去混淆。
  4. 练习证据纪律:每个补丁都记录"为什么补"。

深入阅读

  • 仓库:skills/js-reverse/SKILL.md(五阶段工作流总纲)
  • 仓库:skills/js-reverse/references/env-patching.md(补环境方法论)
  • 仓库:skills/js-reverse/references/local-rebuild.md / node-env-rebuild.md(本地复现)
  • 仓库:skills/js-reverse/references/ast-deobfuscation.md(AST 去混淆)
  • 仓库:skills/js-reverse/references/instrumentation.md / fallbacks.md
  • 实战案例:skills/field-journal/seed-004_js-sign-webpack.md2026-07-05_dsl-vm-captcha-reverse.md