cabin 发表于 2023-3-29 14:54:02

封装伪装isTrust点击,遇到得神奇的问题

事情是这样的:

之前在论坛看到有个网页点击大挑战,破解脚本触发click事件isTrust为false的问题

@cxxjackie 大佬提供思路利用劫持addEventListener,再用Proxy伪装

于是我尝试了下在实际项目里面封装并使用,但是遇到了一个让我匪夷所思的问题

```

const arrClickDoms = [];
const fakeClickEvent = {
isTrusted: true,
pointerType: "mouse",
};
const ael = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function () {
if (arguments === "click") {
    if (arrClickDoms.includes(this)) {
      const fn = arguments;
      arguments = (e) =>
      fn.call(
          this,
          new Proxy(e, {
            get: (target, property, receiver) =>
            property in fakeClickEvent
                ? fakeClickEvent
                : Reflect.get(target, property, receiver),
          })
      );
    }
}
return ael.apply(this, arguments);
};

//下一次点击事件 随机1-3秒
var nextClick = function (
selector,
{ minNum = 1000, maxNum = 3000 } = {}
) {
return new Promise((reslove, reject) => {
    setTimeout(async () => {
      try {
      const = await $.get(selector);
      if (!arrClickDoms.includes(btn)) {
            arrClickDoms.push(btn);
      }
      btn.click();
      arrClickDoms.splice(arrClickDoms.indexOf(btn), 1);
      reslove(btn);
      } catch (err) {
      reject(err);
      }
    }, cb_randomNum(minNum, maxNum));
});
};
```

正常来说,有以下几个步骤:
1先劫持 addEventListener ,
2调用nextClick 筛选btn元素,将其加入arrClickDoms数组
3 触发btn的click
4 进入劫持后的 addEddEventListener 回调方法 判断btn是否在arrClickDoms中,如果存在,则返回伪造Proxy,否则直接正常返回

如果是在小demo中,以上封装是没问题,
但是在实际复杂项目场景的时候,却遇到很奇怪的问题

在没有触发 第2步和第3步的时候,直接先执行了第1步和第4步, 再调用click的时候,却不进入 addEddEventListener 回调。

甚至不调用nextClick,也会执行第1步和第4步,

这是反扒机制还是啥的,感觉有点颠覆了我对js的理解机制

李恒道 发表于 2023-3-29 16:09:26

最好是提供具体的脚本和网站来进行测试
不然很难派查发生原因的

cabin 发表于 2023-3-29 16:32:41

本帖最后由 cabin 于 2023-3-29 19:39 编辑

李恒道 发表于 2023-3-29 16:09
最好是提供具体的脚本和网站来进行测试
不然很难派查发生原因的
基本所有的用vue框架生成的网站,都会 出现这种情况
这个应是涉及js底层的事件机制

我只是想象不出为啥会提前触发 addEventListener 的回调事件,
再次点击click 却不会触发 addEventListener 的回调,
但是会正常触发他自己的业务方法这太反常识了

我是想知道这种模式的理论可能在哪里

我猜测是 dom 事件机制的冒泡和capture 有影响,其他点击事件把劫持的 addEventListener 的回调事件 给提前执行了

或者有可能是业务点击按钮执行了 e.stopImmedatePropogration,导致事件中断

cabin 发表于 2023-3-29 19:38:20

本帖最后由 cabin 于 2023-3-29 20:07 编辑

好像是因为很多网站对addEventListener做了特殊处理,把回调 function给删了


const ael = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function () {
    console.log(arguments)
    return ael.apply(this, arguments);
};

这个是简单demo的arguments
https://wxay-product-pro.oss-cn-shanghai.aliyuncs.com/demo/1.png

这个是Vue项目的arguments,可以看到所有的第二个参数都被扣走了
https://wxay-product-pro.oss-cn-shanghai.aliyuncs.com/demo/2.png

应该是框架 vue或者react把 addEventListener 二次修改了,劫持addEventListener的思路估计仅限于demo

这种情况还怎么绕过isTrusted,源码是混淆后的,没法看懂

cxxjackie 发表于 2023-3-29 20:55:32

没太看懂你的描述,猜测是事件委托的问题,一些框架会将多个元素的事件委托到一个父级元素上,然后根据e.target判断实际触发的元素来调用对应函数。你说的先触发可能是捕获阶段的事件(useCapture: true),因为捕获先于冒泡,父级会比子级先收到事件,这种的应该把监听元素放到正确的父级上才行。
删掉回调的情况我没碰见过,这种可能专门针对性的做了反劫持,得从源码入手。如果真是二次劫持的情况,说明页面劫持发生在你脚本劫持之前,应确保脚本执行于document-start。
如果你是想做一个通用的库来过验证,建议还是放弃吧,实际情况千奇百怪,而且有很多方法来反制,要做到完全通用是不现实的。

cabin 发表于 2023-3-30 10:45:08

cxxjackie 发表于 2023-3-29 20:55
没太看懂你的描述,猜测是事件委托的问题,一些框架会将多个元素的事件委托到一个父级元素上,然后根据e.ta ...

是啊,我就是想按你以前发得那个思路封装库做全局伪装点击劫持,好像行不通,有一个原因应该就是我上面图发的,vue或者react框架层面会把 addEventListenner 二次修改,把arguments 事件回调方法直接删了,挂载到他们自己框架事件机制上,那劫持修改的回调事件自然也不会触发了,自然也谈不上返回伪装的proxy了

这种该怎么破解啊。。。。。。。。。。。。。。。{:4_115:}

cxxjackie 发表于 2023-3-30 21:31:32

cabin 发表于 2023-3-30 10:45
是啊,我就是想按你以前发得那个思路封装库做全局伪装点击劫持,好像行不通,有一个原因应该就是我上面图 ...

有没有测试链接?还有你代码是怎么写的?按理来说arguments应该是一个数组,但你图中展示的却是一个对象,这点很奇怪,被删掉的参数至少也应该显示为undefined才对,感觉像是代码的问题。
另外react框架有特殊的处理办法,可以直接定位到事件函数,不需要劫持addEventListener,在这篇文章里有提到:
https://bbs.tampermonkey.net.cn/thread-1250-1-1.html
页: [1]
查看完整版本: 封装伪装isTrust点击,遇到得神奇的问题