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

[油猴脚本开发指南]script标签初始化对象劫持

[复制链接]
  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

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

    积分
    6760

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

    发表于 2021-9-12 18:28:15 | 显示全部楼层 | 阅读模式

    开篇

    在我们写脚本的时候,经常碰到一种情况,就是网页调用了外部的库,而我们想要去修改内容或者使用一些功能,这时候通常会束手无策,所以我在这里简单的提供一些我自己的想法,可能存在一些问题,可以评论下写出。

    通常分为两种情况,一种情况是网页的功能数据暴露在了windows的内部,这时候我们可以考虑直接对其进行劫持。另外一种是在封闭作用域内,这种情况我们可以考虑对其内部的一些函数进行劫持。

    这里我们以https://www.acwing.com/problem/content/1/为例,我想修改这个编辑器的内容

    图片.png

    通过这里的domclass类可以知道,这个是一个ace编辑器,手册在https://ace.c9.io/#nav=embedding

    顺便一提,目前常见的有两种编辑器,一种是ace编辑器,一种是codemirror编辑器,目前两种并无优劣,ace个人认为开发更舒服一点

    并且查看windows下挂载了ace,我们可以直接使用

    ace.edit("code_editor").setValue('8888')

    (备注,初始化编辑器通常使用ace.edit函数进行初始化)

    来进行设置内容,因为ace编辑器允许反复初始化,并返回相同的内容,这里可以用相等来进行判断

    图片.png

    但是这么简单就没有挑战了!所以我们搞的可以更复杂一点。

    我们现在document-start的时候对脚本注入,然后debugger

    图片.png

    可以看到这时候body里的script函数很少的

    这时候我们查看一下ace对象是否有初始化

    图片.png

    证明我们注入的时候ace还没初始化。我们再看一下加载完毕的body内的内容,可以看到差距非常大

    图片.png

    那这时候我们就可以考虑一个想法,在监控body内的dom变化的时候,检测是否有ace,如果存在就开始劫持ace.edit,直接把对象挂载到window上,这样就把编辑器的对象直接暴露到了外部出去,这里我直接提供一下代码

    window.oldace=null
    document.querySelector('head').addEventListener("DOMNodeInserted", function(event) {
    if(window.ace!==undefined&&window.oldace===null&&window.ace.edit!==undefined){
    window.oldace=window.ace.edit
    window.ace.edit=function(...args){
    let ret=window.oldace.call(this,...args)
    window.setace=ret
    return ret
    }
    }
    });

    if判断window.ace不为undefine的时候检测存储编辑器对象是否为空,如果为空则检测ace.edit是否存在,因为根据我的观察ace的各种函数是逐步初始化的,所以必须进行检测。

    如果检测到了edit函数,则对其包装一层,并将返回的内容暴露到window下。

    这时候我们直接控制window下的oldace就可以操作编辑器了!

    附加

    我们也可以使用数据响应来对其进行劫持完成目的,这时候可以对edit再进行一下处理

    let _ace;
    Object.defineProperty(unsafeWindow, 'ace', {
      configurable: true,
      get: () => _ace,
      set: value => {
        console.log('ace被赋值了');
        _ace = value;
      }
    });
    

    结语

    撒花~

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

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

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

    发表于 2021-9-12 19:39:45 | 显示全部楼层
    李恒道 发表于 2021-9-12 18:28
    @cxxjackie 大佬,监控某个js文件彻底加载完毕有什么好一点的办法么....这样感觉其实还是不太对劲 ...

    那种完全封闭的应该监控不了,除非他自己对外发了消息,监听页面节点插入是比较常见的做法,如果是这种暴露全局对象的,用Object.defineProperty劫持set更好,像这样:
    1. let _ace;
    2. Object.defineProperty(unsafeWindow, 'ace', {
    3.   configurable: true,
    4.   get: () => _ace,
    5.   set: value => {
    6.     console.log('ace被赋值了');
    7.     _ace = value;
    8.   }
    9. });
    复制代码

    监听ace.edit的话,再嵌套一层Object.defineProperty就好了(可以封装成Promise写起来好看点)。
    回复

    使用道具 举报

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

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

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

    发表于 2021-9-13 21:11:12 | 显示全部楼层

    李恒道 发表于 2021-9-13 19:49

    我怀疑可能存在更核心的api用来注入,如果能找到比较优良的注入点就舒服了
    然而菜的抠脚,理论可以,实际 ...

    试着写了个Promise来实现,可能不太完善:

    function waitForProperty(obj, ...props) {
        let _obj = obj;
        let prop;
        const realDP = Object.defineProperty;
        const waitForValue = () => {
            return new Promise(resolve => {
                Object.defineProperty = function() {
                    if (arguments[0] === _obj && arguments[1] === prop) {
                        const value = 'value' in arguments[2] ? arguments[2].value : arguments[2].get.call(_obj);
                        Object.defineProperty = realDP;
                        resolve(value);
                    }
                    return realDP.apply(Object, arguments);
                };
                realDP.call(Object, _obj, prop, {
                    configurable: true,
                    enumerable: false,
                    get: () => undefined,
                    set: value => {
                        realDP.call(Object, _obj, prop, {
                            configurable: true,
                            enumerable: true,
                            writable: true,
                            value: value
                        });
                        Object.defineProperty = realDP;
                        resolve(value);
                    }
                });
            });
        };
        return new Promise(async (resolve, reject) => {
            while (props.length > 0) {
                prop = props.shift();
                if (prop in _obj) {
                    _obj = _obj[prop];
                } else {
                    _obj = await waitForValue();
                }
                if (props.length > 0 && typeof _obj !== 'function' && typeof _obj !== 'object') {
                    return reject(`The property '${prop}' is not a function or object.`);
                }
            }
            resolve(_obj);
        });
    }

    调用方式就像这样:await waitForProperty(unsafeWindow, 'a', 'b', 'c')

    前后端的话当然是前端啦,具体的就不细说了,个人隐私个人隐私~

    回复

    使用道具 举报

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

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

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

    积分
    6760

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

    发表于 2021-9-12 18:28:53 | 显示全部楼层
    @cxxjackie 大佬,监控某个js文件彻底加载完毕有什么好一点的办法么....这样感觉其实还是不太对劲
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

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

    使用道具 举报

  • TA的每日心情
    开心
    2022-7-5 00:02
  • 签到天数: 124 天

    [LV.7]常住居民III

    5

    主题

    168

    回帖

    927

    积分

    版主

    积分
    927

    荣誉开发者油中2周年

    发表于 2021-9-12 18:41:01 | 显示全部楼层
    学到了!!
    回复

    使用道具 举报

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

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

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

    积分
    6760

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

    发表于 2021-9-13 14:52:56 | 显示全部楼层
    cxxjackie 发表于 2021-9-12 19:39
    那种完全封闭的应该监控不了,除非他自己对外发了消息,监听页面节点插入是比较常见的做法,如果是这种暴 ...

    加上去了,完全封闭的可以使用Object.defineProperty劫持之类的在基础api做手脚拿到数据,我之前阿里云盘的时候尝试过
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

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

    使用道具 举报

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

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

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

    发表于 2021-9-13 19:14:48 | 显示全部楼层
    李恒道 发表于 2021-9-13 14:52
    加上去了,完全封闭的可以使用Object.defineProperty劫持之类的在基础api做手脚拿到数据,我之前阿里云盘 ...

    劫持基础API应该可以,这我确实没想那么多。不过Object.defineProperty只能监听到直接赋值的操作,对于同样用Object.defineProperty修改get的就没什么办法了,还得加上对defineProperty这个函数本身的劫持,这种情况可能就得祭出Proxy了,我记得Proxy是可以同时处理get、set和defineProperty的。
    回复

    使用道具 举报

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

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

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

    积分
    6760

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

    发表于 2021-9-13 19:49:34 | 显示全部楼层
    cxxjackie 发表于 2021-9-13 19:14
    劫持基础API应该可以,这我确实没想那么多。不过Object.defineProperty只能监听到直接赋值的操作,对于同 ...

    我怀疑可能存在更核心的api用来注入,如果能找到比较优良的注入点就舒服了
    然而菜的抠脚,理论可以,实际屁都不会
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

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

    使用道具 举报

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

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

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

    积分
    6760

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

    发表于 2021-9-13 19:49:47 | 显示全部楼层
    cxxjackie 发表于 2021-9-13 19:14
    劫持基础API应该可以,这我确实没想那么多。不过Object.defineProperty只能监听到直接赋值的操作,对于同 ...

    话说哥哥你是前端还是后端啊
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

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

    使用道具 举报

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

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

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

    积分
    6760

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

    发表于 2021-9-13 23:07:25 | 显示全部楼层
    cxxjackie 发表于 2021-9-13 21:11
    [md]试着写了个Promise来实现,可能不太完善:

    ```javascript

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

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

    使用道具 举报

    发表回复

    本版积分规则

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