Firefox不尊重Greasemonkey脚本中的Object.defineProperty()吗?

时间:2019-02-02 04:24:02

标签: javascript firefox tampermonkey adblock greasemonkey-4

我正在写一个用户脚本来阻止网站设置document.body.innerHTML,这是网站检测到adblock的典型标志:

(function() {
    'use strict';
    console.log("Loading ...");

    Object.defineProperty(document.body, "innerHTML", {
        set: function() {
            console.log("malicious activity detected");
            throw "Don't try to fool my adblock!";
        }
    });
    console.log("Test setting document.body ...");
    try {
        document.body.innerHTML = "";
    } catch (e) {
        console.log(e);
    }
}) ();

以上用户脚本适用于Chrome + Tampermonkey。但是它在Firefox + Greasemonkey-4上的行为很奇怪。

控制台中的输出为:

  

正在加载...
  测试设置document.body ...
  检测到恶意活动
  不要试图欺骗我的adblock!

因此,用户脚本加载成功,设置器也成功连接。但是当加载后,我在控制台中尝试:

document.body.innerHTML = ""

它只是设置innerHTML而不会引发错误,就像尚未安装该挂钩一样。我已经尝试了所有@run-at选项,但没有一个起作用。


OTAH,如果我在控制台中使用Object.defineProperty(),则它将按预期工作。因此,我得出结论,Firefox不尊重用户脚本中的Object.defineProperty()

您也可以尝试访问以下网站:https://connectwww.com。通过在Chrome的Tampermonkey中安装上述用户脚本,可以成功拦截网站上的adblock检测。但是该用户脚本不适用于Firefox + Greasemonkey。

为什么Firefox 不尊重用户脚本中的Object.defineProperty()?有什么解决方法吗?

旁注:

上述测试网站的某些知名用户脚本(例如anti-adblock-killer)也可以在Chrome上运行,但不能在Firefox上运行,我想这是出于相同的原因。

1 个答案:

答案 0 :(得分:0)

即使在@grant none模式下,

Greasemonkey 4 也会沙入脚本。 <子>(即大约唯一该的Greasemonkey 4 确实比Tampermonkey或Violentmonkey更好。)

所以,你的脚本设置脚本的范围/拷贝innerHTML
在与目标页面范围共享的Tampermonkey中,但是在Greasemonkey中,更恰当地分隔了两个范围。所以页面范围(以及默认的控制台)看不到的变化。

在这种情况下,我不认为the unsafeWindow methods可以工作作出; 您必须注入替代代码

下面是一个脚本,既Greasemonkey的4+和Tampermonkey作品(而且应该Violentmonkey过,但我没有测试)。它适用于Chrome和Firefox的:

// ==UserScript==
// @name     _Overriding Target page functions can be tricky with GM 4
// @match    *://YOUR_SERVER.COM/YOUR_PATH/*
// @grant    none
// @run-at   document-start
// ==/UserScript==
/* eslint-disable no-multi-spaces */

console.log("Loading ...");

function overrideIt () {
    //-- Necessary check because of scope madness in TM, VM, etc.
    if (document.body.innerHTML) {
        Object.defineProperty (document.body, "innerHTML", {
            set: function () {
                var scopeStr = (typeof GM === "object"  &&  GM.info) ? "script" : "page";
                console.log (`Malicious activity detected - ${scopeStr} scope`);
                throw "Don't try to fool my adblock!";
            }
        } );
    }
}
overrideIt ();

if (typeof unsafeWindow === "object") {
    console.log ("unsafeWindow detected.");
    addJS_Node (null, null, overrideIt);
}

console.log ("Test setting document.body ...");
try {
    document.body.innerHTML = "";
} catch (e) {
    console.log ("Caught: ", e);
}

//-- addJS_Node is a standard(ish) function
function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}