javascript - 函数如何使用 [[FunctionLocation]] 访问外部脚本?
问题描述
我有一些代码正在使用 google api 在屏幕上显示共享对话框。(这个:https ://developers.google.com/drive/api/v3/share-button )
share_client = new gapi.drive.share.ShareClient()
share_client.showSettingsDialog()
但是在调用之后showSettingsDialog
,它会失败并显示 403。我可以在我的网络选项卡中看到该请求:
我知道它为什么会失败,并且我相信只要我能在这个请求中添加一个额外的参数,我就能解决这个问题。问题是我不能使用 Service Worker 之类的东西来拦截和更改请求,因为这个请求实际上是从 apis.google.com 的脚本发起的,而不是从我的页面位置发起的,所以我没有访问权限使用 Service Worker。如果可能的话,也很难修改这个 api 代码来发出我想要的请求。我试过了,很多。
如果我检查那个share_client
对象,我可以看到它从我可以控制的代码到外部资源的位置。这是因为被调用的函数有 this [[FunctionLocation]]
,它指向:https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi. ... /cb=gapi.loaded_2
。如果我进入调试器,我可以看到它从这个函数调用跳转到我的本地 API 副本,再到 apis.google.com 中托管的外部脚本
所以我的问题是这到底是如何工作的?函数如何指向外部脚本?这[[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)
}
这是将脚本动态添加到页面的一种非常常见的方法(script
使用给定的创建元素src
,然后将其添加到 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
请求,因为 aniframe
被视为单独的页面,但在您的情况下没有(请求由script
当前页面上加载的 a 发起)。
推荐阅读
- customization - 具有多个值的 Keycloak 用户属性(列表)
- javascript - 使用 React 构建类似 Google 日历的组件
- sql-server - 使用 select 创建列并根据条件向其中添加数据?
- python - 无法在 Python 中打印
- .net-core - 使用 AWS 本地配置文件进行开发的 AWS .NET Core Worker 服务正在尝试从实例配置文件访问 IAM 凭证?
- python - 围绕一个点绘制/绘制一个具有一定半径的圆(matplotlib)
- r - 绘制 R 中逻辑回归的“model.averaging”对象的交互
- pulumi - 如何使用 pulumi 为 aws fargate 设置容器端口和负载均衡器?
- typescript - 如何避免手动复制 TypeScript 接口中的类型文档
- python - 如何从两个父类调用“覆盖”方法?