JS 有什么手段可以判断一个函数是不是原生代码吗?

2021-05-08 16:22:07 +08:00
 xieqiqiang00

比如 XMLHttpRequest,有没有什么手段可以知道这个东西有没有被人为重写?
网站找了不少方法都做不到
下面是我做的一些尝试,这些检测方法都能被绕过

{
    function isNative(api) {
        return /native code/.test(api.toString()) && typeof api !== 'undefined'
    }

    let test = function (input, fake) {
        console.log("------------------------")
        console.log("是否是伪造:", fake)
        console.log("toString:", input.toString())
        console.log("toString.toString:", input.toString)
        console.log("prototype 方法", input.hasOwnProperty("prototype"))
        console.log("toString.call","方法",Function.prototype.toString.call(input))
        console.log("网传最不靠谱方法:isNative", isNative(input))
    }
    test(XMLHttpRequest, false)
    {
        let XMLHttpRequest = function () {
            "[native code]"
        }
        XMLHttpRequest.toString = function () {
            return "function XMLHttpRequest() { [native code] }"
        }
        let toString = function () {
            return "function toString() { [native code] }"
        }
        toString.toString = toString
        XMLHttpRequest.toString.toString = toString
        Function.prototype.toString = toString
        delete XMLHttpRequest.prototype
        test(XMLHttpRequest, true)
        // XMLHttpRequest.prototype = undefined
        // test(XMLHttpRequest, true)
    }
}
5838 次点击
所在节点    JavaScript
80 条回复
luofeii
2021-05-08 18:38:55 +08:00
@BoringTu 正是因为它俩不等于,所以 window.XMLHttpRequest 无论做任何更改,iframe.contentWindow.XMLHttpRequest 对象还是原生的
xiangwan
2021-05-08 18:39:54 +08:00
直接不用 XMLHttpRequest 。用其他语言的 http client 编译成 wasm 调用。
gamexg
2021-05-08 18:44:16 +08:00
@BoringTu #38

以前实现过 js 的浏览器伪装,iframe 也会被处理。
记不清具体细节,印象是 createElement 、getElementById 函数都替换为自己的函数。
浏览器插件来可以实现页面代码之前执行替换代码。

当时考虑过网站检测对抗,只能考虑寻找各个未处理好的细节。

楼主也许可以考虑故意用落后几个版本的 electron(或魔改版) ,然后去依赖老版本不支持的 js 新特征来检查。
例如,看似正常的功能,依赖新特征,浏览器不支持这个功能时 js 回退使用兼容实现。
但是应该故意让 electron 不支持这个特征,那个客户端支持就证明是破解版。
daysv
2021-05-08 18:46:50 +08:00
@xieqiqiang00
用这种绕开呢?
String.toString.call(XMLHttpRequest)
ochatokori
2021-05-08 18:53:05 +08:00
js 层面别费劲了,不管怎么绕都只能过滤一些通用 hook 工具,针对你的程序的话你没办法
就算是 native 层也不是不可能的
KuroNekoFan
2021-05-08 18:55:24 +08:00
这种问题跟“如何避免 https 抓包”是一个性质的吧
ochatokori
2021-05-08 18:56:10 +08:00
@daysv #44 直接重写 String.toString.call
no1xsyzy
2021-05-08 19:48:55 +08:00
如果替换方法是 js,其实是可以用 js 检测的,之前 V2 上面有人做过不记得是 JS 还是 Python 的思考题的,如何判断一个对象是不是 Proxy
hint:递归
但如果对面直接掉替换你的 V8 那也是白搭。
xieqiqiang00
2021-05-08 20:58:07 +08:00
@no1xsyzy 这还能找到传送门吗?
@KuroNekoFan 搞证书绑定的话就可以极大程度上避免被抓包了吧,抬高破解成本
ychost
2021-05-08 21:16:43 +08:00
很难防御,之前用类似的方式破过很多竞赛网站,比如 10fastfingers.com 之类的,前端没法防御只能通过服务端来校验提交有没有异常
rekulas
2021-05-08 21:28:14 +08:00
抛砖引玉
```
   var iframe = document.createElement('iframe')
   document.body.appendChild(iframe)
   XMLHttpRequest === iframe.contentWindow.XMLHttpRequest // true or false?
```
no1xsyzy
2021-05-08 21:28:43 +08:00
@xieqiqiang00 我尝试找了一下,但没找到……
假设一个期望中调用层数为 k 的待测函数
就是去撞递归最大层数
撞到了退回来 k-1 层,调用待测的函数 f,应当调用失败( InternalError: too much recursion )
再多退一层到 k 层,调用待测函数 f,应当调用成功
但是似乎最近浏览器都随机化了最大调用层(防 fingerprinting 吧),不确定 Electron 如何。
(其实最方便的、最坚固的可能是干脆换 Qt 商业授权)
musi
2021-05-08 21:51:59 +08:00
@rekulas 这不是 false 么,因为都不在一个 realm 或者说浏览器上下文里

@luofeii 这位大佬的意识是不需要判断是否是原生的代码,直接用 iframe 里的函数,因为每次创建 iframe 的时候,iframe 自己的浏览器上下文是重新创建的,基本上都能得到原生的代码
JerryCha
2021-05-08 22:26:52 +08:00
那你不如直接用 C++写个 addon 专门负责网络请求
learningman
2021-05-09 00:29:06 +08:00
js 预编译不好使的,建议 wasm
jones2000
2021-05-09 00:51:59 +08:00
直接后台渲染, 不就行了。 后台生成静态页面,显示。什么 js 都没有。
aaronlam
2021-05-09 01:43:22 +08:00
@musi 我试过貌似直接用 iframe 里的 XMLHttpRequest 发送请求是可行的
binux
2021-05-09 03:08:57 +08:00
@BoringTu
> 在 HTML head 标签里所有 script 标签的最前面加上一个 script
这一条做不到
musi
2021-05-09 06:25:29 +08:00
@aaronlam 本来就是可行的,现在微前端里的沙箱基本都离不开 iframe,比如比较流行的 qiankun 框架,比如阿里云的 console os,都是拿 iframe 来做的沙箱隔离,因为目前的 realm api 还在草案阶段
rekulas
2021-05-09 09:08:27 +08:00
@musi 正常是可以判断的,你可以运行下

不过...
@luofeii @BoringTu
正如 @gamexg 提到的,iframe 仍然不完美,客户端仍然能进行攻击,举个栗子
```
document.createElement = () => {
return {contentWindow: {XMLHttpRequest: XMLHttpRequest}}
};
document.body.appendChild = () => {};
var iframe = document.createElement('iframe')
document.body.appendChild(iframe)
console.log(XMLHttpRequest === iframe.contentWindow.XMLHttpRequest)
```
最后判断始终是 true,除非你继续证明 document.createElement 也是原生,这。。。俄罗斯套娃
我觉得可以考虑从某些无法被覆盖的对象入手,例如 navigator 之类

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/775677

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX