Edge/Chrome CDP 远程调试
1. 启动浏览器开启调试端口
# Edge
msedge.exe --remote-debugging-port=9222 --user-data-dir=D:\edge_debug
# Chrome
chrome.exe --remote-debugging-port=9222
2. 获取 WebSocket 调试地址
访问:
http://127.0.0.1:9222/json
返回 JSON,找 webSocketDebuggerUrl:
{
"title": "test page",
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/ABC123"
}
3. 用 DevTools 前端连接
把 ws 地址传给 DevTools 前端:
devtools://devtools/bundled/devtools_app.html?ws=127.0.0.1:9222/devtools/page/ABC123
在 Edge/Chrome 地址栏直接输入即可,打开完整的开发者工具界面。
核心结构:
浏览器(Edge/Chrome)
↓ WebSocket (CDP)
DevTools Frontend(网页 UI)
Node.js TextDecoder 支持情况
Node.js ≥ 11 支持 TextDecoder,Node ≥ 16/18 更稳定:
const { TextDecoder, TextEncoder } = require('util');
const decoder = new TextDecoder('utf-8');
const buf = Buffer.from([0xe4, 0xbd, 0xa0]); // "你"
console.log(decoder.decode(buf)); // 你
Hook TextDecoder.decode
用于拦截 WebSocket / CDP 协议里的二进制转文本:
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.decode]', result);
return result;
};
全局 hook(拦截所有实例):
const orig = TextDecoder;
global.TextDecoder = function (...args) {
const instance = new orig(...args);
const _decode = instance.decode;
instance.decode = function (...params) {
const res = _decode.apply(this, params);
console.log('[WS decode]', res);
return res;
};
return instance;
};
Hook JSON.parse 并落盘
const fs = require('fs');
const _parse = JSON.parse;
JSON.parse = function (text, reviver) {
try {
const result = _parse.call(this, text, reviver);
// 只保存含 "raw" 字段的数据
if (result && typeof result === 'object' && 'raw' in result) {
fs.appendFileSync(
'./json_raw_log.txt',
JSON.stringify({
time: Date.now(),
data: result
}) + '\n'
);
}
return result;
} catch (e) {
return _parse.call(this, text, reviver);
}
};
按关键字过滤避免刷屏:
// 只记录长度 < 5000、包含关键字的
if (typeof text === 'string' && text.length < 5000 && text.includes('method')) {
fs.appendFileSync('./log.txt', text + '\n');
}
Hook Node.js AES 加密
Hook crypto.createCipheriv 抓加密前的明文、key、IV:
const crypto = require('crypto');
const _createCipheriv = crypto.createCipheriv;
crypto.createCipheriv = function (algorithm, key, iv, options) {
console.log('[AES createCipheriv]', {
algorithm,
key: Buffer.isBuffer(key) ? key.toString('hex') : key,
iv: Buffer.isBuffer(iv) ? iv.toString('hex') : iv
});
const cipher = _createCipheriv.call(this, algorithm, key, iv, options);
const _update = cipher.update;
const _final = cipher.final;
cipher.update = function (data, inputEncoding, outputEncoding) {
console.log('[AES encrypt input]', data?.toString?.() ?? data);
return _update.apply(this, arguments);
};
cipher.final = function (outputEncoding) {
const res = _final.apply(this, arguments);
console.log('[AES encrypt output]', res);
return res;
};
return cipher;
};
解密 hook(对称):
const _createDecipheriv = crypto.createDecipheriv;
crypto.createDecipheriv = function (algorithm, key, iv) {
const decipher = _createDecipheriv.call(this, algorithm, key, iv);
const _update = decipher.update;
decipher.update = function (data) {
const res = _update.apply(this, arguments);
console.log('[AES decrypt result]', res.toString());
return res;
};
return decipher;
};
组合 hook(实战抓包)
WebSocket + 加密接口逆向的标准三件套:
TextDecoder.prototype.decode— 抓二进制转文本JSON.parse— 抓接口返回 JSONcrypto.createCipheriv/createDecipheriv— 抓 AES 明文和密钥
部分代码直接用 Buffer.toString('utf-8') 而不经过 TextDecoder,还需要额外 hook:
const _toString = Buffer.prototype.toString;
Buffer.prototype.toString = function (encoding, ...rest) {
const result = _toString.call(this, encoding, ...rest);
if (encoding === 'utf8' || encoding === 'utf-8') {
console.log('[Buffer.toString]', result.slice(0, 200));
}
return result;
};