【问题标题】:Inject javascript code into anonymous function scope将javascript代码注入匿名函数范围
【发布时间】:2017-10-10 23:40:20
【问题描述】:

我有这种需要注入的脚本

! function(e) {
    function doSomething()
    {
    }
}

基本上,当我的代码通过 Function 对象调用时,我得到了对 doSomething 的引用,但我需要挂钩到 doSomething,所以我需要对 id 的原始引用。由于 doSomething 是在匿名函数中声明的,因此我无法使用它。问题是,我能否以某种方式将代码注入匿名函数、Greesemonkey 或任何其他工具的范围内。

【问题讨论】:

  • “注入”是什么意思?您是否正在尝试制作在某个页面上操作 JS 的用户脚本/浏览器扩展?是的,你可以用它做任何你想做的事情,但你不能仅仅通过引用它来改变doSomething
  • 是的,我正在编写一个用户脚本,并想挂钩网页上的一些功能。为此,我需要更改对匿名函数范围内的函数的原始引用。
  • 最好的办法是拦截脚本加载,更改其源代码并对其进行评估。
  • 这听起来是个不错的解决方案。我该怎么做?
  • 不知道,这取决于浏览器和使用的确切技术。我只记得the old Opera had a BeforeScript event 正是为了这个用途。

标签: javascript anonymous-function javascript-injection


【解决方案1】:

Javascript 并不容易从范围内获取值。

您可以在更广泛的范围内声明doSomething

function doSomething() {
    // ...
}
function func(e) {
    doSomething(); // This works! `func` has a reference to `doSomething`
}

doSomething(); // This also works! `doSomething` is declared in this scope.

您还可以从内部范围返回值!例如:

function func(e) {
    function doSomething() {
        // ...
    }

    // Note that we are not invoking `doSomething`, we are only returning a reference to it.
    return doSomething; 
}

var doSomething = func(/* some value */);

// Now you got the reference!
doSomething();

有时您的外部函数已经需要返回另一个值:

function func(e) {
    function doSomething() { /* ... */ }
    return 'important value!!';
}

在这种情况下,我们仍然可以返回 doSomething,以及原始值:

function func(e) {
    function doSomething() { /* ... */ }
    return {
        value: 'important value',
        doSomething: doSomething
    };
}

var funcResult = func(/* some value */);
var originalValue = funcResult.value;
var doSomething = funcResult.doSomething;

// Now we have the original value, AND we have access to `doSomething`:
doSomething(); // This works

【讨论】:

  • 好吧,我需要挂钩到该范围内的函数,这意味着我仍然需要修改对该函数的原始引用,因为它被该范围内的多个其他函数调用。如果我用一个全局函数覆盖它,我只会实现所有现在调用我的函数,但我仍然需要调用我需要挂钩的原始函数。
  • 我列出的其他方法呢?只需在返回值中包含doSomething
  • 我无权访问任何东西 :) 这只是一个网站,将其脚本部署在一个巨大的匿名函数中。我正在尝试为它编写一个用户脚本。
  • 我不确定我还能在原始问题中添加什么。该页面有一个脚本,该脚本包含在匿名函数中。我想编写一个用户脚本,一旦加载,它将向页面添加功能。我需要做的一件事是挂钩隐藏范围内的函数,因为我需要对该函数的原始引用,所以我可以用我自己的替换它,但它无法访问。我还应该在问题描述中添加什么内容?
  • 怎么样?该范围内有一些函数使用我要挂钩的函数,我需要所有这些函数开始调用我的实现。在我的实现中,我做我需要的,然后调用原始函数。
【解决方案2】:

嘿,伙计,我在谷歌搜索后看到你的问题,因为我对同样的主题感兴趣,我有点沮丧,其他人似乎不明白你在问什么......但在想了想,我居然提出了一个解决方案!

首先,如果您要编写 chrome 扩展,我将向您展示如何做到这一点,这将是保证我们拦截脚本源的最简单方法,但也有一种方法可以在不制作扩展的情况下做到这一点,请参见下文。

基本上,假设您有一些要为其编写插件的网站,其中包含一些 HTML 内容,例如:

<script src="http://www.someURL.com/someFile.js"></script>

文件 someFile.js 的内容如下:

(function() {
    function cantGetMeMethod() {

    }
})();

因此,用户在执行 HTML 的主页上无法获取函数“cantGetMeMethod”。

问题是,如果我们能够简单地更改该 JavaScript 文件的源代码,我们可以轻松移除匿名函数包装,或者在底部插入某种全局变量引用。

但是我们怎么可能从客户端更改 JavaScript 源代码呢?

这就是 chrome 扩展的用武之地。使用扩展,可以将在页面加载之前在网站上任何地方发出的 HTTP 请求重定向到另一个网站。因此,例如,如果一个页面有这样的图像:

<img src="http://example.com/somePic.png"></img>

该扩展程序可以将来自 example.com 的所有请求重定向到另一个网站,因此显示的真实图像(使用扩展程序的客户端)实际上可能来自其他网站,并且是完全不同的图像!

这与 JavaScript 有什么关系?

因为同样的原理也适用于 JavaScript 源代码。我们所要做的就是找到对其他文件的 JavaScript 引用,并使用扩展名将 src URL 重定向到我们自己的服务器,并将原始 src URL 作为获取参数。假设我们有一些 nodeJS 站点或托管在 http://www.myAwesomeNodeJSserverOrSomething.com 的东西,所以我们将所有对 http://www.someURL.com/someFile.js 的调用(或至少相关的脚本调用)重定向到 http://www.myAwesomeNodeJSserverOrSomething.com/http://www.someURL.com/someFile.js

然后在 nodeJS 端执行如下操作:

require("http")
.createServer((q,r) => {
    http.get(q.url.slice(1), req => {
        let str = "";
        req.on("data", d => str += d.toString())
        req.on("end", () => {
            let newCode = someFunctionThatModifiesCode(str);
            r.end(newCode);
        });
    }); //pseudocode obviously, check for errors etc. for real
}).listen(8080);

现在页面已经修改了 JavaScript 代码!那么我们如何制作一个重定向标题的快速扩展呢?首先,创建一个新目录,并在其中创建一个名为 manifest.json 的文件,如下所示:

{
    "name":"JavaScript cracking the codes",
    "version":"1.0",
    "description":"hi",
    "manifest_version":2,
    "permissions": [
        "webRequest",
        "webRequestBlocking",
        "<all_urls>"
    ],
    "background": {
        "scripts":["lol.js"],
        "persistent": true
    }
}

现在在同一目录中创建一个新文件“lol.js”,并在其中放入如下内容:

let otherServer = "http://www.myAwesomeNodeJSserverOrSomething.com",
    urlsToRedirect = [ //list of javascript files that need fine tuning
        "http://www.someURL.com/someFile.js",
        "http://www.someURL.com/someFile2.js",
        "http://www.someURL.com/someFile3.js",
    ];
chrome.webRequest.onBeforeRequest.addListener(
    details => {
        if(
            urlsToRedirect.includes(
                details
                .url
            )
        ) {
            {
                redirectUrl: (
                    otherServer 
                    + "/"
                    + details.url
                )
            }
        }
    },
    {urls: ["<all_urls>"]},
    ["blocking"]
);

(警告:未经测试的代码)

然后进入chrome设置,进入开发者模式,加载一个新的扩展,然后选择那个文件夹。

此外,如果您自己只是这样做,那么在没有扩展的情况下执行此操作的方法是在页面加载之前注入一个mutationobserver 脚本,类似于篡改猴子。有关更多信息,请参阅 https://github.com/CertainPerformance/Stack-Exchange-Userscripts/blob/master/obsolete/Experiment-Off/StackExperimentOff.user.js https://stackoverflow.com/a/59424277/2016831 让我知道这是否可以解决您的问题。

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多