欢迎光临!这里是页首

zqdlly的博客(博客标题)

zqdlly的博客(博客子标题)

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

警告:该随笔内容仅用于帮助某星内部人员完善其代码,不得被某星内部人员以外的任何个人和机构使用,不得用于非法用途,禁止转载,否则后果自负,我一定会用我折腾js的精力向你索赔到底!!!

最近在某星视频观看网课,突然发现教师设置了不能倍速播放视频。这样会让我感到很痛苦,没有倍速的网课是没有灵魂的!!!此外视频还有失焦后,就会自动暂停播放的操作,导致我一进入控制台就给我暂停视频,这增加了我的不适感。于是,平素就热爱折腾js的我,投入了大把时间研究这个问题,并最终幸运的实现了目标。感谢强大的TamperMonkey插件,感谢cnblogs、StackOverflow、SegmentFault、CSDN,以及其他各网站上曾帮助过我的的一切技术大佬们(排名不分先后)。

以下的所有步骤是凭借我的记忆来的,可能会缺少很多内容,顺序上也不准确,但无伤大雅。

  • 某星的视频很变态,在video外面套了两层iframe,会增加对定位元素的阻力。好在基于强大的TamperMonkey插件,可以直接把脚本匹配网站设为嵌套视频的那层iframe的src链接。问题解决。
  • 想过偷懒,找一个现成的油猴脚本。很遗憾暂时没有找到一个能够在现有的某星平台上,唤回倍速播放功能的脚本。估计是某星更新太频繁了。于是决定自己写一个脚本凑活着用。
  • 首先需要取消蛋疼的视频自动暂停功能。受限于我当时的技术水平,我是这么做的
v.addEventListener("pause",e=>{
    e.target.play()
})
//虽然这么是不会自动暂停了,可也造成了视频无法暂停,难受啊。先不管了,因为这个只是小菜,重头戏是倍速播放。
  • 继续研究,发现某星给视频添加了很多事件的监听器,其中就有个匿名函数绑定在ratechange事件上。借助它,某星可以拦截所有修改倍速的操作,直接使用document.querySelector("video").playbackRate = 2;是无效的,他会马上给你改回来(题外话,发现如果把倍速设置为1以下,就不会被拦截,这是什么恶趣味?)。常规的话,想要移除绑定了回调函数的监听器,只能移除有名字的函数的监听器,移除匿名函数的监听器是不可能的。此外,某星还对其部分js源码进行了加密,比如video.js,放眼望去几万行代码,各种混淆后的标识符名字,我截取一行你们体会下function a0_0x3ffc(_0xf3628b,_0x19b3a9){var _0x53fe0f=a0_0x53fe();return a0_0x3ffc=function(_0x3ffc55,_0x4f6c6f){_0x3ffc55=_0x3ffc55-0xfd;var _0x1795ee=
  • 首先,利用新版的Chrome浏览器,可以移除绑定匿名函数的事件监听器!怎么样是不是很意外?我也很意外,但就是这样,不得不说Chrome太强大了,也是最近一两年才推出的这个操作(题外话:新版的Chrome浏览器也终于汉化了控制台,算是解决了一大历史遗留问题,是我们的福音啊。我现在虽然还是以使用Firefox浏览器为主,但能明显地感受到,Chrome比Firefox的手感实在是丝滑太多了,比如打开调试器的时候,我的Firefox比Chrome总是更容易卡死,又比如在调试器搜索东西的时候,搜索出来的结果也经常是Chrome更多。强大的Chrome甚至比Firefox还多了一个getEventlisteners的函数。感觉Firefox在走下坡路啊,悲伤ing,Firefox你要振作起来啊)。虽然利用新版的Chrome浏览器,可以移除事件监听器,但这有个问题,操作太麻烦,每次都要手动打开控制台,找到iframe里面的video,然后找到ratechenge事件,然后手动移除之。这个操作是不能用js完成的,没有自动化就没有灵魂啊!不能满足我的需求,我要继续折腾,而且我要找到一种能够在Firefox上使用的方法。转变思路:不再尝试移除匿名的Eventlistener
  • 想过利用冒泡/捕获事件的规则。以前尝试过解除某网页的防粘贴功能,就是利用了当时该网页把paste事件设置为捕获事件,首先触发根节点的paste,然后才触发子节点的paste。这次我发现修改视频播放倍速,触发video的ratechange事件是冒泡事件,意味着是从里到外触发的。做了个实验(部分源码在下面),在video标签内部加一个子vidoe标签,为二者都分别加上ratechange事件的监听器,然后修改子video的倍速,结果却发现只触发了子video的事件就结束,不会传播到父video。后来猛然意识到,ratechange事件,根本上和paste、click这类事件是不同的!!!后者可以产生一种传递的关系,依次触发涉及到的各层次元素,从而可以对这种机制加以利用,在传递的途中就予以阻断。而当前的ratechange不一样,改变子视频倍速,确实不会触发父视频的倍速变化事件!转变思路:不再尝试利用冒泡/捕获事件的机制
<!--这是我使用,测试冒泡和捕获的部分源码-->
<video id="v">
<video id="subv">
</video>
</video>
<script>
document.querySelector("#v").addEventListener('ratechange', function(event) {
	alert("v rate changed");
}, false);//false表示不是捕获事件
document.querySelector("#subv").addEventListener('ratechange', function(event) {
	alert("subv rate changed")
}, false);				
</script>
  • 在StackOverflow看到过一个移除dom上所有Eventlisteners的方式:dom.outerHTML=dom.outerHTML;这种方法虽然有效,但会造成所有Eventlisteners的移除,比如视频的play事件的监听器,移除了就无法播放了!转变思路:不再尝试移除所有Eventlisteners
  • 想过解密混淆后的js源码。很可惜,这个工作量实在是太大了,而且以我的能力估计也会卡住。后来很幸运的在思否上找到一个大佬的文章,Javascript混淆与解混淆的那些事儿 - SegmentFault 思否 ,惊喜的发现,某星的加密方式,似乎就是该文章中提到的"javascript-obfuscator混淆后生成的代码"的方式(题外话:感觉思否的社区质量一直都很高啊!不知道是怎么做到的,可能因为太小众了吧)。然后顺藤摸瓜,在本文中找到其对应的解密工具crack.js。过程中也尝试过其他的各种解密方式,比如jsnice,,然而最后都失败了,要么源码太长,要么网站连接失败,要么就是我现在看不懂的操作。其实我也不是很想解密,因为这个过程注定了对某星api的依赖,万一它每隔10分钟就换一套代码,又要重新开始折腾,时间成本太大了。以前解密过某其他的网站的js,使用的是该文章中提到的第一种加密法——by eval(),不得不说这种加密方式属实ez,最后我甚至能还原出其原本的函数名。而某星就直接把所有函数名进行了不可逆的改名,我觉得她根本就没想过给我提供一个把名字还原的操作api!转变思路:不再尝试揭秘源码
  • 经过长久的网路冲浪,最后在StackOverflow发现某提问者给了我一个思路,那就是直接重置addEventListener这个东东(我之前使用eval方式解密某网站的那次操作,跟这个很像,也是重置了网页原本的eval函数)。说实话,现在我还不是很懂addEventListener这个函数,为什么window.addEventListener==Element.prototype.addEventListener是真,而document.addEventListener==Element.prototype.addEventListener有时候真,有时候假。难道是每个dom的addEventListener都不一样吗?存疑。
const oldAddEventListener = Element.prototype.addEventListener;
const EventListener = function(type,listener) {
    //do something
    oldAddEventListener.call(this, type, listener);
};
Element.prototype.addEventListener = EventListener;
/*
    * 通过这种操作,就可以人为的控制网页的原始addEventListener!
    * 我可以不让ratechange事件,pause事件等有关的函数绑定在video上,从而达到人为过滤
    * 当然这么做的前提是,必须抢在某星使用原始的addEventListener之前,就改写它!
    * 如果只凭我的手速,这是不可能的吧。
    * 很可惜,基于强大的TamperMonkey插件,通过把脚本设置为run-at document-start的方法,就可以做到!
    * (再一次感谢TamperMonkey给我的帮助)
    */
  • 现在释放一下我的效果图并作出解说:
    • 我在左上角添加了一组按钮,通过点击就可以设置为我想要的播放速度。不过能够这些按钮成功,其灵魂还是在于上面的一堆操作
    • 再一次衷心感谢自己能够幸运的被身边这么多大佬和强大的技术所环绕!《当你负重前行的时候,你要记得有人在替你岁月静好》

    • 不要试图问我要代码,我也不会回应你的需求。这些成功只属于那些愿意为他付出时间,去折腾的人们。

  • 后续:趁热打铁,想要试试能不能直接获取匿名函数,并对其进行移除。下图是我在控制台输出的结果:

    可以发现,我得到了我想要的内容。接下来尝试能不能移除。
    • 刚开始我迷糊了很久,因为始终不能在顶级页面控制台得到我声明的全局变量,但控制台却能输出内容,后来才意识到iframe的存在(我居然可以在顶级页面的控制台看到iframe的console.log输出的内容,好奇怪啊,这不满足同源策略吧)。因为video是在两层iframe里面的,直接使用unsafeWindow.top.arrayOfElms = new Array();;类似这样的赋值语句会报错:Uncaught (in promise) DOMException: Permission denied to access property "arrayOfElms" on cross-origin object,对于我而言,这意味着我无法从iframe向其顶级页面传递数据。但奇怪的是如果在顶级页面使用frames[0].frames[0].window.xxx,就能得到iframe里面的xxx(这也不满足同源策略吧)。接下来我打算尝试移除我想移除的事件监听器。
    • 首先,尝试在顶级页面移除,如下:
      刚开始输入索引0没有成功,是因为其存储的是绑定在另一个元素上的函数。改成1再试试,没想到居然直接就成功了!这个过程没有遭到同源策略的阻力,是我万万没有想到的。既然这都能成功,那在iframe层的移除就更能成功了,我就不再试了

再次警告:该随笔内容仅用于帮助某星内部人员完善其代码,不得被某星内部人员以外的任何个人和机构使用,不得用于非法用途,禁止转载,否则后果自负,我一定会用我折腾js的精力向你索赔到底!!!

posted on 2022-03-24 12:39  zqdlly  阅读(355)  评论(0编辑  收藏  举报

欢迎光临!这里是页脚

联系方式:zqdlly@163.com 非诚勿扰