我正在写一个用户脚本来阻止网站设置document.body.innerHTML
,这是网站检测到广告块的典型标志:
(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上的行为很奇怪。
控制台中的输出为:
正在加载
测试设置文档.body…
检测到恶意活动
不要试图欺骗我的广告块!
因此用户脚本成功加载,setter也成功挂接。但当加载后,我在控制台中尝试:
document.body.innerHTML = ""
它只是设置innerHTML
而没有抛出错误,就好像钩子还没有安装一样。我已经尝试了所有的@run-at
选项,但都不起作用。
OTAH,如果我在控制台中使用Object.defineProperty()
,那么它可以按预期工作。因此,我得出结论,Firefox不尊重用户脚本中的Object.defineProperty()
。
您也可以尝试访问此网站:https://connectwww.com.通过在Chrome中的Tampermonkey中安装上述用户脚本,成功拦截了网站上的广告块检测。但是用户脚本在Firefox+Greasemonkey上不起作用。
为什么Firefox不尊重用户脚本中的Object.defineProperty()
?有什么变通办法吗
旁注:
一些知名的用户脚本,比如反广告块杀手,也适用于Chrome,但不适用于Firefox,我想这也是出于同样的原因。
Greasemonkey4即使在@grant none
模式下也会对脚本进行沙盒处理(这是Greasemonkey4比Tampermonkey或Violentmonkey做得更好的唯一一件事。)
因此,您的脚本正在设置innerHTML
的脚本范围/副本
在Tampermonkey中,它与目标页面作用域共享,但在Greasemonkey中这两个作用域被更恰当地分离。因此,页面作用域(和默认控制台)没有看到更改。
在这种情况下,我认为unsafeWindow
方法无法工作必须注入覆盖代码。
这是一个同时适用于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);
}