javascript - 函数如何通过 [[FunctionLocation]] 到达外部脚本?

标签 javascript httprequest prototype-chain

我有一些代码使用 google api 在屏幕上显示共享对话框。 (这个:https://developers.google.com/drive/api/v3/share-button)

   share_client = new gapi.drive.share.ShareClient()
   share_client.showSettingsDialog()

但是在调用 showSettingsDialog 后,它失败并返回 403。我可以在网络选项卡中看到该请求: failed request

我知道它失败的原因,并且我相信如果我可以为此请求添加一个额外的参数,我就可以解决这个问题。问题是我无法使用 Service Worker 之类的东西来拦截和更改请求,因为该请求实际上是从 apis.google.com 的脚本发起的,而不是从我的页面位置发起的,所以我无权访问与 Service Worker 一起完成。如果可能的话,修改这个 api 代码来发出我想要的请求也是非常困难的。我已经尝试了很多。

如果我检查该 share_client 对象,我可以看到它从我可以控制的代码转移到外部资源的点。这是因为被调用的函数有这个 [[FunctionLocation]],它指向:https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi。 .../cb=gapi.loaded_2。如果我进入调试器,我可以看到它从这个函数调用跳转到 API 的本地副本,再跳转到 apis.google.com 中托管的外部脚本

enter image description here

所以我的问题是它到底是如何工作的?函数如何指向外部脚本?这个[[FunctionLocation]]来自哪里?它是如何生成的?可以改变吗?它如何在不实际发出 http 请求的情况下到达此外部代码?

基本上,我想了解这一切如何结合在一起。我不太相信实际上可以像我想要的那样向该请求添加参数,但此时我主要只是想了解更多信息。

最佳答案

在进行一些逆向工程时,我们可以在 https://apis.google.com/js/api.js JavaScript 代码中看到这一点:

var W = decodeURI("%73cript");

这相当于:

var W = "script";

原因可能是提供某种混淆来防止我们对代码进行逆向工程,但这还不足以阻止我们!

然后,就有了这个函数:

va = function (a) {
    var b = v.createElement(W);
    b.setAttribute("src", Y ? Y.createScriptURL(a) : a);
    a = ua();
    null !== a && b.setAttribute("nonce", a);
    b.async = "true";
    (a = v.getElementsByTagName(W)[0]) ? a.parentNode.insertBefore(b, a) : (v.head || v.body || v.documentElement).appendChild(b)
}

这是一种非常常见的动态添加脚本到页面的方法(使用给定的 src 创建一个 script 元素,然后将其添加到 DOM)。

这就是https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.fr.VPdiypayOnU.O/m=drive_share/rt= j/sv=1/d=1/ed=1/am=wQc/rs=AGLTcCPUjzWofrE8wWhx40v1IW1jnz4lrQ/cb=gapi.loaded_0 脚本正在加载。

在此脚本的末尾,我们可以看到:

lU.prototype.E2 = function() {
    this.Ds.Gh("settings")
}
;
_.z("gapi.drive.share.ShareClient", lU);
lU.prototype.setItemIds = lU.prototype.HE;
lU.prototype.setOAuthToken = lU.prototype.KE;
lU.prototype.showSettingsDialog = lU.prototype.E2;

这是将 showSettingsDialog 分配给 ShareClient.prototype 的地方。您可以轻松地将其替换为您自己的函数,但这对您没有帮助,因为您要修改的函数是其他函数(由 this.Ds.Gh("settings") 间接调用)。

不幸的是,我强烈怀疑您是否可以修改该底层函数,因为所有内容都包含在回调中:gapi.loaded_0(function(_) {...,并且是唯一可以从外部获得的东西由于以下代码,此回调是 ShareClient:

_.q = this || self; // contains window during execution
_.z = function(a, b) {
    a = a.split(".");
    var c = _.q;
    a[0]in c || "undefined" == typeof c.execScript || c.execScript("var " + a[0]);
    for (var d; a.length && (d = a.shift()); )
        a.length || void 0 === b ? c = c[d] && c[d] !== Object.prototype[d] ? c[d] : c[d] = {} : c[d] = b
}

这段代码的作用就像一个polyfill,它改变全局gapi对象并将ShareClient分配给gapi.drive.share,其他一切都是在匿名回调内部对外界隐藏,防止您对其进行修改。

但是,没有什么可以阻止您使用 Service Worker 作为此请求的代理。无论发起请求是什么,无论目标域是什么,Service Worker 都会工作。您无法使用 Service Worker 的唯一情况是拦截 iframe 请求,因为 iframe 被视为单独的页面,但您的情况下没有(该请求由当前页面加载的脚本发起)。

关于javascript - 函数如何通过 [[FunctionLocation]] 到达外部脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63185392/

相关文章:

javascript - 动态选项卡 - 加载多个子项 PER 选项卡

javascript - 带条形码生成器的动态网格 ANGULAR

安卓网络请求

java - 如何读取超时的HttpServletRequest数据?

javascript - 表单中的手机字段

javascript - 尝试使用 PHP/Laravel 实现 Disqus SSO 时,无法设置未定义的属性 'remote_auth_s3'

http - 发送 HTTP 请求

javascript - PrimeNG p-table header 选择所有具有延迟加载和分页的持久性

javascript - 组合 javascript 原型(prototype)样式

javascript - 拦截对构造函数的调用