上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖
楼主: cabin - 

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

[复制链接]
  • TA的每日心情
    慵懒
    2023-3-28 14:26
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    9

    主题

    30

    回帖

    42

    积分

    初级工程师

    积分
    42
    发表于 2023-3-29 14:54:02 | 显示全部楼层 | 阅读模式
    悬赏20油猫币未解决

    事情是这样的:

    之前在论坛看到有个网页点击大挑战,破解脚本触发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[0] === "click") {
        if (arrClickDoms.includes(this)) {
          const fn = arguments[1];
          arguments[1] = (e) =>
            fn.call(
              this,
              new Proxy(e, {
                get: (target, property, receiver) =>
                  property in fakeClickEvent
                    ? fakeClickEvent[property]
                    : 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 [btn] = 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的理解机制

  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5960

    回帖

    6759

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6759

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2023-3-29 16:09:26 | 显示全部楼层
    最好是提供具体的脚本和网站来进行测试
    不然很难派查发生原因的
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2023-3-28 14:26
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    9

    主题

    30

    回帖

    42

    积分

    初级工程师

    积分
    42
    发表于 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,导致事件中断
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2023-3-28 14:26
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    9

    主题

    30

    回帖

    42

    积分

    初级工程师

    积分
    42
    发表于 2023-3-29 19:38:20 | 显示全部楼层
    本帖最后由 cabin 于 2023-3-29 20:07 编辑

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


    1. const ael = EventTarget.prototype.addEventListener;
    2.   EventTarget.prototype.addEventListener = function () {
    3.     console.log(arguments)
    4.     return ael.apply(this, arguments);
    5.   };
    复制代码

    这个是简单demo的arguments


    这个是Vue项目的arguments,可以看到所有的第二个参数都被扣走了


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

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

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

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

    使用道具 举报

  • TA的每日心情
    慵懒
    2023-3-28 14:26
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    9

    主题

    30

    回帖

    42

    积分

    初级工程师

    积分
    42
    发表于 2023-3-30 10:45:08 | 显示全部楼层
    cxxjackie 发表于 2023-3-29 20:55
    没太看懂你的描述,猜测是事件委托的问题,一些框架会将多个元素的事件委托到一个父级元素上,然后根据e.ta ...

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

    这种该怎么破解啊。。。。。。。。。。。。。。。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 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
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表