如何在用户脚本中创建与评估函数的钩子

How can I create a hook to eval functions in userscript

本文关键字:函数 评估 创建 用户 脚本      更新时间:2023-09-26

我想计算用于动态解释的函数调用次数JavaScript代码(例如,evalsetTimeout)。我的主要目的是找到作为参数传递给 eval 和 setTimeout 的字符串。这是因为恶意脚本使用 eval 函数动态评估复杂代码是很常见的。找到这一点的一种方法是挂接函数,以便可以触发对 eval 函数的每次调用。但我不确定该怎么做。请用一个例子来解释这一点。

我正常尝试了设置超时,但我没有得到正确的结果。

我的代码如下

var sto = setTimeout; setTimeout = function setTimeout(str){
console.log(str);
}

我的实际用户脚本是:

// ==UserScript==
// @encoding    UTF-8 
// @name        Count_setTimeout
// @run-at      document-start
// ==/UserScript==
addJS_Node("var count=0;");
function Log_StimeoutCreations ()
{
  var sto = setTimeout;
  setTimeout = function(arg, time) 
  {
     if(typeof arg == "string")
        console.log("Insecure setTimeout: ", arg);
     else
        console.log("setTimeout:",arg);   
     count++;
     sto(arg, time);    
  }
}
var waitForDomInterval = setInterval (
function () {
    var domPresentNode;
    if (typeof document.head == "undefined")
        domPresentNode = document.querySelector ("head, body");
    else
        domPresentNode = document.head;
    if (domPresentNode) {
        clearInterval (waitForDomInterval);
        addJS_Node (null, null, Log_StimeoutCreations);           
    }
},
1
);
function addJS_Node (text, s_URL, funcToRun) {
var D                                   = document;
var scriptNode                          = D.createElement ('script');
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);
}
addJS_Node("document.onreadystatechange = function (){if (document.readyState == 'complete'){if(typeof(unsafeWindow)=='undefined') { unsafeWindow=window; } unsafeWindow.console.log('count--'+count);}}");

但我什至没有在源代码中查看 setTimeout 函数。我如何实现这一点 此外,通过这将获得内在的评估功能,即eval(eval());

你基本上做对了。 这是我的代码:

var sto = setTimeout;
setTimeout = function(arg, time) {
    if(typeof arg == "string")
        console.warn("Insecure setTimeout: ", arg);
    // call real setTimeout
    sto(arg, time);
}
// ...now all future setTimeout calls will warn about string use...
setTimeout("alert(1);", 1000);

如果你想对它保持超级正确,并且不将sto留在允许访问原始setTimeout的全局命名空间中,请使用闭包:

(function() {
    var sto = setTimeout;
    setTimeout = function(arg, time) {
        if(typeof arg == "string")
            console.warn("Insecure setTimeout!", arg);
        sto(arg, time);
    }
})();

这样,真正的setTimeout是完全无法访问的,因为一旦匿名函数结束,sto就无法访问,除非在新的setTimeout包装器中。