feat(v2.4.0): JSVMP 双路径攻克体系 + jsdom 环境补丁知识库

基于实战经验重构 JSVMP 分析框架:

- SKILL.md: 新增路径选择决策树(路径 A 算法追踪 vs 路径 B 环境伪装)
- SKILL.md: 路径 B「环境伪装六步法」完整方法论(采集→对比→分级→补丁→验证→端到端)
- SKILL.md: 新增场景 10「JSVMP + jsdom 环境伪装」、解法模式 E
- SKILL.md: 标注三板斧适用边界与局限,经验法则扩充至 22 条
- references/jsdom-env-patches.md: 新增 jsdom 环境补丁知识库(Function.toString 三层防御 / plugins 完整模拟 / DOM 布局属性 / 30+ API 存根)
- cases/: 新增经验库系统(模板 + 首个 JSVMP 实战案例含 58 项环境检测差异全表)
- references/jsvmp-analysis.md: JSVMP 专项分析详细指南
- references/troubleshooting.md: 常见问题排查指南
- templates/python-request/: Python 项目模板
- 各 references 文档增强、Python 技术栈支持、MCP v1.1 适配(44→52 工具)

Made-with: Cursor
This commit is contained in:
白夜
2026-04-02 18:10:05 +08:00
parent fd6e51c825
commit b5cf8b121a
30 changed files with 4045 additions and 433 deletions
+194 -125
View File
@@ -2,46 +2,51 @@
## 概述
本手册详细说明 `js-reverse` 和 `chrome-devtools` 两个 MCP 服务器的协作使用方式,
本手册详细说明 `camoufox-reverse` MCP 服务器的使用方式,
提供常见逆向场景下的具体操作步骤。
## 工具速查表
### js-reverse MCP(逆向分析核心)
### camoufox-reverse MCP(52 个工具)
| 类别 | 工具 | 核心用途 |
|------|------|---------|
| **源码搜索** | `search_in_sources` | 在所有 JS 中搜索关键词 |
| **源码获取** | `get_script_source` | 获取指定脚本的代码片段 |
| **源码保存** | `save_script_source` | 将脚本保存到本地文件 |
| **浏览器** | `launch_browser` / `close_browser` | 启动/关闭反检测浏览器 |
| **导航** | `navigate` / `reload` / `go_back` | 页面导航 |
| **页面交互** | `click` / `type_text` / `wait_for` | 元素交互 |
| **截图** | `take_screenshot` / `take_snapshot` | 截图 / 无障碍树 |
| **页面信息** | `get_page_info` / `get_page_html` | 页面状态和 HTML |
| **源码搜索** | `search_code` | 在所有 JS 中搜索(结构化结果,默认 max_results=50) |
| **精确搜索** | `search_code_in_script` | 在指定脚本中搜索(前后 3 行上下文,适合大文件) |
| **源码获取** | `get_script_source` | 获取指定脚本的代码 |
| **源码保存** | `save_script` | 将脚本保存到本地文件 |
| **脚本列表** | `list_scripts` | 列出页面加载的所有脚本 |
| **断点设置** | `set_breakpoint_on_text` | 按代码文本设置断点 |
| **XHR 断点** | `break_on_xhr` | 在 XHR 请求时暂停 |
| **函数追踪** | `trace_function` | 追踪函数调用,记录参数 |
| **暂停信息** | `get_paused_info` | 获取断点处的栈和变量 |
| **单步调试** | `step_into/over/out` | 单步执行 |
| **脚本注入** | `inject_before_load` | 页面加载前注入 JS |
| **脚本执行** | `evaluate_script` | 在页面执行 JS |
| **网络请求** | `list_network_requests` | 列出网络请求 |
| **请求详情** | `get_network_request` | 获取请求完整信息 |
| **请求来源** | `get_request_initiator` | 获取请求的 JS 调用栈 |
| **WebSocket** | `list_websocket_connections` | 列出 WS 连接 |
| **WS 分析** | `analyze_websocket_messages` | 分析 WS 消息模式 |
| **控制台** | `list_console_messages` | 读取控制台输出 |
### chrome-devtools MCP(浏览器自动化)
| 类别 | 工具 | 核心用途 |
|------|------|---------|
| **页面管理** | `new_page` / `navigate_page` / `close_page` | 页面操作 |
| **UI 交互** | `click` / `fill` / `type_text` / `press_key` | 元素交互 |
| **DOM 快照** | `take_snapshot` | 获取页面文本结构 |
| **截图** | `take_screenshot` | 页面截图 |
| **脚本执行** | `evaluate_script` | 执行 JS |
| **设备模拟** | `emulate` | 模拟 UA/视口/网络 |
| **网络请求** | `list_network_requests` / `get_network_request` | 请求监控 |
| **等待** | `wait_for` | 等待文本出现 |
| **对话框** | `handle_dialog` | 处理弹窗 |
| **执行 JS** | `evaluate_js` / `evaluate_js_handle` | 在页面执行任意 JS |
| **加载前注入** | `add_init_script` | 页面加载前注入脚本(支持 `persistent` 跨导航重注入) |
| **伪断点** | `set_breakpoint_via_hook` | 通过 Hook 设置伪断点(支持 `persistent` 持久化) |
| **断点数据** | `get_breakpoint_data` | 获取伪断点捕获的数据 |
| **函数追踪** | `trace_function` / `get_trace_data` | 追踪函数调用(支持 `persistent` 跨导航持久化) |
| **自定义 Hook** | `hook_function` | 注入自定义 Hook(before/after/replace,支持 `non_overridable` 防覆盖) |
| **预设 Hook** | `inject_hook_preset` | 一键 Hook(xhr/fetch/crypto/websocket/debugger_bypass,默认持久化) |
| **移除 Hook** | `remove_hooks` | 移除所有 Hook(支持 `keep_persistent` 保留持久化 Hook) |
| **冻结原型** | `freeze_prototype` | 冻结任意原型方法,防止页面 JS 覆盖 Hook |
| **属性追踪** | `trace_property_access` / `get_property_access_log` | Proxy 级别属性访问追踪 |
| **JSVMP 插桩** | `hook_jsvmp_interpreter` | 一键插桩 JSVMP(Function.prototype.apply + 30+ 敏感属性) |
| **JSVMP 日志** | `get_jsvmp_log` | 获取 JSVMP 日志(API 调用统计 + 属性读取摘要) |
| **JSVMP 字符串** | `dump_jsvmp_strings` | 提取字符串数组,识别 API 名称,检测混淆模式 |
| **环境采集** | `compare_env` | 全面收集浏览器环境(navigator/screen/canvas/WebGL/Audio/timing) |
| **网络捕获** | `start_network_capture` / `stop_network_capture` | 启停网络捕获(支持 `capture_body` 捕获响应体) |
| **网络请求** | `list_network_requests` | 列出捕获的请求 |
| **请求详情** | `get_network_request` | 获取请求完整信息(含响应体) |
| **请求来源** | `get_request_initiator` | 获取请求的 JS 调用栈(改进 URL 匹配 + 诊断信息) |
| **请求拦截** | `intercept_request` / `stop_intercept` | 拦截/修改/Mock 请求 |
| **Cookie** | `get_cookies` / `set_cookies` / `delete_cookies` | Cookie 管理 |
| **Storage** | `get_storage` / `set_storage` | localStorage / sessionStorage |
| **状态管理** | `export_state` / `import_state` | 保存/恢复浏览器状态 |
| **控制台** | `get_console_logs` | 读取控制台输出 |
| **指纹** | `get_fingerprint_info` | 检查浏览器指纹 |
| **反检测** | `check_detection` | 测试是否被反爬识别 |
| **反调试** | `bypass_debugger_trap` | 绕过 debugger 陷阱 |
## 场景化操作手册
@@ -50,40 +55,46 @@
**目标**:找到接口中加密参数的生成逻辑
```
步骤 1:打开目标页面
[chrome-devtools] new_page(url="https://target.com")
步骤 1:启动反检测浏览器
[camoufox-reverse] launch_browser()
步骤 2:获取页面结构
[chrome-devtools] take_snapshot() → 确认页面正常加载
步骤 2:导航到目标页面
[camoufox-reverse] navigate(url="https://target.com")
步骤 3:触发数据请求(如翻页)
[chrome-devtools] click(uid="翻页按钮的uid")
步骤 3:确认页面加载
[camoufox-reverse] take_screenshot() → 确认页面正常
步骤 4:开始网络捕获
[camoufox-reverse] start_network_capture()
步骤 5:触发数据请求(如翻页)
[camoufox-reverse] click(selector=".next-page")
或
[chrome-devtools] evaluate_script(function="document.querySelector('.next').click()")
[camoufox-reverse] evaluate_js(expression="document.querySelector('.next').click()")
步骤 4:查看网络请求
[js-reverse] list_network_requests(resourceTypes=["XHR","Fetch"])
步骤 6:查看网络请求
[camoufox-reverse] list_network_requests
步骤 5:获取目标请求详情
[js-reverse] get_network_request(reqid=目标请求ID)
步骤 7:获取目标请求详情
[camoufox-reverse] get_network_request(request_id=N)
→ 记录 URL、Headers、Params、Response
步骤 6:获取请求调用栈
[js-reverse] get_request_initiator(requestId=目标请求ID)
→ 找到发起请求的 JS 函数
步骤 8:获取请求调用栈(黄金路径)
[camoufox-reverse] get_request_initiator(request_id=N)
→ 直接定位发起请求的 JS 函数
步骤 7:搜索加密参数
[js-reverse] search_in_sources(query="参数名=")
[js-reverse] search_in_sources(query="参数名")
步骤 9:搜索加密参数
[camoufox-reverse] search_code(keyword="参数名=")
[camoufox-reverse] search_code(keyword="参数名")
步骤 8:读取相关源码
[js-reverse] get_script_source(url="包含加密逻辑的脚本URL", startLine=X, endLine=Y)
步骤 10:读取相关源码
[camoufox-reverse] get_script_source(script_url="包含加密逻辑的脚本URL")
步骤 9:设置断点验证
[js-reverse] set_breakpoint_on_text(text="加密函数调用")
步骤 11:设置伪断点验证
[camoufox-reverse] set_breakpoint_via_hook(target_function="加密函数路径")
触发请求 →
[js-reverse] get_paused_info(includeScopes=true)
→ 查看变量值确认加密逻辑
[camoufox-reverse] get_breakpoint_data
→ 查看捕获的参数和返回值
```
### 场景 2:动态 Cookie 逆向
@@ -92,25 +103,31 @@
```
步骤 1:注入 Cookie Hook
[js-reverse] inject_before_load(script="Cookie setter Hook 代码")
[camoufox-reverse] hook_function(
function_path="Document.prototype.cookie",
hook_code="console.log('[Cookie Set]', arguments[0]); console.trace('Cookie Stack');",
position="before"
)
或使用预设 Hook:
[camoufox-reverse] inject_hook_preset(preset="crypto")
步骤 2:刷新页面触发 Cookie 生成
[js-reverse] navigate_page(type="reload")
[camoufox-reverse] reload()
步骤 3:读取 Hook 输出
[js-reverse] list_console_messages(types=["log"])
[camoufox-reverse] get_console_logs
→ 找到 Cookie 设置记录和调用栈
步骤 4:根据调用栈定位生成函数
[js-reverse] search_in_sources(query="目标函数名")
[js-reverse] get_script_source(url="...", startLine=X, endLine=Y)
[camoufox-reverse] search_code(keyword="目标函数名")
[camoufox-reverse] get_script_source(script_url="...")
步骤 5:分析生成逻辑
[js-reverse] set_breakpoint_on_text(text="cookie生成代码片段")
[camoufox-reverse] set_breakpoint_via_hook(target_function="cookie生成函数")
刷新页面 →
[js-reverse] get_paused_info → 查看入参
[js-reverse] step_into → 进入加密函数
[js-reverse] get_paused_info → 查看中间值
[camoufox-reverse] get_breakpoint_data → 查看入参和返回值
[camoufox-reverse] trace_function(function_path="加密函数", log_args=true, log_return=true, log_stack=true)
[camoufox-reverse] get_trace_data → 查看中间值
```
### 场景 3:混淆代码分析
@@ -119,27 +136,27 @@
```
步骤 1:列出所有脚本
[js-reverse] list_scripts()
[camoufox-reverse] list_scripts
→ 找到可疑的混淆脚本(通常文件名无意义或体积很大)
步骤 2:保存混淆脚本到本地
[js-reverse] save_script_source(url="混淆脚本URL", filePath="./project/obfuscated.js")
[camoufox-reverse] save_script(script_url="混淆脚本URL", save_path="./project/obfuscated.js")
步骤 3:搜索关键特征
[js-reverse] search_in_sources(query="_0x", urlFilter="混淆脚本URL")
[camoufox-reverse] search_code(keyword="_0x")
→ 确认混淆类型(OB混淆)
[js-reverse] search_in_sources(query="switch|while.*true", urlFilter="混淆脚本URL")
[camoufox-reverse] search_code(keyword="switch|while.*true")
→ 检查是否有控制流平坦化
步骤 4:在浏览器中还原字符串
[js-reverse] evaluate_script(function="返回字符串数组的代码")
[camoufox-reverse] evaluate_js(expression="返回字符串数组的代码")
→ 获取解密后的字符串映射
步骤 5:定位关键函数
[js-reverse] search_in_sources(query="encrypt|sign|md5|aes", urlFilter="混淆脚本URL")
[camoufox-reverse] search_code(keyword="encrypt|sign|md5|aes")
→ 找到加密相关代码的大致位置
[js-reverse] get_script_source → 获取上下文
[camoufox-reverse] get_script_source → 获取上下文
```
### 场景 4:WASM 逆向
@@ -148,29 +165,24 @@
```
步骤 1:搜索 WASM 加载代码
[js-reverse] search_in_sources(query="WebAssembly|.wasm|instantiate")
[camoufox-reverse] search_code(keyword="WebAssembly|.wasm|instantiate")
步骤 2:找到 WASM 文件
[js-reverse] list_network_requests(resourceTypes=["Other"])
[camoufox-reverse] list_network_requests
→ 找到 .wasm 文件的请求
步骤 3:分析 WASM 调用
[js-reverse] search_in_sources(query="exports.|instance.exports")
[camoufox-reverse] search_code(keyword="exports.|instance.exports")
→ 找到导出函数的调用代码
步骤 4:追踪输入输出
[js-reverse] set_breakpoint_on_text(text="wasm导出函数调用")
[camoufox-reverse] set_breakpoint_via_hook(target_function="wasm导出函数调用路径")
触发请求 →
[js-reverse] get_paused_info → 查看入参
[js-reverse] step_over → 执行函数
[js-reverse] get_paused_info → 查看返回值
[camoufox-reverse] get_breakpoint_data → 查看入参和返回值
步骤 5:在浏览器中测试
[js-reverse] evaluate_script(function="调用wasm函数并返回结果")
[camoufox-reverse] evaluate_js(expression="调用wasm函数并返回结果")
→ 验证 I/O 关系
步骤 6:下载 WASM 文件
[chrome-devtools] get_network_request(reqid=WASM请求ID, responseFilePath="./project/main.wasm")
```
### 场景 5:WebSocket 通信分析
@@ -178,18 +190,18 @@
**目标**:分析 WebSocket 消息格式和加密
```
步骤 1:列出 WS 连接
[js-reverse] list_websocket_connections()
步骤 1:注入 WebSocket Hook
[camoufox-reverse] inject_hook_preset(preset="websocket")
步骤 2:分析消息模式
[js-reverse] analyze_websocket_messages(wsid=连接ID, direction="sent")
[js-reverse] analyze_websocket_messages(wsid=连接ID, direction="received")
步骤 2:读取 WS 消息日志
[camoufox-reverse] get_console_logs
→ 获取 WS 发送/接收消息
步骤 3:获取具体消息
[js-reverse] get_websocket_messages(wsid=连接ID, show_content=true)
步骤 3:搜索 WS 相关代码
[camoufox-reverse] search_code(keyword="WebSocket|ws.send|onmessage")
步骤 4:搜索 WS 相关代码
[js-reverse] search_in_sources(query="WebSocket|ws.send|onmessage")
步骤 4:手动发送 WS 消息
[camoufox-reverse] evaluate_js(expression="ws.send(JSON.stringify({...}))")
```
## 高级技巧
@@ -197,30 +209,79 @@
### 使用 trace_function 自动记录函数调用
```
[js-reverse] trace_function(
functionName="encrypt",
logArgs=true,
logThis=false,
pause=false
[camoufox-reverse] trace_function(
function_path="window.encrypt",
log_args=true,
log_return=true,
log_stack=true,
max_captures=50,
persistent=True → 跨导航持久化,页面刷新/跳转后自动重注入
)
```
→ 每次 `encrypt` 被调用时自动记录参数,不暂停执行
→ 每次 `encrypt` 被调用时自动记录参数、返回值和调用栈,不暂停执行
→ `get_trace_data` 会自动合并页面数据和 Python 端持久化数据
### 使用条件断点
### 使用 inject_hook_preset 一键 Hook
```
[js-reverse] set_breakpoint_on_text(
text="fetch(",
condition="arguments[0].indexOf('/api/data') !== -1"
默认 persistent=True(持久化,跨导航自动重注入):
[camoufox-reverse] inject_hook_preset(preset="xhr") → Hook 所有 XHR 请求
[camoufox-reverse] inject_hook_preset(preset="fetch") → Hook 所有 fetch 请求
[camoufox-reverse] inject_hook_preset(preset="crypto") → Hook btoa/atob/JSON.stringify
[camoufox-reverse] inject_hook_preset(preset="websocket") → Hook WebSocket 消息
[camoufox-reverse] inject_hook_preset(preset="debugger_bypass") → 绕过反调试
```
### 使用 hook_function 自定义 Hook
```
[camoufox-reverse] hook_function(
function_path="XMLHttpRequest.prototype.open",
hook_code="console.log('[XHR]', arguments[0], arguments[1])",
position="before",
non_overridable=True → 防覆盖:Object.defineProperty 冻结 + toString 伪装 native code
)
```
→ 只在请求特定接口时暂停
→ 在 XHR.open 调用前输出请求方法和 URL,即使页面 JS 尝试覆盖也不会丢失
### 使用 inject_before_load 进行预分析
### 使用 freeze_prototype 防止 Hook 被覆盖
```
[js-reverse] inject_before_load(script=`
// 记录所有全局变量的创建
[camoufox-reverse] freeze_prototype(className="XMLHttpRequest", methodName="send")
```
→ 冻结原型方法(configurable:false + writable:false),防止 JSVMP 等覆盖你的 Hook
### 使用 JSVMP 专项工具
```
[camoufox-reverse] hook_jsvmp_interpreter → 一键插桩 Function.prototype.apply + 30+ 敏感属性
[camoufox-reverse] dump_jsvmp_strings → 提取字符串数组,识别 API 名称
触发操作...
[camoufox-reverse] get_jsvmp_log → 获取 API 调用统计 + 属性读取摘要
[camoufox-reverse] compare_env → 收集完整浏览器环境(补环境基准线)
```
### 使用属性访问追踪
```
[camoufox-reverse] trace_property_access(target_expression="navigator")
触发操作...
[camoufox-reverse] get_property_access_log → 查看 navigator 的哪些属性被读取
```
→ 精确发现 JSVMP 或签名逻辑读取了哪些环境属性
### 使用 search_code_in_script 精确搜索大文件
```
[camoufox-reverse] search_code_in_script(script_id=3, keyword="sign|token|encrypt")
```
→ 在指定脚本中搜索,返回前后 3 行上下文,适合 200KB+ 的 JSVMP 文件
### 使用 add_init_script 进行预分析
```
[camoufox-reverse] add_init_script(script=`
const knownGlobals = new Set(Object.keys(window));
setInterval(() => {
const newGlobals = Object.keys(window).filter(k => !knownGlobals.has(k));
@@ -229,14 +290,13 @@
newGlobals.forEach(k => knownGlobals.add(k));
}
}, 1000);
`)
`, persistent=True) → 跨导航持久化
```
### 使用 evaluate_script 提取运行时数据
### 使用 evaluate_js 提取运行时数据
```
[js-reverse] evaluate_script(function=`
// 提取当前页面的所有 Cookie
[camoufox-reverse] evaluate_js(expression=`
JSON.stringify(document.cookie.split('; ').reduce((obj, pair) => {
const [k, v] = pair.split('=');
obj[k] = v;
@@ -245,20 +305,29 @@
`)
```
## 两个 MCP 的分工原则
### 使用 intercept_request 拦截/修改请求
| 需求 | 使用 js-reverse | 使用 chrome-devtools |
|------|----------------|---------------------|
| 搜索 JS 源码 | ✅ `search_in_sources` | ❌ |
| 设置断点 | ✅ `set_breakpoint_on_text` | ❌ |
| 单步调试 | ✅ `step_into/over/out` | ❌ |
| 函数追踪 | ✅ `trace_function` | ❌ |
| 注入 Hook | ✅ `inject_before_load` | ❌ |
| 页面截图 | ✅ 可以 | ✅ 更灵活(指定元素) |
| UI 交互(点击/输入) | ❌ | ✅ `click/fill/type_text` |
| 模拟 UA/设备 | ❌ | ✅ `emulate` |
| DOM 快照 | ❌ | ✅ `take_snapshot` |
| 保存请求响应到文件 | ❌ | ✅ `get_network_request(responseFilePath)` |
| WebSocket 分析 | ✅ 完整支持 | ❌ |
| 请求调用栈 | ✅ `get_request_initiator` | ❌ |
| 执行 JS | ✅ 支持 `mainWorld` 选项 | ✅ 支持 `args` 传 uid |
```
[camoufox-reverse] intercept_request(url_pattern="**/api/data*", action="log") → 仅记录
[camoufox-reverse] intercept_request(url_pattern="**/ads/*", action="block") → 屏蔽广告
[camoufox-reverse] intercept_request(url_pattern="**/api/*", action="modify", modify_headers={"X-Custom": "test"})
[camoufox-reverse] intercept_request(url_pattern="**/api/*", action="mock", mock_response={"status": 200, "body": "{\"ok\":1}"})
```
## camoufox-reverse MCP 工具分类总览(52 个)
| 类别 | 工具 | 说明 |
|------|------|------|
| 浏览器生命周期 | `launch_browser` `close_browser` | 启动/关闭 Camoufox |
| 页面导航 | `navigate` `reload` `go_back` | 导航控制 |
| 页面交互 | `click` `type_text` `wait_for` | UI 自动化 |
| 页面状态 | `get_page_info` `take_screenshot` `take_snapshot` `get_page_html` | 页面信息 |
| 源码分析 | `list_scripts` `get_script_source` `search_code` `search_code_in_script` `save_script` | JS 逆向核心 |
| JS 执行 | `evaluate_js` `evaluate_js_handle` `add_init_script` | 代码执行(支持持久化) |
| 调试 | `set_breakpoint_via_hook` `get_breakpoint_data` `get_console_logs` | 伪断点调试(支持持久化) |
| Hook | `trace_function` `get_trace_data` `hook_function` `inject_hook_preset` `remove_hooks` `freeze_prototype` | 函数 Hook(支持持久化 + 防覆盖) |
| 属性追踪 | `trace_property_access` `get_property_access_log` | Proxy 级别属性访问监控 |
| JSVMP 专项 | `hook_jsvmp_interpreter` `get_jsvmp_log` `dump_jsvmp_strings` `compare_env` | JSVMP 虚拟机保护分析 |
| 网络 | `start_network_capture` `stop_network_capture` `list_network_requests` `get_network_request` `get_request_initiator` `intercept_request` `stop_intercept` | 网络分析(支持响应体捕获) |
| 存储 | `get_cookies` `set_cookies` `delete_cookies` `get_storage` `set_storage` `export_state` `import_state` | 状态管理 |
| 反检测 | `get_fingerprint_info` `check_detection` `bypass_debugger_trap` | 指纹与反检测 |