脚本体验师001 发表于 2021-10-7 20:02:58

这还真有意思,似乎那些小概率的页面空白损坏啥的有了解释

cxxjackie 发表于 2021-10-8 20:50:48

李恒道 发表于 2021-10-7 16:39
还是不太理解这种操作。
想不通为什么要这样做
等以后有机会再看看吧...


我又仔细地跟了一下油猴和腾讯文档的代码,最终确定问题了,不是window指向的问题,而是油猴本身会对document.addEventListener进行劫持(可以随便打开一个页面,控制台输出document.addEventListener看看),而原有的函数存储于document.__addEventListener中,劫持操作完后调用这个__addEventListener进行绑定。这个函数的存储时机就在第一次读取document的时候(用Object.defineProperty实现的),而腾讯文档对addEventListener的劫持是在document-start之后,这就导致了油猴存储到的函数实际上是页面的原函数,等于破坏了腾讯文档对document的劫持,腾讯文档的劫持就是把所有事件都委托给一个函数处理(我怀疑单纯是为了反调试),油猴这波操作以后造成绑定在document上的原事件被暴露,不过腾讯文档劫持的是EventTarget,除了document的都没事,如果把EventTarget.prototype.addEventListener改成只读,甚至可以暴露出更多事件。

李恒道 发表于 2021-10-8 20:58:29

cxxjackie 发表于 2021-10-8 20:50
我又仔细地跟了一下油猴和腾讯文档的代码,最终确定问题了,不是window指向的问题,而是油猴本身会对docu ...

有点复杂,大概有一点感觉了,等我明天仔细研究一下哥哥!

李恒道 发表于 2021-10-8 21:50:29

cxxjackie 发表于 2021-10-8 20:50
我又仔细地跟了一下油猴和腾讯文档的代码,最终确定问题了,不是window指向的问题,而是油猴本身会对docu ...
看了大佬的话又研究了一下....
我他妈还是不太懂这个问题。
目前知道只有沙盒模式油猴会包装document.addEventListener
但是我这里没看到document.__addEventListener

还有一个问题就是
我不知道我理解的对不对

正常网页是
函数调用addeventlistener。

腾讯文档的操作是
劫持addeventlistener

函数调用addeventlistener
虚假的addeventlistener做了一层包裹调用真实addeventlistener
这时候真实addeventlistener发起注册

但是这时候腾讯文档调用addEventListener的回调事件应该是包裹函数啊,包裹函数再调用原函数
为什么会暴露出包裹前的调用我一直不怎么理解
有点笨...我卡这个很久了

cxxjackie 发表于 2021-10-8 22:26:21

李恒道 发表于 2021-10-8 21:50
看了大佬的话又研究了一下....
我他妈还是不太懂这个问题。
目前知道只有沙盒模式油猴会包装document.addE ...

跟他的事件委托机制有关,首先他绑事件都是直接addEventListener传递真实事件的,劫持addEventListener所做的操作就是把真实事件包装成一个通用的函数,然后再调用原addEventListener绑定,最后看到的效果就是所有事件都指向那个通用函数。而油猴也劫持了addEventListener,所做的就是保存原函数-劫持处理-调用原函数。在正常情况下,腾讯文档的劫持先于油猴,所以油猴保存到的原函数是被腾讯文档劫持过的,而document-start访问document会导致油猴先于腾讯文档劫持,此时保存的原函数就是没有被劫持的。之后页面中的js调用document.addEventListener的时候,会进入油猴的逻辑,传进来的是真实事件,再用真实的addEventListener绑定,就出现了这种歪打正着的效果。

李恒道 发表于 2021-10-8 22:52:12

cxxjackie 发表于 2021-10-8 22:26
跟他的事件委托机制有关,首先他绑事件都是直接addEventListener传递真实事件的,劫持addEventListener所 ...

我就是这里不懂
按我的想法是

腾讯文档是
调用addeventlistener
包装addeventlistener
真实addeventlistener

油猴提前注入就变成了

调用addeventlistener
包装addeventlistener
油猴addeventlistener
真实addeventlistener

按道理油猴拿到的依然是包装的呀...

李恒道 发表于 2021-10-8 22:52:42

cxxjackie 发表于 2021-10-8 22:26
跟他的事件委托机制有关,首先他绑事件都是直接addEventListener传递真实事件的,劫持addEventListener所 ...
{:4_105:}抱歉,大佬,我太笨了...
就是他妈理解不了这,唉

cxxjackie 发表于 2021-10-8 23:16:31

李恒道 发表于 2021-10-8 22:52
我就是这里不懂
按我的想法是



我这样说明吧,假设原来的叫addEventListener,腾讯文档劫持的叫TaddEventListener,油猴劫持的叫YaddEventListener,页面中调用addEventListener的写法是XXX.addEventListener('copy', 原函数, ...args),注意这里无论什么情况都是传入原函数的。
腾讯文档所做的:addEventListener.call(this, 'copy', 包装函数(原函数), ...args);
油猴所做的:__addEventListener = document.addEventListener;
document.addEventListener = function() {
//...
return __addEventListener.apply(this, arguments);
}
正常情况下,__addEventListener等于TaddEventListener,虽然油猴取得的是原函数,但他调用了__addEventListener后原函数就被包装了。提前劫持的情况下,__addEventListener等于addEventListener,此时调用__addEventListener是直接将原函数绑定在原addEventListener上。

李恒道 发表于 2021-10-8 23:20:23

cxxjackie 发表于 2021-10-8 22:26
跟他的事件委托机制有关,首先他绑事件都是直接addEventListener传递真实事件的,劫持addEventListener所 ...
我调了一下
感觉像是如果劫持过
腾讯文档就不会再进行劫持了
这里是进行处理劫持的地方
如果挂载了油猴会有一次Event的劫持
如果不挂载会有两次的Event的劫持初始化
不挂载的话会在第二次进行劫持addeventlistener
                            function e(t) {
                              var e = P && P.prototype;
                              e && e.hasOwnProperty && e.hasOwnProperty("addEventListener") && (k(e, "addEventListener", (function(e) {
                                    return function(r, i, a, u) {
                                        try {
                                          i && i.handleEvent && (i.handleEvent = n.wrap(i.handleEvent))
                                        } catch (t) {}
                                        var c, s, f;
                                        return o && o.dom && ("EventTarget" === t || "Node" === t) && (s = n.S("click"),
                                        f = n.U(),
                                        c = function(t) {
                                          if (t) {
                                                var e;
                                                try {
                                                    e = t.type
                                                } catch (t) {
                                                    return
                                                }
                                                return "click" === e ? s(t) : "keypress" === e ? f(t) : void 0
                                          }
                                        }
                                        ),
                                        e.call(this, r, n.wrap(i, void 0, c), a, u)
                                    }
                              }
                              ), r),
                              k(e, "removeEventListener", (function(t) {
                                    return function(e, n, r, o) {
                                        try {
                                          n = n && (n.K ? n.K : n)
                                        } catch (t) {}
                                        return t.call(this, e, n, r, o)
                                    }
                              }
                              ), r))
                            }

李恒道 发表于 2021-10-8 23:21:50

cxxjackie 发表于 2021-10-8 23:16
我这样说明吧,假设原来的叫addEventListener,腾讯文档劫持的叫TaddEventListener,油猴劫持的叫YaddEve ...

基本懂了!
哥哥牛逼!
页: 1 2 [3] 4
查看完整版本: [逆向分析实战]三句话,让腾讯文档为我放下戒备