Chrome CDP 远程调试:--remote-debugging-port 与 Node.js Hook 框架

CDP 远程调试

启动浏览器并开放调试端口

# Chrome
chrome.exe --remote-debugging-port=9222

# Edge(建议指定独立 user-data-dir)
msedge.exe --remote-debugging-port=9222 --user-data-dir=D:\edge_debug

获取 WebSocket 调试地址

浏览器启动后,访问:

http://127.0.0.1:9222/json

返回当前所有 Tab 的信息,其中 webSocketDebuggerUrl 是关键字段:

{
  "id": "ABC123",
  "title": "test page",
  "webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/ABC123"
}

连接 DevTools 前端

devtools://devtools/bundled/devtools_app.html?ws=127.0.0.1:9222/devtools/page/ABC123

整体链路:--remote-debugging-port 开放 CDP 端口 → /json 获取 ws 地址 → DevTools 前端通过 ws 接入。

Node.js Hook 三件套

在 Node 程序里注入以下 hook 可以拦截运行时数据流。

Hook JSON.parse(记录解析数据)

const fs = require('fs');
const _parse = JSON.parse;

JSON.parse = function (text, reviver) {
    const result = _parse.call(this, text, reviver);

    // 只保存含 "raw" key 的对象
    if (result && typeof result === 'object' && 'raw' in result) {
        fs.appendFileSync('./json_log.txt',
            JSON.stringify({ time: Date.now(), data: result }) + '\n');
    }

    return result;
};

过滤条件也可以改为 /"raw"\s*:/.test(text) 在原始字符串层面筛选,减少反序列化开销。

Hook TextDecoder.decode(截获二进制转字符串)

const { TextDecoder } = require('util');
const _decode = TextDecoder.prototype.decode;

TextDecoder.prototype.decode = function (input, options) {
    const result = _decode.call(this, input, options);
    console.log('[TextDecoder]', result);
    return result;
};

适合抓 WebSocket 二进制帧、CDP 协议数据等场景。注意 Buffer.toString('utf-8') 走的是另一条路径,需要单独 hook Buffer.prototype.toString

Hook AES 加密(抓密钥与明文)

const crypto = require('crypto');
const _createCipheriv = crypto.createCipheriv;

crypto.createCipheriv = function (algorithm, key, iv, options) {
    console.log('[AES key]', {
        algorithm,
        key: key?.toString?.('hex'),
        iv:  iv?.toString?.('hex')
    });

    const cipher = _createCipheriv.call(this, algorithm, key, iv, options);
    const _update = cipher.update;

    cipher.update = function (data) {
        console.log('[AES plaintext]', data?.toString?.() ?? data);
        return _update.apply(this, arguments);
    };

    return cipher;
};

Hook createDecipheriv 的结构完全对称,可以抓解密后的明文。

注意事项

  • JSON.parse 被局部引用绕过时(const p = JSON.parse; p(...)),改 global.JSON.parse 更彻底
  • 大流量场景建议加过滤条件(text.length < 5000)避免日志刷屏
  • Node.js 版本 >= 11 才有全局 TextDecoder,旧版用 require('util').TextDecoder