【问题标题】:Inject javascript into a javascript function将 javascript 注入到 javascript 函数中
【发布时间】:2011-01-07 17:09:30
【问题描述】:

我有一个奇怪的问题,我需要将一些 javascript 注入另一个 javascript 函数。我正在使用一个已锁定的框架,因此我无法更改现有功能。

我得到的是这样的

函数做某事(){ ... }

...***

我可以操纵 ***(上图)但是我不能更改 doSomething 函数...相反,我需要以某种方式将几行代码注入到 doSomething 代码的末尾。

我需要这样做的原因是自定义框架调用了 doSomething(),这会导致从服务器返回一个我需要提取的 ID。此 ID 仅在 doSomething 函数内部引用,因此除非我将代码注入该函数(除非我错过了某些内容),否则我无法捕获它。

有没有办法做到这一点?

【问题讨论】:

标签: javascript function code-injection


【解决方案1】:

通过使用源代码字符串来更改函数非常简单。要针对特定​​实例执行此操作,请尝试:

eval(doSomething.toString().replace(/}\s*$/, ' return id; $&'));

现在doSomething 返回 ID。我通常不是eval 的粉丝,但正常的aspect oriented programming 技术在这里并不适用,因为需要访问局部变量。

如果doSomething 已经返回一个值,请尝试将正文包裹在try ... finally 中:

eval(doSomething.toString()
    .replace(/^function *\w* *\([^)]*\) *{/, '$& try {')
    .replace(/}\s*$/, '} finally { window.someID = id; } $&')
);

要将其转换为函数,我们需要将代码设为evaluate in global scope。最初,此答案使用with 来更改eval 的范围,但这目前在浏览器中不起作用。而是使用.calleval 的范围更改为window

(function () {
    var begin = /^function\s*\w*\s*\([^)]*\)\s*{/,
        end = /}\s*$/;

    function alter(func, replacer) {
        var newFunc = replacer(func.toString());
        eval.call(window, newFunc);
    }

    function insertCode(func, replacer, pattern) {
        alter(func, function (source) { 
            return source.replace(pattern, replacer);
        });
    };

    /* Note: explicit `window` to mark these as globals */
    window.before = function (func, code) {
        return insertCode(func, '$& ' + code, begin);
    };

    window.after = function (func, code) {
        return insertCode(func, code + ' $&', end);
    };

    window.around = function (func, pre, post) {
        /* Can't simply call `before` and `after`, as a partial code insertion may produce a syntax error. */
        alter(func, function(source) {
            return source
                .replace(begin, '$& ' + pre)
                .replace(end, post + ' $&');
        });
    };
})();
...
after(doSomething, 'return id;');
/* or */
around(doSomething, 'try {', '} finally { window.someID = id; }');

如果要重写绑定到变量的方法和匿名函数,请将alter更改为:

...
    function alter(func, replacer) {
        var newFunc = replacer(eval('window.' + funcName).toString());
        eval.call(window, newFunc);
    }
...
function Foo() {}
Foo.prototype.bar = function () { var secret=0x09F91102; }
...
after('Foo.prototype.bar', 'return secret;');

请注意,函数的第一个参数现在是字符串。可以进一步改进以处理在全局范围内无法访问的方法。

【讨论】:

  • 这在一般情况下不起作用,因为该函数可以在任何时间提前执行返回,因此可能无法到达注入的代码。
  • @TonyO'Hagan:谢谢;现在应该通过使用try ... finally 来解决这个问题。
【解决方案2】:

感谢您的所有反馈。每个答案都给了我一个线索,因此我想出了以下解决方案。

<body>
<script type="text/javascript">
    var val;
    function doSomething(item1, item2) {
        var id = 3;
    }
    function merge() {
        var oScript = document.createElement("script");
        var oldDoSomething = doSomething.toString();
        oScript.language = "javascript";
        oScript.type = "text/javascript";
        var args = oldDoSomething.substring(oldDoSomething.indexOf("(") + 1, oldDoSomething.indexOf(")"));
        var scr = oldDoSomething.substring(oldDoSomething.indexOf("{") + 1, oldDoSomething.lastIndexOf("}") - 1);
        var newScript = "function doSomething(" + args + "){" + scr + " val = id; }";
        oScript.text = newScript;
        document.getElementsByTagName('BODY').item(0).appendChild(oScript);
    }

    merge();

</script>
<input type="button" onclick="doSomething();alert(val);" value="xx" />

【讨论】:

  • 更好的解决方案(不需要 DOM 操作,纯 Javascript):stackoverflow.com/a/9134757/39722
  • @BernhardHofmann 实际上并没有解决问题。问题是具体如何注射
【解决方案3】:

我不确定您所说的“锁定”是什么意思 - JavaScript 由您的浏览器解释。即使它已被缩小或编码,您仍然可以从脚本页面的源中复制该函数的源。此时,您将原始函数重新分配给您自己的设计,其中包含复制的代码和您自己的代码。

var id;
var myFunction = function() {
  // code copied from their source, which contains the variable needed

  // insert  your own code, such as for copying the needed value
  id = theirIDvalue;

  // return the value as originally designed by the function
  return theirValue;
};

theirObject.theirFunction = myFunction;

【讨论】:

    【解决方案4】:
    function doSomething() { ... }
    var oldVersionOfFunc = doSomething;
    doSomething = function() {
        var retVal = oldVersionOfFunc.apply(oldVersionOfFunc, args);
        // your added code here
        return retVal;
    }
    

    这似乎引发了错误(递归过多)

    function doSomething(){ document.write('Test'); return 45; } 
    var code = 'myDoSomething = ' + doSomething + '; function doSomething() { var id = myDoSomething(); document.write("Test 2"); return id; }';
    eval(code)
    doSomething();
    

    这对我有用,即使它很丑。

    【讨论】:

      【解决方案5】:

      我无法更改 doSomething 函数...相反,我需要在 doSomething 代码的末尾注入几行代码

      对我来说,在doSomething 代码的末尾注入几行代码听起来像是更改了doSomething 函数。不幸的是,我认为你被搞砸了。

      (我对这一切有点模糊,但我认为函数是担心这些事情的人如何在 JavaScript 中实现信息隐藏,正是因为你无法从它们外部访问它们的范围。)

      【讨论】:

        【解决方案6】:

        别名。

        var oldDoSomething = doSomething;
        doSomething = function() {
          // Do what you need to do.
          return oldDoSomething.apply(oldDoSomething, arguments);
        }
        

        【讨论】:

        • 他需要访问一个作用域为原始函数的变量
        • 错误答案。需要逐个使用。
        【解决方案7】:

        函数是 Javascript 中的第一类值,这意味着您可以将它们存储在变量中(实际上,声明一个命名函数本质上就是将一个匿名函数分配给一个变量)。

        你应该可以做这样的事情:

        function doSomething() { ... }
        
        var oldVersionOfFunc = doSomething;
        doSomething = function() {
        
            var retVal = oldVersionOfFunc.apply(oldVersionOfFunc, args);
        
            // your added code here
        
            return retVal;
        }
        

        (但是,我可能是错的。我的 javascript 有点生锈了。;))

        【讨论】:

        • 如果我的问题是正确的,这将无济于事,因为问题是提取仅在 doSomething 中引用的局部变量的值。而且新版doSomething不能引用旧版里面的变量。
        猜你喜欢
        • 2013-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-23
        • 2011-05-02
        • 2017-06-10
        • 1970-01-01
        • 2014-05-24
        相关资源
        最近更新 更多