# MCP 工具使用手册 ## 概述 本手册详细说明 `js-reverse` 和 `chrome-devtools` 两个 MCP 服务器的协作使用方式, 提供常见逆向场景下的具体操作步骤。 ## 工具速查表 ### js-reverse MCP(逆向分析核心) | 类别 | 工具 | 核心用途 | |------|------|---------| | **源码搜索** | `search_in_sources` | 在所有 JS 中搜索关键词 | | **源码获取** | `get_script_source` | 获取指定脚本的代码片段 | | **源码保存** | `save_script_source` | 将脚本保存到本地文件 | | **脚本列表** | `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` | 处理弹窗 | ## 场景化操作手册 ### 场景 1:分析数据接口的加密参数 **目标**:找到接口中加密参数的生成逻辑 ``` 步骤 1:打开目标页面 [chrome-devtools] new_page(url="https://target.com") 步骤 2:获取页面结构 [chrome-devtools] take_snapshot() → 确认页面正常加载 步骤 3:触发数据请求(如翻页) [chrome-devtools] click(uid="翻页按钮的uid") 或 [chrome-devtools] evaluate_script(function="document.querySelector('.next').click()") 步骤 4:查看网络请求 [js-reverse] list_network_requests(resourceTypes=["XHR","Fetch"]) 步骤 5:获取目标请求详情 [js-reverse] get_network_request(reqid=目标请求ID) → 记录 URL、Headers、Params、Response 步骤 6:获取请求调用栈 [js-reverse] get_request_initiator(requestId=目标请求ID) → 找到发起请求的 JS 函数 步骤 7:搜索加密参数 [js-reverse] search_in_sources(query="参数名=") [js-reverse] search_in_sources(query="参数名") 步骤 8:读取相关源码 [js-reverse] get_script_source(url="包含加密逻辑的脚本URL", startLine=X, endLine=Y) 步骤 9:设置断点验证 [js-reverse] set_breakpoint_on_text(text="加密函数调用") 触发请求 → [js-reverse] get_paused_info(includeScopes=true) → 查看变量值确认加密逻辑 ``` ### 场景 2:动态 Cookie 逆向 **目标**:找到 Cookie 的生成逻辑 ``` 步骤 1:注入 Cookie Hook [js-reverse] inject_before_load(script="Cookie setter Hook 代码") 步骤 2:刷新页面触发 Cookie 生成 [js-reverse] navigate_page(type="reload") 步骤 3:读取 Hook 输出 [js-reverse] list_console_messages(types=["log"]) → 找到 Cookie 设置记录和调用栈 步骤 4:根据调用栈定位生成函数 [js-reverse] search_in_sources(query="目标函数名") [js-reverse] get_script_source(url="...", startLine=X, endLine=Y) 步骤 5:分析生成逻辑 [js-reverse] set_breakpoint_on_text(text="cookie生成代码片段") 刷新页面 → [js-reverse] get_paused_info → 查看入参 [js-reverse] step_into → 进入加密函数 [js-reverse] get_paused_info → 查看中间值 ``` ### 场景 3:混淆代码分析 **目标**:还原混淆的 JS 代码 ``` 步骤 1:列出所有脚本 [js-reverse] list_scripts() → 找到可疑的混淆脚本(通常文件名无意义或体积很大) 步骤 2:保存混淆脚本到本地 [js-reverse] save_script_source(url="混淆脚本URL", filePath="./project/obfuscated.js") 步骤 3:搜索关键特征 [js-reverse] search_in_sources(query="_0x", urlFilter="混淆脚本URL") → 确认混淆类型(OB混淆) [js-reverse] search_in_sources(query="switch|while.*true", urlFilter="混淆脚本URL") → 检查是否有控制流平坦化 步骤 4:在浏览器中还原字符串 [js-reverse] evaluate_script(function="返回字符串数组的代码") → 获取解密后的字符串映射 步骤 5:定位关键函数 [js-reverse] search_in_sources(query="encrypt|sign|md5|aes", urlFilter="混淆脚本URL") → 找到加密相关代码的大致位置 [js-reverse] get_script_source → 获取上下文 ``` ### 场景 4:WASM 逆向 **目标**:分析 WASM 加密函数的输入输出 ``` 步骤 1:搜索 WASM 加载代码 [js-reverse] search_in_sources(query="WebAssembly|.wasm|instantiate") 步骤 2:找到 WASM 文件 [js-reverse] list_network_requests(resourceTypes=["Other"]) → 找到 .wasm 文件的请求 步骤 3:分析 WASM 调用 [js-reverse] search_in_sources(query="exports.|instance.exports") → 找到导出函数的调用代码 步骤 4:追踪输入输出 [js-reverse] set_breakpoint_on_text(text="wasm导出函数调用") 触发请求 → [js-reverse] get_paused_info → 查看入参 [js-reverse] step_over → 执行函数 [js-reverse] get_paused_info → 查看返回值 步骤 5:在浏览器中测试 [js-reverse] evaluate_script(function="调用wasm函数并返回结果") → 验证 I/O 关系 步骤 6:下载 WASM 文件 [chrome-devtools] get_network_request(reqid=WASM请求ID, responseFilePath="./project/main.wasm") ``` ### 场景 5:WebSocket 通信分析 **目标**:分析 WebSocket 消息格式和加密 ``` 步骤 1:列出 WS 连接 [js-reverse] list_websocket_connections() 步骤 2:分析消息模式 [js-reverse] analyze_websocket_messages(wsid=连接ID, direction="sent") [js-reverse] analyze_websocket_messages(wsid=连接ID, direction="received") 步骤 3:获取具体消息 [js-reverse] get_websocket_messages(wsid=连接ID, show_content=true) 步骤 4:搜索 WS 相关代码 [js-reverse] search_in_sources(query="WebSocket|ws.send|onmessage") ``` ## 高级技巧 ### 使用 trace_function 自动记录函数调用 ``` [js-reverse] trace_function( functionName="encrypt", logArgs=true, logThis=false, pause=false ) ``` → 每次 `encrypt` 被调用时自动记录参数,不暂停执行 ### 使用条件断点 ``` [js-reverse] set_breakpoint_on_text( text="fetch(", condition="arguments[0].indexOf('/api/data') !== -1" ) ``` → 只在请求特定接口时暂停 ### 使用 inject_before_load 进行预分析 ``` [js-reverse] inject_before_load(script=` // 记录所有全局变量的创建 const knownGlobals = new Set(Object.keys(window)); setInterval(() => { const newGlobals = Object.keys(window).filter(k => !knownGlobals.has(k)); if (newGlobals.length > 0) { console.log('[Monitor] 新全局变量:', newGlobals); newGlobals.forEach(k => knownGlobals.add(k)); } }, 1000); `) ``` ### 使用 evaluate_script 提取运行时数据 ``` [js-reverse] evaluate_script(function=` // 提取当前页面的所有 Cookie JSON.stringify(document.cookie.split('; ').reduce((obj, pair) => { const [k, v] = pair.split('='); obj[k] = v; return obj; }, {})) `) ``` ## 两个 MCP 的分工原则 | 需求 | 使用 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 |