以不可检测的方式检查WebSocket框架

Wal*_*anG 4 javascript google-chrome firefox-addon websocket google-chrome-extension

如何在Chrome扩展程序或Firefox附加组件中以网页无法检测到的方式阅读网页的WebSocket框架?

从Chrome Dev Tools扩展程序检查WebSockets框架可以制定类似的问题,但开发NPAPI插件不再有意义,因为它很快就会被删除.

Rob*_*b W 15

拦截WebSocket数据很容易.只需在页面构造WebSocket之前执行以下脚本.这段代码片段修补了WebSocket构造函数:当创建一个新的WebSocket构造函数时,该代码片段会订阅该message事件,您可以从中执行任何您想要的数据.

此代码段设计为与本机代码无法区分,因此页面无法轻松检测到修改(但请参阅本文末尾的备注).

(function() {
    var OrigWebSocket = window.WebSocket;
    var callWebSocket = OrigWebSocket.apply.bind(OrigWebSocket);
    var wsAddListener = OrigWebSocket.prototype.addEventListener;
    wsAddListener = wsAddListener.call.bind(wsAddListener);
    window.WebSocket = function WebSocket(url, protocols) {
        var ws;
        if (!(this instanceof WebSocket)) {
            // Called without 'new' (browsers will throw an error).
            ws = callWebSocket(this, arguments);
        } else if (arguments.length === 1) {
            ws = new OrigWebSocket(url);
        } else if (arguments.length >= 2) {
            ws = new OrigWebSocket(url, protocols);
        } else { // No arguments (browsers will throw an error)
            ws = new OrigWebSocket();
        }

        wsAddListener(ws, 'message', function(event) {
            // TODO: Do something with event.data (received data) if you wish.
        });
        return ws;
    }.bind();
    window.WebSocket.prototype = OrigWebSocket.prototype;
    window.WebSocket.prototype.constructor = window.WebSocket;

    var wsSend = OrigWebSocket.prototype.send;
    wsSend = wsSend.apply.bind(wsSend);
    OrigWebSocket.prototype.send = function(data) {
        // TODO: Do something with the sent data if you wish.
        return wsSend(this, arguments);
    };
})();
Run Code Online (Sandbox Code Playgroud)

在Chrome扩展中,摘录可以通过运行内容脚本run_at:'document_start',看代码插入到使用内容脚本的页面上下文.

Firefox也支持内容脚本,适用相同的逻辑(带contentScriptWhen:'start').

注意:在页面的其余部分之前执行时,前一个代码段的设计与本机代码无法区分.检测这些修改的唯一(不寻常和脆弱)方法是:

  • 将无效参数传递给WebSocket构造函数,捕获错误并检查依赖于实现的(特定于浏览器的)堆栈跟踪.如果还有一个堆栈帧比平时多,那么构造函数可能会被篡改(从页面的角度看).

  • 序列化构造函数.未修改的构造函数变为function WebSocket() { [native code] },而修补的构造函数看起来像function () { [native code] }(此问题仅出现在Chrome中;在Firefox中,序列化是相同的).

  • 序列化WebSocket.prototype.send方法.由于函数未绑定,序列化it(WebSocket.prototype.send.toString())会显示非本机实现.这可以通过重写.toString方法来减轻,而方法.send又可以通过严格的比较来检测页面Function.prototype.toString.如果您不需要发送的数据,请不要覆盖OrigWebSocket.prototype.send.

  • @wZVanG如果输入是自定义构造函数,您可以覆盖`Function.prototype.toString`并返回与"reality"匹配的自定义值.但这反过来可以通过创建一个新的脚本上下文(iframe)并使用该上下文中的`Function.protototype.toString`来获得真正的序列化来打败.网页不太可能使用我的笔记中的方法,因为它们很复杂并且输出是非标准的(并且在浏览器决定更改内部时可能会中断). (2认同)
  • @wZVanG然后检测修改的唯一方法是将错误的参数传递给构造函数并检查错误的堆栈跟踪.这可以通过捕获错误,重写堆栈跟踪然后重新抛出错误来解决.但是在看到您网站上的pastebin之后,我认为不需要这种额外的对策. (2认同)

Xan*_*Xan 8

还有一种替代Rob W的方法可以完全掩盖与页面的任何交互(对于Chrome)

也就是说,你可以拿出一些重型火炮并使用chrome.debugger.

请注意,使用它将阻止您为相关页面打开Dev Tools(或者更准确地说,打开Dev Tools将使其停止工作,因为只有一个调试器客户端可以连接).

这是一个非常低级的API; 您需要自己使用调试器协议构建查询.此外,相应的事件不在1.1文档中,您需要查看开发版本.

您应该能够接收像这样的WebSocket事件并检查它们payloadData:

{"method":"Network.webSocketFrameSent","params":{"requestId":"3080.31","timestamp":18090.353684,"response":{"opcode":1,"mask":true,"payloadData":"Rock it with HTML5 WebSocket"}}}
{"method":"Network.webSocketFrameReceived","params":{"requestId":"3080.31","timestamp":18090.454617,"response":{"opcode":1,"mask":false,"payloadData":"Rock it with HTML5 WebSocket"}}}
Run Code Online (Sandbox Code Playgroud)

此扩展示例应提供一个起点.

事实上,这是一个起点,假设tabId是您感兴趣的标签:

chrome.debugger.attach({tabId:tab.id}, "1.1", function() {
  chrome.debugger.sendCommand({tabId:tabId}, "Network.enable");
  chrome.debugger.onEvent.addListener(onEvent);
});

function onEvent(debuggeeId, message, params) {
  if (tabId != debuggeeId.tabId)
    return;

  if (message == "Network.webSocketFrameSent") {
    // do something with params.response.payloadData,
    //   it contains the data SENT
  } else if (message == "Network.webSocketFrameReceived") {
    // do something with params.response.payloadData,
    //   it contains the data RECEIVED
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经测试了这种方法(如上所述修改了链接样本)并且它可以工作.

  • 不,如果你这样做,我会努力取消删除它.因为答案对普通观众有用,而Stack Overflow的目的不是回答_你个人_而是其他人也可能需要知道相同的事情. (3认同)