李恒道 发表于 2022-3-9 11:42:44

[油猴脚本开发指南]实战videojs极限注入

# 前文

超星更新后的网页

这次在beforesetup和setup的钩都给强制return了

导致无法再次使用钩子

所以我观察源码搞了一个极限注入的操作

本质上学习观察源码的过程也是提升自我的一个过程

只要忍过第一个阵痛期,后面其实能看懂源码很爽的

很多时候你比只会看文档的程序员更了解执行原理!

# 开始

之前的hooks已经失效了,那我们在初始化阶段几乎没有什么可以插手的地方了

```js
      hooks('beforesetup').forEach(function (hookFunction) {
      var opts = hookFunction(el, mergeOptions$3(options));

      if (!isObject$1(opts) || Array.isArray(opts)) {
          log$1.error('please return an object in beforesetup hooks');
          return;
      }

      options = mergeOptions$3(options, opts);
      }); // We get the current "Player" component here in case an integration has
      // replaced it with a custom player.

      var PlayerComponent = Component$1.getComponent('Player');
      player = new PlayerComponent(el, options, ready);
      hooks('setup').forEach(function (hookFunction) {
      return hookFunction(player);
      });
```

hooks钩的地方可以全部排除了

那我们唯一能下手的地方就是更核心的地方

也就是Component$1.getComponent函数

我们先观察一下他的源码

```js
      Component.getComponent = function getComponent(name) {
      if (!name || !Component.components_) {
          return;
      }

      return Component.components_;
      };
```

这里判断是否为空,或者保存组件的位置是否为空,如果都不为空,则返回对应的名字

也就是说Player保存在Component.components_['Player']中

那我们需要设置的,就是对components_进行设置

全局搜索Component.components_以及查阅官方文档

可以找到这里

![图片.png](data/attachment/forum/202203/09/113008ymy3n28movm6uwea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

查阅官方文档可以发现,这里是注册组件的地方

那么思路来了,我们可不可以注册Player函数?

阅读源码开始!

```js
      if (typeof name !== 'string' || !name) {
          throw new Error("Illegal component name, \"" + name + "\"; must be a non-empty string.");
      }
```

判断名字异常,可以跳过

```js
      var Tech = Component.getComponent('Tech'); // We need to make sure this check is only done if Tech has been registered.

      var isTech = Tech && Tech.isTech(ComponentToRegister);
      var isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype);

      if (isTech || !isComp) {
          var reason;

          if (isTech) {
            reason = 'techs must be registered using Tech.registerTech()';
          } else {
            reason = 'must be a Component subclass';
          }

          throw new Error("Illegal component, \"" + name + "\"; " + reason + ".");
      }
```

这里通过原型链判断是否继承与Comp组件或者继承于Tech组件

```js
      name = toTitleCase$1(name);

      if (!Component.components_) {
          Component.components_ = {};
      }
```

name函数经过某些处理,然后对components_如果不存在则进行初始化

```js
      var Player = Component.getComponent('Player');
```

获取Player组件

```js
      if (name === 'Player' && Player && Player.players) {
          var players = Player.players;
          var playerNames = Object.keys(players); // If we have players that were disposed, then their name will still be
          // in Players.players. So, we must loop through and verify that the value
          // for each item is not null. This allows registration of the Player component
          // after all players have been disposed or before any were created.

          if (players && playerNames.length > 0 && playerNames.map(function (pname) {
            return players;
          }).every(Boolean)) {
            throw new Error('Can not register Player component after player has been created.');
          }
      }
```

这里判断了Player地方进行了处理,可以看到首先判断名字是否是Player

然后判断Player是否为空,如果不为空,则继续判断players是否存在

三者都存在的时候才禁止替换Player组件

也就是说我们可以对其进行组件替换

这里可以看出来Vidoejs的设计非常优秀,对大部分的功能做了一个组件化的抽离和替换。

```js
      Component.components_ = ComponentToRegister;
      Component.components_ = ComponentToRegister;
      return ComponentToRegister;
```

然后非常简单,对其组件进行赋值了

理论建立完毕,开始实战

```js
let OriginPlayer = _videojs.getComponent('Player')
let woailiyinhe=function(tag, options, ready){这里做原OriginPlayer的对象生成,返回,处理}
woailiyinhe.prototype=Object.create(OriginPlayer.prototype)
videojs.registerComponent('Player',woailiyinhe)
```

这里因为是tm脚本,所以我直接上了一个prototype替换,按道理其实官方更推荐用class类,但是那就要做语法转换了,所以hook偷了个懒

劫持完毕之后我们就可以完美的劫持Player初始化前后的操作了!

# 结语

其实阅读源码对个人提升帮助真的很大,所以偶尔会带领大家一起拆解一些流行的框架或者库的源码

至于给我爱李银河改成我爱破解,真的蛮无聊的

写李银河只是因为我个人非常崇尚王小波

我经常翻读王小波的著作,其中面朝大海,春暖花开那一段非常经典,

我看了不下十遍,至今仍能倒背如流,所以建议如果不懂李银河瞎改建议先提高文学素养

我认为写代码不仅仅是写代码,也是一个表达自我精神的一个机会

代码上的喜好能直接体现出人的性格,希望大家写出属于自己的代码

# 李银河

```js
李银河(1952年2月4日-),女,北京人,中国大陆社会学家、社会活动家,性学家、LGBT权利活动家,已故中国当代作家王小波的遗孀。
```

cocang 发表于 2022-3-9 14:38:09

ggnb
收藏 = 学废了

李恒道 发表于 2022-3-9 14:46:53

cocang 发表于 2022-3-9 14:38
ggnb
收藏 = 学废了

给我学!你不是最喜欢videojs的吗!

q2454181517 发表于 2022-3-14 12:39:48

ggnb!!!!!

nimo 发表于 2022-3-16 13:47:08


大哥 今天网站更新了 用不了了 能更新下插件吗

李恒道 发表于 2022-3-16 14:03:39

nimo 发表于 2022-3-16 13:47
大哥 今天网站更新了 用不了了 能更新下插件吗

超星之前连续三次都是针对我更新的
没法玩了
暂时没更新计划了哦

arootwzz 发表于 2022-3-18 14:32:14

道哥,学这个需要什么语言作为基础呢

李恒道 发表于 2022-3-18 15:15:44

arootwzz 发表于 2022-3-18 14:32
道哥,学这个需要什么语言作为基础呢

一般来说会js就够了
按指南目录看到哪不会查哪其实也可以的

815132496 发表于 2022-3-26 17:35:13

虽然看不懂,但能被超星针对打补丁的,牛的不说了{:4_94:}

李恒道 发表于 2022-3-26 18:13:25

815132496 发表于 2022-3-26 17:35
虽然看不懂,但能被超星针对打补丁的,牛的不说了

呜呜呜
牌面就完事了!
谢谢哥哥!
页: [1] 2 3 4
查看完整版本: [油猴脚本开发指南]实战videojs极限注入