在 Firefox 插件中覆盖原型方法时出现 XrayWrapper 错误(值是可调用的)

XrayWrapper error (value is callable) when overwriting prototype method in Firefox addon

我想监控从 Firefox 附加组件访问浏览器内置对象的某些方法。下面包含的示例代码大部分都有效,除非方法参数之一是函数。然后,我收到以下 XrayWrapper 错误:

XrayWrapper denied access to property 0 (reason: value is callable). See https://developer.mozilla.org/en-US/docs/Xray_vision for more information. Note that only the first denied property access from a given global object will be reported.

我不明白为什么会抛出 XrayWrapper 错误,因为检测的原型是 unsafeWindow(页面脚本)范围内的一个对象。用于检测的内容脚本是:

function logCalls(object, objectName, methodName) {
  var originalMethod = object[methodName];
  object[methodName] = function () {
    console.log(objectName + "." + methodName, "was called");
    originalMethod.apply(this, arguments);
  };
}

// 1. Works (expected)
logCalls(unsafeWindow.RTCPeerConnection.prototype,
        "unsafeWindow.RTCPeerConnection", "createDataChannel");

// 2. Throws XrayWrapper Error (unexpected)
logCalls(unsafeWindow.RTCPeerConnection.prototype,
        "unsafeWindow.RTCPeerConnection", "createOffer");

示例页面脚本:

var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection;
var connection = new PeerConnection({iceServers: []}, {optional: [{RtpDataChannels: !0}]});

// 1. Method call recorded
connection.createDataChannel("", {reliable: !1});

// 2. Method call recorded but causes XrayWrapper error
connection.createOffer(function(a) {
    connection.setLocalDescription(a)
}, function(err) {})

对于 (1),检测按预期工作。调用 createDataChannel 记录到控制台并成功创建数据通道。

对于 (2),检测成功登录到控制台。但是,内容脚本的第 5 行 (originalMethod.apply(this, arguments);) 由于参数列表包含函数而导致上述 XrayWrapper 错误。

首先,您应该对分配到不同安全上下文中的任何方法给予 exportFunction 处理。

但这可能还不够,因为方法主体本身仍在特权上下文中执行,这意味着它接收的任何参数也将是 xray 包装器。将它们传递回特权较低的范围,尤其是通过像 applyarguments 对象这样的神秘魔法可能不会做你期望的事情。可能需要额外的 xray 展开或使用 rest 参数和 .call。

在这种情况下,eval() 调用拦截逻辑进入目标范围并仅导出拦截包装器调用的日志记录函数可能更容易。这样,参数、this 或 return 值将不会有任何非特权 -> 特权 -> 非特权转换,只有日志调用会跨越安全边界。

由于插件审查指南不鼓励使用 eval,因此您可能还需要就该方法咨询审查人员。