震惊!他居然用控制台自动植入JS实现某度破解!
前言
一切都要从某度网盘(下称某盘)的倍速功能说起。
任意一个没有开VIP的账号随变打开一个视频。
切换VIP的时候会提醒VIP专享功能,需要。。。🤔
emmmmmm
等我先把我之前写的插件关一下 ,不然倍速和画质都解锁了还教啥。。。🤣
嗯,再看一下,图标变回来了。
👉
👈 |
----> |
👉
👈 |
黑金尊贵金属科技感没了,那这次应该关掉了。好了我们继续。不过广告也出现了,果然是鱼与熊掌不可兼得。
哦对了,顺便说一下,这个也就是我【之前在论坛里发过的帖子】中的【某盘脚本】,只不过更新了好几代,现在相对更完善而已。。。😏
好,回到本次主题上。
引入
很久前写脚本时,想解锁某盘的倍速功能,就去分析了当时某盘倍速会跳回去的原因,分析了一下,大概就是某盘代码里会每隔500ms把视频播放的速率调整为当前的设置,非 VIP 就是写死的 1 ,VIP 就是把这个速率调整为 X ,其实也是锁定的,但是没有改动所以不会感受到而已。
于是,在各个地方出现的各种所谓的解锁脚本,都是以更快的频率去重置达到所谓的解锁目的。因为至少也算达到了目的,姑且就算称之为“解锁”吧。🙄
我使用的解决办法不是设置比他更快的定时器的执行方式,毕竟两个定时,一个比一个快(比快我是真的不擅长),浏览器吃得消么?所以导致页面也会越来越卡,但愿浏览器没事。🙏
某盘使用的是 setTimeout
每隔500 ms
调用自己,于是我。。。
for(let k=0;k<99999;clearTimeout(k++));
说白了,在循环里清除所有延时定时。。。确实还真的有奇效。😂
但是好景不长,后来某盘更新了算法,大量的脚本都失效了(现在这一部分也是类似的算法),我们本文引入部分需要讨论的也是这部分内容。
简单的搜索一下倍速播放按钮上面的提示,定位到定义的位置,因为本文描述的只是一些稀奇古怪的东西,因此其他的基础内容(比如控制台的打开啊,格式化啊,断点啊,js 基础的操作之类的)请自行查找,我之前的教程也有涉及到,也可以去翻看。
定位到位置向下翻,最终呈现的UI上有“立即开通SVIP”,那我开了肯定就不显示了,果然翻到一个非常清楚的问号冒号条件判断语句:
顺便补一下基础知识吧(虽然说要基础,但是总要照顾一下读者嘛。。。),很多语言中都有类似的语法,
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定义的位置下断点,然后刷新页面,页面暂停,断点处断下。
鼠标放到上面悬浮几秒,参数明了了,确实是我不SVIP,那改了不就有了?😘
修改的方式有很多,双击弹窗,在上面直接修改(左下图),
或是在右边的寄存器里找到然后双击修改(右上图),再或者是在控制台输入:d.userInfo.isSVip=true
然后敲回车。我最喜欢第三种因为有点很久前那种修改前端让自己以为冲上QB啊之类的快感。。。
改完发现,诶,不仅倍速解锁了,连画质都解锁了。好了下面就是撸脚本了,但是如果你只是自己用呢?就算你会写,在亿堆代码里找调用的位置也是很难的,此外js中最头疼的是什么?是this
的内容和作用域。。。
这么说吧,我代码中最终呈现出来的效果,肯定是我分析过了的,但是最终代码里没有呈现出来的不一定是我没做,也可能是技术原因没搞出来怎么实现,还有可能就纯粹的因为我懒(老咕咕咕怪了🤣),但是我个人觉得最多的情况其实应该是难以下手。别看你这里显示的又是isSvip,又是userinfo的,这都是关键数据,没混淆的,你随手往上看一眼,就用我们下断点前面一点地方的截图说明吧:
那我问你,这图上所有的参数e
我都用红框标出来了,哪个e是哪个e分得清么?最上面的三个e
是另一个函数里的,跟我们这个函数无关,function
后面括号里的e是参数,是什么还需要找这个函数的调用位置(本函数名是d),而function后面紧跟着的是定义的一个新函数,这个函数的名字是e,而var后的那个e则是一个新的变量,完全没有任何关系的一堆e集中在一张图里。。。🤐😨
那你可能说要下断点,然后控制台赋值,回车然后再运行。没错可以,但是不够智能,那我写这篇文字的意义在哪里?
🙄教你如何修改某盘的倍速么?那不如直接用我的插件🤔
解决
抛开脚本不谈,(比如在修改过程中,或者就是临时自用一下)
我们可以利用chrome的条件断点完成赋值。
跟OD之类的调试器一样,控制台也支持条件断点。
下断点怎么下的?直接左键点一下行号前面,那右键呢?
东西还挺多的,上图①就相当于OD中的F4
,运行到这里,和②下断点然后运行其实是差不多的;
⑤一般可以用于反调试临时防止一直在某个地方断点,⑥就是忽略这个脚本,跟我们更没关系。。。
最想说的就是③和④,其中③:当表达式为true
的时候断下,而④:运行到这里的时候会打印输入的表达式。
因为打印表达式是一定会打印的,我们不需要打印数据,和大多数语言一样,巨大数量的打印日志会增加浏览器的负担导致卡顿,
而断点则是根据输入内容的真与假
的布尔值有条件的断下,因此我们主要需要用到这个条件断点
。
与很多语言一样,比如逗号连接的几个表达式是相同级别的,而最终的返回值则是最后一个逗号后面的值:
比如
前面不管干什么,主要最后一个值是false,那就是false,反之亦然。
所以完全可以利用刚才的条件断点完成注入(这就是本文最主要想说的内容)
我们在条件断点里直接写上赋值语句,然后刷新页面(控制台不关)这里会断下来,又因为所有的赋值都一定是成功的,所以d.userInfo.isSVip=true
的返回值一定是true
因此每次运行到这里,条件断点都会在这里断下。
当我们再在后面加上 ,false
,就相当于上面的(true,false)
的类型,对条件断点返回了false
,就可以实现利用控制台不断下进行自动注入。
这样注入的好处很多,比如无须添加断点后手动修改数据(不管用什么方法),时间总会很长(超过比如500毫秒),有可能被检测到或是导致数据失效或者就是最简单的原因:重复操作很麻烦。
额外新知识
此外就是没事找事了,使用代码倍速,如果使用代码修改的话还很麻烦的,首先因为他用了shadowroot
技术把video标签关闭封装了,
这都不是关键问题,通过其他方式我们还是可以通过代码获取到这个标签的,控制倍速什么的也都是正常的。
但是!如果页面加载的是旧版SDK,且我们没有之前那样修改isSvip
为true
,同样的操作,获取当前的速度就会变成
这样,然后赋值则是没效果。。。😫
分析一下原因吧。这个原因我找遍了国内外,都没有找到原因,然后我就全页面搜索关键词playbackRate
挨个排查所有搜到的js,最后看到了这串代码(因为代码看的不直观就截图了)
我怎么不仅看到锁定播放速率,还看到了奇怪的东西?如果不是SVIP,并且有视频播放器,并且没有剩余的数量(指试用次数,最上面判断是否显示购买SVIP图标的地方有相关字样),就定义属性?(附:MDN说明文档)
🤔???(心里疑惑)再看一下get和set
所以那段代码的意义就是非SVIP把video标签的playbackrate
系统属性重写了,读取速率时返回自己的速率,然后自己又会去读取自己,造成炸堆栈效果?而设置速率就改成空行为。。。
😲秒啊,真的是学到了,这波骚操作是真的服气。。。其实之前也在论坛里提过,不过是在一个帖子里的子楼层提出来的,并且没有给出响应的解释,这里解释一下。并且艾特一下这位大佬( @Culaccino )
现学现卖
你以为到这里就结束了?你以为我只是分享这个属性重写觉得他厉害么?😏😎
显然不是,就算这么搞,我还是修改成功了,所以我最厉害🤣(开个玩笑。。。)
转到某度文档(下称:某文)解锁免VIP复制、全屏纯净阅读的时候(相关脚本也在最上面那个帖子里,【脚本地址】),老规矩,搜关键词,不对,先关脚本。。。广告出现就出现吧,好歹免VIP复制和纯净阅读的特权是不存在了。
👉
👈 |
----> |
👉
👈 |
随变打开一篇文章,随变选中一些文字,点复制,弹出购买VIP框。搜索关键词“开通VIP可继续复制”,只找到一处。
找到定义地方下断点,此时是创建VIP弹窗,且没有判断,因此考虑找找堆栈回溯。F5刷新,重复操作,断下后点运行,发现第一次断下是弹出悬浮栏的功能,点击复制按钮后第二次断下,才是复制的功能弹窗。
因此第二次断下后查看堆栈,堆栈截图如下
一般相关的代码都是写在一起的(包括require引入方式),而xreader一看就像是一个什么插件库之类的东西🤔,因此我们重点看common这个库相关的调用。
一眼嫖见clickCopy,点击复制按钮,点击跳转过去
clickCopy: function() {
r.a.xsend(102222),
this.setVisible(!1),
this.setIsCopyActivated(!0)
},
一看第一个就是记录日志然后发送去提升体验感的,直接略过。第二个设置不可见(!1为false),应该是隐藏当前悬浮栏弹窗,最后一个设置复制状态,因为vue调试时候的问题,直接定位不过去,这里可以两种办法找到定位:
-
直接搜索setIsCopyActivated
一般没有人会定义两个同样名称的函数
这不就有了么
-
在这里下断点,断下后到堆栈里找位置
唔,注意一层层找,稍微有点麻烦,不过也不比搜索慢
断下后this
->setIsCopyActivated
->[[TargetFunction]]
->[[FunctionLocation]]
,点一下就同样可以跳过去。
emmm不过这里貌似不可行,他被翻译成native code 了,问题不大反正是一种思路😅
(这又不能怪我,都怪编译器把他编译成native code了,你瞧我们现在所在的clickCopy不是好好的么😕)
注:其原因应该是与函数的影响的参数类型有关,下面会说到
找到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的时候有没有豁然开朗?🤣下断点直接运行,果然成功断下。
果然是这么调用过来的,具体发生了什么都不知道,但是问题是确实解决了,接着就是重蹈覆辙(简称重复),比如找到cannotCopy赋值的地方(当然也可以使用刚刚的技巧直接赋值false,屡试不爽),看看能不能连什么isvip什么的一起连根解决
找了一圈没发现像刚刚那种定义函数,那就直接找关键词,最终,找到了下面的formatedText
有对cannotCopy
赋值的操作this.canCopy(t.length)
返回真就给cannotCopy
赋值false
,否则就是true
。这个canCopy函数名确实没毛病😉
这次寄存器里又可以找到定义的位置了,直接跳转过去。
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
,然后回车。。。。
然后就报错了,截图放下面👇了
翻译一下就是isVip定义了但是没有完全定义🤐
翻译一下:
没有分配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
直接运行,完美🎉🎉🎉
至此,全局终。
什么?要打开控制台不方便?想拿代码实现?
那我Greasy Fork上代码不是开源的么。。自己分析去啊💢
总结
我只负责将道理,讲的是人情事故,我讲是人情,但是翻车了那是事故。
那同理,我讲了,你听懂了,那是世故,那如果你没听懂,那也是事故,问题不大。
(摘自B站UP主“阿三解说”,跟楼主没有任何关系)
本文作者:吾爱破解@涛之雨
本来是打算web分类新成立发个简单的水水的来着,结果越写越多,顺便把vue相关的也都谢了一大堆,就当是我知道的第一个vue相关的破解教程叭,
晚安。
时2021年7月30日00:45:38
更新(修改了部分文案,修复了错别字的bug):
总结一下部分楼层主要内容:
-
cnblog同步地址:https://www.cnblogs.com/taozhiyu/p/15077779.html,不过我一般不会同步过去。。。
因为懒,
-
本文主要讲了3点内容:
- 条件断点注入JS
- vue相关网页的关键信息定位与查找
- Object的定义属性的学习与使用
-
本文的最终意义:
修改某云某盘都是假的,最主要的就是这种条件断点方法的运用
以前大家的代码都比较纯净,直接下个断点,写完控制台转手复制到油猴直接注入就行,
现在都是各种框架,各种打包,大部分都是每个函数在自己独立的空间内通过参数传入绑定数据,不是很好写代码,只能下断点-执行代码,
这个条件断点在逆向的时候还是很方便的,比如某些网站的疯狂debugger反调试,就可以直接置空,防止断下如图:
是不是很巧妙?是不是完美的就解决要不是fd替换大法去掉断点,要不就打开“禁用断点按钮”,那问题来了,我下不了断点,那还怎么下断点调试?
引用一下@大白痴先生 的在本帖回复【点我直达】:
有了你提供的这个方法真的是有无限可能啊,以前遇到这种情况我要么用fiddler完全自己返回修改了以后的js文件,要么用Chrome自带的overrides功能,但是都不方便。用这个自带的条件断点功能就方便多了。这个功能推广一下我估计也可以在其他工具里使用,比如IntelliJ IDEA什么的,但是具体怎么应用我还没想好。多谢楼主分享啊!
啊,多么好的楼主啊(开个玩笑🤣)
修订于:2021年8月1日11:46:08