| name | web-re-skill |
| description | AI辅助Web逆向工程综合技能。用于Web前端加密/反混淆、浏览器环境补全(补环境)、wasm逆向分析(wasm2c/wasm2js)、视频播放链路解密(m3u8/ts/NAL/TEA)、VMP虚拟机保护分析、浏览器播放对齐(Chrome DevTools MCP先导、worker状态追踪、postMessage序列重放、零输出诊断)、AI自动插桩追踪调用链。触发词:补环境、wasm逆向、解密视频、播放链路、vmp分析、web逆向、ts帧解密、播放对齐、CCTV。 |
Web Reverse Engineering
AI辅助Web逆向工程。融合实战经验(CCTV wasm+vmp 播放链路逆向)与浏览器优先的播放对齐方法论。
核心原则
- 浏览器优先 — 以浏览器捕获的实证为唯一权威来源,不猜测任何环境字段
- 不写一行代码 — 让AI自动完成补环境、插桩、分析;人工聚焦在验证和决策
- 状态即数据 — postMessage 顺序、vmpTag 状态都是必须精确复现的数据
- 合理目标 — 从"完全黑盒"推进到"本地可用",不追求完美复刻
决策树:选择逆向策略
用户提供了什么?
├── 完整 URL(如 tv.cctv.com/...shtml)
│ └── → 浏览器优先工作流(第2节)
│ CDP 打开页面 → 跟踪播放链路 → 保存环境证据 → 用户确认 → Node 复现
│
├── JS 代码文件
│ ├── 含 wasm(有 VMP) → 直接补源JS(策略3),跳过 wasm 转换
│ ├── 含 wasm(无 VMP) → wasm2js 后补环境,或 wasm2c 分析算法
│ └── 纯 JS 加密 → AI 自动插桩分析 + 补环境
│
├── wasm 二进制
│ ├── wasm2js 转 JS 调试
│ └── wasm2c 转 C 分析算法
│
└── m3u8/ts 文件(视频解密)
└── → 视频解密工作流(第7节)
检测加密类型 → 提取密钥 → 解密 ts → ffmpeg 验证
1. 浏览器优先工作流(四阶段法)
当处理具体网页(如 CCTV 视频播放)时,严格遵循以下四个阶段。
阶段1:浏览器发现(Browser Discovery)
用 Chrome DevTools MCP 打开目标页面,捕获:
□ 页面 URL
□ 脚本引导链(script bootstrap chain)
□ Worker 创建路径及每个 worker 的角色
□ Worker URL(原始脚本路径 / blob worker / host-worker)
□ 页面环境转储(全局变量、location、navigator 等)
□ Worker 环境转储
□ 网络请求顺序:
- video info / H5player.json
- playlist / m3u8
- 各 ts fragment
- 配置文件
□ 播放引导:
- player init 调用
- MediaSource / SourceBuffer 创建
- codec 字符串
□ 主线程 → worker 消息顺序(postMessage 序列)
□ Worker → 主线程消息顺序
□ 解密发生在哪个阶段(moduleActive / moduleDecData)
□ transmux / mux / remux 发生在哪里
□ Wasm / module 初始化序列
捕获的每一条都必须是浏览器实证,不能是推测。
阶段2:用户确认(User Confirmation)
保存浏览器发现的完整流程记录,向用户确认:
- 这是正确的播放流程吗?
- 有遗漏的阶段吗?
- 是否按此流程进行 Node 复现?
- Node 环境是否基于该页面的浏览器环境构建?
阶段3:Node 复现(Node Recreation)
□ Node.js 是唯一的本地运行目标
□ jsdom 模拟被证实需要的浏览器字段
□ pageHref / workerHref / location 等值从浏览器捕获
□ 复用真实 worker 源码而非重写等价逻辑
□ 保持 postMessage 顺序与浏览器一致
□ 保持输入字节与浏览器一致
□ 不补浏览器未观测到的字段
阶段4:验证(Validation)
□ ffprobe 检查输出媒体信息
□ ffmpeg remux 或 decode-check
□ 输出验证结果报告
危险信号(停止并返回浏览器)
- 在没有浏览器证据的情况下模拟请求
- 凭记忆添加 location / navigator 字段
- 重排或省略 worker 消息
- 使用 HTML 而非 Node 做本地复现
- 跳过输出验证
- 浏览器流程未经用户确认就进入 Node 复现
2. 浏览器环境补全(补环境)
需要补的浏览器环境变量
| 变量 | 补全方式 | 来源场景 |
|---|
window / document / self | jsdom | 几乎所有页面 |
location / location.origin | 从浏览器捕获 | 环境检测 |
pageHref / workerHref | 从浏览器捕获 | worker 环境 |
navigator.userAgent | 从浏览器捕获 | 环境检测 |
mediaTagID | 从页面元素提取 | 播放器 |
Date.now() / performance.now() | 固定时间 | 时间相关算法 |
new Date() | 固定时间 | 时间相关算法 |
blob worker href/pathname/protocol | 从浏览器捕获 | worker 环境 |
| XHR/fetch | mock 返回 | 环境检测请求 |
indexedDB | mock | 存储检测 |
补环境代码框架
const { JSDOM } = require('jsdom');
const dom = new JSDOM('<!DOCTYPE html>', {
url: 'https://example.com',
referrer: 'https://example.com',
contentType: 'text/html',
pretendToBeVisual: true,
runScripts: 'dangerously',
});
global.window = dom.window;
global.document = dom.window.document;
global.navigator = dom.window.navigator;
global.location = dom.window.location;
global.self = dom.window;
const FIXED_TIME = 1712345678000;
Date.now = () => FIXED_TIME;
global.performance = { now: () => 0 };
AI 辅助补环境迭代
Round 1: 原始 JS 给 AI,告知入口函数名
→ AI 返回补环境后代码
→ 运行,记录错误
Round 2: 错误信息给 AI
→ AI 补充缺失变量/函数
→ 继续运行
Round N: 重复直到解密函数正常输出
详细参考:references/browser-env.md
3. Wasm 逆向分析
Wasm 转换工具
npm install -g wabt
wasm2js input.wasm -o output.js
wasm2c input.wasm -o output.c
VMP(虚拟机保护)识别特征
- wasm 中存在中心分发函数(如
f50)
- 所有导出函数最终都进入该分发函数
- 包含超长字节码段(VMP 指令集)
- 同一输入在不同状态下输出可能不同
检测到 VMP → 直接补源JS,跳过 wasm2c/wasm2js 深度分析。
三种策略对比
| 策略 | 方法 | 适用场景 | 缺点 |
|---|
| wasm2c | wasm2c in.wasm -o out.c | 无VMP,深究算法 | VMP下无意义 |
| wasm2js | wasm2js in.wasm -o out.js | 无VMP,JS调试 | 代码体积巨大 |
| 直接补源JS | JS不变,只补环境 | 含VMP的推荐方案 | 需处理超长字节码 |
VMP 代码特征(wasm2js 输出)
function $49($0_1, $1_1, $2_1, $3_1) {
if ((global$4 | 0) != (2 | 0)) {
HEAP32[(global$1 + 8 | 0) >> 2] = $0_1;
if ((global$4 | 0) == (1 | 0)) { global$4 = 3 }
}
$0(gimport$4 + 513548 | 0 | 0);
return HEAP32[global$1 >> 2] | 0 | 0;
}
4. 浏览器播放对齐
当浏览器播放正常但本地复现结果不同时,定位差异。
核心原则
- Trust the browser — 浏览器主 worker 是状态序列的权威来源
- State over input — 相同输入 + 不同状态序列 = Session 积累问题
- Message order matters — postMessage 顺序比内容更重要
最小浏览器插桩
const origWorker = window.Worker;
const captured = { messages: [], workerUrl: null };
window.Worker = function(url, options) {
captured.workerUrl = url;
const w = new origWorker(url, options);
const origPost = w.postMessage;
w.postMessage = function(msg) {
captured.messages.push({
ordinal: captured.messages.length,
time: Date.now(),
type: msg?.constructor?.name,
});
return origPost.apply(this, arguments);
};
return w;
};
零输出分析
记录每个零输出调用:segment_index、call_ordinal、timing_tag、state_tag、input_length、output_length。
精简实验(按顺序尝试)
- Neighbor-window: 比较 ordinal-1, ordinal, ordinal+1
- Alternate timing: 同一单元换不同时间值
- Skip-ordinal: 跳过前置单元看是否影响后续
- Browser-message replay: 重放浏览器 postMessage 序列
- State-window capture: 调用前后快照 worker 状态
详细参考:references/playbook.md
5. AI 自动插桩分析
让 AI 在关键路径自动插入日志追踪参数传递。
提示词模板
分析以下 JS 的 {函数名} 调用链:
1. 标注所有子函数及作用
2. 追踪参数从入口到最终使用的路径
3. 识别加密算法特征(TEA/AES/RC4/XOR)
4. 标记所有浏览器环境依赖
5. 自动插入 console.log 调试日志
6. 视频解密模式
常见加密方案
| 方案 | 识别特征 | 应对 |
|---|
| 固定 KEY | m3u8 含 #EXT-X-KEY:URI="..." | 下载 KEY 解密 |
| TEA加密 | 密钥嵌入 NAL 数据 | NAL[15:31] 取16字节 |
| Wasm+VMP | wasm + vmptag 状态推进 | 补环境 + postMessage 重放 |
| Token/DRM | 需要会话 token | 模拟认证 |
算法参考
from Crypto.Cipher import AES
key = nal_data[15:31]
cipher = AES.new(key, AES.MODE_ECB)
decrypted = cipher.decrypt(encrypted_data)
- LCG mediaid: 以时间戳为种子,
X_{n+1} = (a*X_n + c) mod m
- VMPTag状态机: 初始0,每次调用
[0~6]触发,调用后→7
完整视频逆向流程示例(CCTV)
1. CDP 打开视频页面 → 捕获网络请求获取 m3u8
2. 提取播放器 JS → 定位解密入口函数 ua
3. 检测到 wasm+VMP → 直接补源JS
4. 捕获 postMessage 序列和环境变量
5. AI 补环境(jsdom + 固定时间 + location)
6. Node.js 运行,检查 NAL 输出
7. 修复缺失环境(XHR mock, workerHref 等)
8. 下载 ts 分段解密
9. ffmpeg 合成 mp4 验证
10. 检查花屏 → 继续补环境
7. 产出规范
本地文件保存
每次复现保存以下产物:
artifacts/{session_name}/
├── browser-flow-summary.md # 浏览器流程记录
├── browser-environment.json # 浏览器环境转储
├── worker-message-order.json # postMessage 序列
├── request-list.json # 网络请求列表
├── downloaded-sources/ # 下载的 JS 源码(原始+格式化)
│ ├── player-original.js
│ └── player-formatted.js
├── node-reproduction-summary.md # Node 复现结果
└── validation-report.txt # ffmpeg/ffprobe 验证报告
环境输出要求
每次追踪后,保存环境摘要说明 Node 正在模拟什么:
- 页面 URL
- worker URL
- 哪些全局变量存在/不存在
- 使用哪些网络/存储 API
- 从浏览器捕获并固定的值
- 仍未知的字段(不允许猜测)
参考文件
按需加载:
脚本工具