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

【油猴开发指南】堆栈异常抛出的利用技巧

[复制链接]
  • TA的每日心情
    无聊
    2025-1-31 20:04
  • 签到天数: 195 天

    [LV.7]常住居民III

    745

    主题

    6465

    回帖

    7159

    积分

    管理员

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

    积分
    7159

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

    发表于 3 天前 | 显示全部楼层 | 阅读模式

    前言

    其实这个方法已经在不同的篇章和论坛回答里用过很多次了
    但是一直没有整理,所以决定今天整理一下

    正文

    很多网页会为了防止脚本对基础API进行劫持,会对调用进行一层封装
    从而导致即使劫持了,因为上层传入的函数没有任何特征,导致无从下手
    例如

    function runTimer(callback, time=1000) {
      setTimeout(() => {
        callback();
      }, time);
    }
    function exampleA() {
      runTimer(() => {
        console.log("A");
      });
    }
    function exampleB() {
      runTimer(() => {
        console.log("B");
      });
    }
    
    exampleA()
    exampleB()

    因为对setTimeout劫持得到的一定是一个箭头函数,根本无法无从下手
    这个时候我们就可以尝试制造一个Error错误,然后利用错误对堆栈进行检查
    从而找到一个有特征的上层函数,来实现通过基础AP进行劫持和过滤操作
    我们可以尝试一下

    const originSetTimeout = window.setTimeout;
    window.setTimeout = function (callback, time) {
      const  err = new Error("大赦天下");
      console.log(err);
      return originSetTimeout.call(this, callback, time);
    };

    打印的输出内容有

    Error: 大赦天下
        at window.setTimeout (1.js:3:16)
        at runTimer (1.js:8:3)
        at exampleA (1.js:13:3)
        at 1.js:23:1
    Error: 大赦天下
        at window.setTimeout (1.js:3:16)
        at runTimer (1.js:8:3)
        at exampleB (1.js:18:3)
        at 1.js:24:1

    可以发现可以通过exampleA和exampleB的字样来选择过滤函数,例如我们想要过滤掉exampleA

    const originSetTimeout = window.setTimeout;
    window.setTimeout = function (callback, time) {
      const err = new Error("大赦天下");
      if (err.stack.indexOf("exampleA") !== -1) {
        return -1;
      }
      return originSetTimeout.call(this, callback, time);
    };

    现在开始只有exampleB可以正常调用runTimer的setTimeout来等待到时间回调输出内容了

    利用异常抛出终止JS文件执行

    当整个文件我们都想阻断执行,或者找不到注入点的时候
    可以利用该方法来阻断文件的执行
    其原理是因为现代前端会使用打包工具进行打包,或框架/库存在初始化代码
    所以通常一个文件的开头会调用一些基础API,我们对基础API进行劫持
    当发现堆栈来自于某个我们想要拦截的文件,就抛出一个异常
    由于这个异常的出现,会导致JS文件的终止,从而杀死后续的代码执行
    例如现在存在两个JS文件,代码分别为

    // A.js
    (window.initArr ?? (window.initArr = [])).push("AFile");
    console.log("A")
    // B.js
    (window.initArr ?? (window.initArr = [])).push("BFile");
    console.log("B")

    我们将window.initArr视为文件的初始化流程的模拟
    这时候可以针对push劫持,并且制造一个Error检查是否来自A.js

    window.initArr = window.initArr ?? [];
    const originPush = window.initArr.push;
    window.initArr.push = function (...args) {
      const err = new Error("大赦天下");
      if(err.stack.indexOf("A.js")!=-1){
        throw Error("Kill A.js")
      }
      return originPush.call(this, ...args);
    };

    可以发现A.js执行到第一条由于异常直接被强制终止了,而B.js可以正确执行,打印输出如下

    inject.js:6 Uncaught Error: Kill A.js
        at window.initArr.push (inject.js:6:11)
        at A.js:1:43
    B.js:2 B

    这个时候无论是想要彻底不再执行这个文件,还是在阻断后在gm_xhr请求这个文件再去执行都没问题了
    当然抛出一个错误不好看,我们可以再通过onError捕获抛出的错误,如果是我们自己的就pass掉
    这样就很干净了!

    window.onerror = function(message, source, lineno, colno, error) {
      if(error.message=="Kill A.js"){
        return true
      }
    };

    结语

    完结撒花~

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.com/a/lihengdao666
  • TA的每日心情
    开心
    3 天前
  • 签到天数: 16 天

    [LV.4]偶尔看看III

    7

    主题

    45

    回帖

    90

    积分

    初级工程师

    积分
    90

    油中3周年油中2周年新人报道挑战者 lv2

    发表于 3 天前 | 显示全部楼层
    大赦天下!
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2025-1-31 20:04
  • 签到天数: 195 天

    [LV.7]常住居民III

    745

    主题

    6465

    回帖

    7159

    积分

    管理员

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

    积分
    7159

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

    发表于 前天 03:13 | 显示全部楼层

    以前特别痴迷天天快手看精神小伙直播
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.com/a/lihengdao666
    回复

    使用道具 举报

  • TA的每日心情
    开心
    昨天 01:15
  • 签到天数: 7 天

    [LV.3]偶尔看看II

    1

    主题

    7

    回帖

    12

    积分

    助理工程师

    积分
    12
    发表于 前天 08:56 | 显示全部楼层
    原来还可以这么玩,学到了。感谢大佬分享。
    🏷️ 小鱼标签 (UTags) https://bbs.tampermonkey.net.cn/thread-8121-1-1.html
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2025-1-31 20:04
  • 签到天数: 195 天

    [LV.7]常住居民III

    745

    主题

    6465

    回帖

    7159

    积分

    管理员

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

    积分
    7159

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

    发表于 前天 10:52 | 显示全部楼层
    pipecraft 发表于 2025-2-19 08:56
    原来还可以这么玩,学到了。感谢大佬分享。

    hhh
    谢谢哥哥~
    我也是摸索好久加上论坛其他人帮助才get到的
    利用异常终止文件执行第一眼真的骚
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.com/a/lihengdao666
    回复

    使用道具 举报

    发表回复

    本版积分规则

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