将 javascript 注入 javascript 函数

发布于 2024-08-19 01:30:44 字数 386 浏览 4 评论 0原文

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

我得到的是这样的东西

function doSomething(){ ... }

...***

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

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

有办法做到这一点吗?

I've got a weird question in that I need to inject some javascript into another javascript function. I am using a framework which is locked so I can not change the existing function.

What I've got is something like this

function doSomething(){
...
}

...***

I can manipulate the ***(above) however I can not change the doSomething function... Instead I need to somehow inject a few lines of code into the end of the doSomething code.

The reason I need to do this is that the custom framework calls doSomething() and this results in an ID being returned from the server that I need to extract. This ID is only referenced inside the doSomething function so I can not catch it unless I inject code to that function (unless I've missed something).

Is there a way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

兔姬 2024-08-26 01:30:44

别名它。

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

Alias it.

var oldDoSomething = doSomething;
doSomething = function() {
  // Do what you need to do.
  return oldDoSomething.apply(oldDoSomething, arguments);
}
屋檐 2024-08-26 01:30:44

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

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

现在 doSomething 返回 ID。我通常不喜欢 eval,而是普通的面向方面的编程由于需要访问局部变量, 技术在这里不适用。

如果 doSomething 已经返回了一个值,请尝试将主体包装在 try ...finally 中:

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

要将其转换为函数,我们需要编写代码 在全球范围内进行评估。最初,这个答案使用 with 来更改 eval 的范围,但这目前在浏览器中不起作用。相反,.call 用于将 eval 的范围更改为 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, '
amp; ' + code, begin);
    };
    
    window.after = function (func, code) {
        return insertCode(func, code + ' 
amp;', 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, '
amp; ' + pre)
                .replace(end, post + ' 
amp;');
        });
    };
})();
...
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;');

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

替代方法

不改变 doSomething ,而是可以包装它调用的函数,这些函数提供 doSomething 用于生成 ID 的数据(或者,一般来说,无论要捕获什么数据)。有一些警告:

  • 被调用的函数只有在全局范围内才能被包装,或者可以注入代码在定义的范围内运行。
  • 包装该函数将影响使用该函数的所有代码,而不仅仅是 doSomething,这可能会引入错误。
  • 如果被调用的函数不直接返回感兴趣的数据,而是 doSomething 必须处理结果,则包装器必须重复此处理(这违反了 DRY 原则)。如果处理量很小,这不会是一个大问题,但仍然是潜在的错误来源(特别是,如果 doSomething 中的处理发生更改,但代码可能会不同步包装器不是)。

Altering the function by working with the source code strings can be quite simple. To do it for a specific instance, try:

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

Now doSomething returns the ID. I'm not normally a fan of eval, but normal aspect oriented programming techniques don't apply here, due to the requirement for accessing a local variable.

If doSomething already returns a value, try wrapping the body in a try ... finally:

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

To turn this into a function, we need to make the code evaluate in global scope. Originally, this answer made use of with to change the scope of the eval, but this doesn't currently work in browsers. Instead, .call is used to change the scope of eval to 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, '
amp; ' + code, begin);
    };
    
    window.after = function (func, code) {
        return insertCode(func, code + ' 
amp;', 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, '
amp; ' + pre)
                .replace(end, post + ' 
amp;');
        });
    };
})();
...
after(doSomething, 'return id;');
/* or */
around(doSomething, 'try {', '} finally { window.someID = id; }');

If you want to rewrite methods and anonymous functions bound to variables, change alter to:

...
    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;');

Note the first argument to the functions are now strings. Further improvements could be made to handle methods that aren't accessible in global scope.

Alternate approach

Instead of altering doSomething, it might be possible to wrap around the function/-s that it calls which provide the data that doSomething uses to generate the ID (or, in general, whatever data is to be captured). There are some caveats:

  • The called function can only be wrapped if it is in global scope, or code can be injected & run in the scope where it's defined.
  • Wrapping the function will affect all code that uses it, not just doSomething, which may introduce bugs.
  • If the called function doesn't return the data of interest directly but rather doSomething must process the result, then the wrapper must duplicate this processing (which violates the DRY principle). If the processing is minimal, this won't be a large issue, but is still a potential source of bugs (in particular, the code can get out of sync if the processing in doSomething is changed but the wrapper isn't).
骄兵必败 2024-08-26 01:30:44

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

<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" />

Thanks for all your feedback. Each answer gave me a clue and as such I've come up with the following solution.

<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" />

我的鱼塘能养鲲 2024-08-26 01:30:44

我不确定你所说的“锁定”是什么意思 - 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;

I'm not sure what you mean by "locked" - JavaScript is interpreted by your browser. Even if it has been minified or encoded, you can still copy the source of that function from source of the page of script. At that point, you reassign the original function to one of your own design, which contains the copied code plus your own.

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;
无敌元气妹 2024-08-26 01:30:44
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();

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

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

This seems to provoke an error (Too much recursion)

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();

This works for me, even if it is ugly.

打小就很酷 2024-08-26 01:30:44

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

你应该能够做这样的事情:(

function doSomething() { ... }

var oldVersionOfFunc = doSomething;
doSomething = function() {

    var retVal = oldVersionOfFunc.apply(oldVersionOfFunc, args);

    // your added code here

    return retVal;
}

但是,我可能是错的。我的javascript有点生疏。;))

Functions are first class values in Javascript, which means that you can store them in variables (and in fact, declaring a named function is essentially assigning an anonymous function to a variable).

You should be able to do something like this:

function doSomething() { ... }

var oldVersionOfFunc = doSomething;
doSomething = function() {

    var retVal = oldVersionOfFunc.apply(oldVersionOfFunc, args);

    // your added code here

    return retVal;
}

(But, I could be wrong. My javascript's a little rusty. ;))

記憶穿過時間隧道 2024-08-26 01:30:44

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

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

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

I can not change the doSomething function... Instead I need to somehow inject a few lines of code into the end of the doSomething code

Injecting a few lines into the end of the doSomething code sounds like changing the doSomething function, to me. I think, unfortunately, that you’re screwed.

(I’m a bit hazy on all this, but I think functions are how people who worry about such things implement information hiding in JavaScript, precisely because you can’t access their scope from outside them.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文