震惊!他居然用控制台自动植入JS实现某度破解!

震惊!他居然用控制台自动植入JS实现某度破解!

前言

一切都要从某度网盘(下称某盘)的倍速功能说起。

任意一个没有开VIP的账号随变打开一个视频。

切换VIP的时候会提醒VIP专享功能,需要。。。🤔

image

emmmmmm

等我先把我之前写的插件关一下 ,不然倍速和画质都解锁了还教啥。。。🤣

嗯,再看一下,图标变回来了。

👉image👈 ----> 👉image👈

黑金尊贵金属科技感没了,那这次应该关掉了。好了我们继续。不过广告也出现了,果然是鱼与熊掌不可兼得。

哦对了,顺便说一下,这个也就是我【之前在论坛里发过的帖子】中的【某盘脚本】,只不过更新了好几代,现在相对更完善而已。。。😏

好,回到本次主题上。

引入

很久前写脚本时,想解锁某盘的倍速功能,就去分析了当时某盘倍速会跳回去的原因,分析了一下,大概就是某盘代码里会每隔500ms把视频播放的速率调整为当前的设置,非 VIP 就是写死的 1 ,VIP 就是把这个速率调整为 X ,其实也是锁定的,但是没有改动所以不会感受到而已。

于是,在各个地方出现的各种所谓的解锁脚本,都是以更快的频率去重置达到所谓的解锁目的。因为至少也算达到了目的,姑且就算称之为“解锁”吧。🙄

我使用的解决办法不是设置比他更快的定时器的执行方式,毕竟两个定时,一个比一个快(比快我是真的不擅长),浏览器吃得消么?所以导致页面也会越来越卡,但愿浏览器没事。🙏

某盘使用的是 setTimeout 每隔500 ms调用自己,于是我。。。

for(let k=0;k<99999;clearTimeout(k++));

说白了,在循环里清除所有延时定时。。。确实还真的有奇效。😂

但是好景不长,后来某盘更新了算法,大量的脚本都失效了(这一部分现在也是类似的算法),我们本文引入部分需要讨论的也是这部分内容。

简单的搜索一下倍速播放按钮上面的提示,定位到定义的位置,因为本文描述的只是一些稀奇古怪的东西,因此其他的基础内容(比如控制台的打开啊,格式化啊,断点啊,js 基础的操作之类的)请自行查找,我之前的教程也有涉及到,也可以去翻看。

image

定位到位置向下翻,最终呈现的UI上有“立即开通SVIP”,那我开了肯定就不显示了,果然翻到一个非常清楚的问号冒号条件判断语句:

image

顺便补一下基础知识吧(虽然说要基础,但是总要照顾一下读者嘛。。。),很多语言中都有类似的语法,

a?b:c

上述的a,b,c分别代表三组表达式,为什么不是说三个呢?因为不仅可以像他这样放上 json ,还可以是一连串的表达式,比如下面的伪代码所示:

判断1&&判断2&&判断3?
(成立做的事情1,成立做的事情2,成立做的事情3):
(不成立做的事情1,不成立做的事情2,不成立做的事情3)

等等这些都可以。

什么?这就看不懂了?没关系,还有很多其他的你也不懂🤏,当然,也还有更多我所不懂的,一起探索世界嘛,都懂的世界有什么意义呢对吧,毕竟我们还没达到看破红尘的境界。

好,收回来,我们知道了之前代码的意思是:

如果d.userInfo.isSVip不是空(或者0),就把下面的哪个 json 赋值给他,然后显示出来。

翻译一下,如果用户信息里的isSvip不是“假”的话,就不显示哪个按钮

再翻译一下,如过是Svip就不显示那个按钮了

那么我就把这个isSvip改成真试试。

好,下断点,因为这是一个大json,因此直接下断点是无法直接断下来的,因此我们需要在json定义的位置下断点,然后刷新页面,页面暂停,断点处断下。

image

鼠标放到上面悬浮几秒,参数明了了,确实是我不SVIP,那改了不就有了?😘

修改的方式有很多,双击弹窗,在上面直接修改(左下图),

image image

或是在右边的寄存器里找到然后双击修改(右上图),再或者是在控制台输入:d.userInfo.isSVip=true然后敲回车。我最喜欢第三种因为有点很久前那种修改前端让自己以为冲上QB啊之类的快感。。。

改完发现,诶,不仅倍速解锁了,连画质都解锁了。好了下面就是撸脚本了,但是如果你只是自己用呢?就算你会写,在亿堆代码里找调用的位置也是很难的,此外js中最头疼的是什么?是this的内容和作用域。。。

这么说吧,我代码中最终呈现出来的效果,肯定是我分析过了的,但是我没呈现出来的就不一定我没做,有可能是技术原因没搞出来,有可能是纯粹的因为我懒,但是我个人觉得最多的情况其实应该是难以下手别看你这里显示的又是isSvip,又是userinfo的,这都是关键数据,没混淆的,你随手往上看一眼,就是用我们下断点前面一点的截图说明吧:

image

那我问你,这图上所有的参数e我都用红框标出来了,哪个e是哪个e分得清么?最上面的三个e是另一个函数里的,跟我们这个函数无关,function后面括号里的e是参数,是什么还需要找这个函数的调用位置(本函数名是d),而function后面紧跟着的是定义的一个新函数,这个函数的名字是e,而var后的那个e则是一个新的变量,完全没有任何关系的一堆e集中在一张图里。。。🤐😨

那你可能说要下断点,然后控制台赋值,回车然后再运行。没错可以,但是不够智能,那我写这篇文字的意义在哪里?🙄教你如何修改某盘的倍速么?那不如直接用我的插件🤔

解决

我们可以利用chrome的条件断点完成赋值。

跟OD之类的调试器一样,控制台也支持条件断点。

下断点怎么下的?直接左键点一下行号前面,那右键呢?

image

东西还挺多的,上图①就相当于OD中的F4,运行到这里,和②下断点然后运行其实是差不多的;

⑤一般可以用于反调试临时防止一直在某个地方断点,⑥就是忽略这个脚本,跟我们更没关系。。。

最想说的就是③和④,其中③:当表达式为true的时候断下,而④:运行到这里的时候会打印输入的表达式。

很多语言都一样,比如逗号连接的几个表达式是相同级别的,而最终的返回值则是最后一个逗号后面的值

比如

image

前面不管干什么,主要最后一个值是false,那就是false,反之亦然。

所以完全可以利用刚才的条件断点完成注入(这就是本文最主要想说的内容)

我们在条件断点里直接写上赋值语句,然后刷新页面(控制台不关)这里会断下来,然后赋值是成功的,

image

当我们再在后面加上 ,false 就可以实现控制台不断下自动注入(并且不用考虑注入的时间)

image

额外新知识

此外就是没事找事了,使用代码倍速,如果使用代码修改的话还很麻烦的,首先因为他用了shadowroot技术把video标签关闭封装了,

image

这都不是关键问题,通过其他方式我们还是可以通过代码获取到这个标签的,控制倍速什么的也都是正常的。

image

但是!如果是试用旧版SDK,且我们没有之前那样修改isSviptrue,同样的操作,获取当前的倍速信息就会变成

image

这样,然后赋值的时候则是没效果。。。😫

分析一下原因吧。这个原因我找遍了国内外,都没有找到原因,然后我就全页面搜索关键词playbackRate挨个排查所有搜到的js,最后看到了这串代码(因为代码看的不直观就截图了)

image

image

我怎么不仅看到锁定播放速率,还看到了奇怪的东西?如果不是SVIP,并且有视频播放器,并且没有剩余的数量(指试用次数,最上面判断是否显示购买SVIP图标的地方有相关字样),就定义属性?(附:MDN说明文档

image

🤔???(心里疑惑)再看一下get和set

image

所以那段代码的意义就是非SVIP把video标签的playbackrate系统属性重写了,读取速率时返回自己的速率,然后自己又会去读取自己,造成炸堆栈效果?而设置速率就改成空行为。。。

😲真的是学到了,这波骚操作是真的服气。。。其实之前也在论坛里提过,不过是在一个帖子里的子楼层提出来的,并且没有给出响应的解释,这里解释一下。并且艾特一下这位大佬()

现学现卖

你以为到这里就结束了?你以为我只是分享这个属性重写觉得他厉害么?😏😎

显然不是,就算这么搞,我还是修改成功了,所以我最厉害🤣(开个玩笑。。。)

转到某度文档(下称:某文)解锁免VIP复制、全屏纯净阅读的时候(相关脚本也在最上面那个帖子里,【脚本地址】),老规矩,搜关键词,不对,先关脚本。。。广告出现就出现吧,好歹免VIP复制和纯净阅读的特权是不存在了。

👉image👈 ----> 👉image👈

随变打开一篇文章,随变选中一些文字,点复制,弹出购买VIP框。搜索关键词“开通VIP可继续复制”,只找到一处。

image

找到定义地方下断点,此时是创建VIP弹窗,且没有判断,因此考虑找找堆栈回溯。F5刷新,重复操作,断下后点运行,发现第一次断下是弹出悬浮栏的功能,点击复制按钮后第二次断下,才是复制的功能弹窗。

image

因此第二次断下后查看堆栈,堆栈截图如下

image

一般相关的代码都是写在一起的(包括require引入方式),而xreader一看就像是一个什么插件库之类的东西🤔,因此我们重点看common这个库相关的调用。

一眼嫖见clickCopy,点击复制按钮,点击跳转过去

clickCopy: function() {
    r.a.xsend(102222),
    this.setVisible(!1),
    this.setIsCopyActivated(!0)
},

一看第一个就是记录日志然后发送去提升体验感的,直接略过。第二个设置不可见(!1为false),应该是隐藏当前悬浮栏弹窗,最后一个设置复制状态,因为vue调试时候的问题,直接定位不过去,这里可以两种办法找到定位:

  1. 直接搜索setIsCopyActivated一般没有人会定义两个同样名称的函数

    image

    这不就有了么

  2. 在这里下断点,断下后到堆栈里找位置

    唔,注意一层层找,稍微有点麻烦,不过也不比搜索慢

    image

    断下后this->setIsCopyActivated->[[TargetFunction]]->[[FunctionLocation]],点一下就同样可以跳过去。

    emmm不过这里貌似不可行,他被翻译成native code 了,问题不大反正是一种思路😅

    (这又不能怪我,都怪编译器把他编译成native code了,你瞧我们现在所在的clickCopy不是好好的么😕)

    image

    注:其原因应该是与函数的影响的参数类型有关,下面会说到

找到setIsCopyActivated所对应的函数了:

setIsCopyActivated: function(t, e) {
    t.isCopyActivated = e
},

但是只有一行赋值,那他是怎么实现弹窗操作的呢?

这又要涉及到vue生命周期的机制了,他的参数你只需要赋值,然后你代码里所有使用的地方都会同步更新,并且如果添加了监听或是计算等属性是会被自动调用的,(或许这就是为什么上面那个函数是native的原因了,因为有大量的函数是Vue实现的,所以并不是我们对其操作😶不管你信不信,反正我是这么理解的,毕竟也没有看到有几个vue逆向的教程啥的之类的,这里的某文是vue的,上面提到的某盘新主界面也是基于vue的,但是都被我完成修改了hhhhhh😏)因此我们需要知道哪里对于isCopyActivated这个参数的值做出了监听或者是计算之类的。

或者你要是没有vue的基础知识,听不懂我在说什么,换个角度也行:到这里我们就陷入死胡同了,因为没有调用任何地方,我们只是赋值而已。那接下来干什么?是不是肯定跟isCopyActivated这个参数有关?搜索一下看一下这个是在哪里被使用是不是说不定也可以找到蛛丝马迹?或者实在不行就每个调用的地方都下断点,看看哪里在赋值之后断下呗。

那么怎么找呢?理论上也可以通过寄存器查找,不过我吸取了上的教训就没找(其实是我没找到🤣),直接搜索即可找到watch监听的地方

watch: {
    isCopyActivated: function(t) {
        t && this.cannotCopy && (this.showVipGuideCard(),
        r.a.xsend(101643, {
            index: 1
        }))
    },
    formatedText: function(t) {
        this.canCopy(t.length) ? (Object(o.a)(".".concat(this.copyBtnId)).attr("data-clipboard-text", t),
        this.cannotCopy = !1) : this.cannotCopy = !0
    }
},

看到cannotCopy的时候有没有豁然开朗?🤣下断点直接运行,果然成功断下。

image

果然是这么调用过来的,具体发生了什么都不知道,但是问题是确实解决了,接着就是重蹈覆辙(简称重复),比如找到cannotCopy赋值的地方(当然也可以使用刚刚的技巧直接复制false,屡试不爽),看看能不能连什么isvip什么的一起连根解决

image

找了一圈没发现像刚刚那种定义函数,不过看到了下面的formatedText有对cannotCopy赋值的操作this.canCopy(t.length)返回真就给cannotCopy赋值false,否则就是true。这个canCopy函数名确实没毛病😉

这次寄存器里又可以找到定义的位置了,直接跳转过去。

image

canCopy: function(t) {
    var e = this.getCountFromCookie() < 10;
    return t > 100 && !this.isVip && this.docBizType !== B.a.SECRET && (e = !1),
    this.isVip || e
},

诶,这个熟啊,刚刚不是刚干过isSvip么,这就来了isVip😁不得不说规范化变量名还是有好处的对吧😘

下断点,断下后输入我们心爱的this.isVip=true,然后回车。。。。

然后就报错了,截图放下面👇了

image

翻译一下就是isVip定义了但是没有完全定义🤐

翻译一下:

image

没有分配setter?是不是有点熟悉?

没错!刚刚的属性定义,连系统中native的属性都可以重定义了,那我构造一个。。。

Object.defineProperty(this,"isVip",{
    get: function() {
        return true
    }
})

获取isVip值的时候,我不管其他的,直接返回这不就阔以了,用lambda语法糖稍微优化一下:

Object.defineProperty(this,"isVip",{
    get:()=>true
    }
})

压缩一下,再加上最后熟悉的,false

Object.defineProperty(this,"isVip",{get:()=>true}),false

直接运行,完美🎉🎉🎉

image

至此,全局终。

什么?控制台不方便?想拿代码实现?

那我Greasy Fork代码不是开源的么。。自己分析去啊💢

总结

我只负责将道理,讲的是人情事故,我讲是人情,但是翻车了那是事故。

那同理,我讲了,你听懂了,那是世故,那如果你没听懂,那也是事故,问题不大。

(摘自B站UP主“阿三解说”,跟楼主没有任何关系)

本文作者:吾爱破解@涛之雨

本来是打算web分类新成立发个简单的水水的来着,结果越写越多,顺便把vue相关的也都谢了一大堆,就当是我知道的第一个vue相关的破解教程叭,

晚安。

时2021年7月30日00:45:38

posted @ 2021-07-30 00:49  涛之雨  阅读(2294)  评论(0编辑  收藏  举报