JS调试之破解某视频网站字幕文件加密
一个还不错的视频网站,资源不多但质量都比较好
昨天协会群里有小伙伴在问怎么获取上面这个视频网站的字幕,其实大家对这个都不怎么感兴趣,我也不知道有啥用也没在意,今天上午他又发消息问了我很久,所以就试着去分析了下这个网站的字幕。大概调试了一个多小时,最后解密出了字幕文件,感觉整个分析过程很有意思且难度适中,我就把分析过程记录下来。

分析之前听小伙伴说之前能在控制台直接搜索到srt的字幕文件,现在就找不到了,所以我猜测多半是被加密了。看了一下很多视频下方的评论,视频资源的字幕应该是站长自己搞的,可能不想被别人盗用吧。
一开始我发现设置中可以调整字幕的颜色,大小,样式,说明是单独加载的字幕文件没错。我试着去定位这些字幕在页面出现的标签位置,直接搜索字幕里的内容。

发现在这样一个div标签里,观察发现每次新的字幕出现时,该dom节点的值都会发生改变。但是class没有改变,所以可以通过vjs-text-track-cue vjs-text-track-cue-zh-cn来定位。

因为要修改dom,肯定要绑定事件来监听,在element面板的右侧有Event Listeners可以看到,但是这里我把js都大概看了一下发现并不是加载字幕文件的js,所以这条路是走不通的。
还是回到network面板,肯定能找到字幕文件的请求。因为我对字幕文件的格式本身也不了解,所以先把每个请求都看了一遍,最后发现一个ddr的文件。

并且内容是乱码,这就很可疑了。

虽然我不是ddr的拓展名是个什么东西,但我大胆猜测这个应该就是字幕文件。那怎么验证这个猜想呢,我的思路是拦截这个请求,不让他加载,如果播放视频的时候没有字幕了,那说明这个肯定是字幕文件。

拦截这个请求,再次刷新页面,字幕消失了。

所以肯定这个是字幕文件了,那么接下来要做的就是如何将字幕解密出来。这个就要去分析js方法调用了,先解除拦截,让文件正常加载,分析有哪些调用。

在Initialor查看堆的调用,点上面的跟进该js文件中,在Sources面板我们直接来到了第440行也就是xhr.send()发起xhr请求。

一开始我看到这里的时候感觉这段代码就是发起ddr文件请求的,看到CryptoJS我猜测大概没错了,字幕应该就是在这里解密的。但还是先浏览了整个js的代码。

看到上面的代码中还出现了key,我想的是莫非这里才是?遇事不决下断点调试就好了,还是先在之前的地方下断点。
但是这里需要注意下断点的时候不要send方法那里!

刷新页面,点击让视频播放,这个时候才会去请求ddr文件。

可见这里确实是加载的字幕文件的内容,Scope窗口看值可能不太方便,直接在控制台输出即可。

这是我没想通的点,image???我在这里纠结了好久,甚至一度怀疑我的思路是不是错了!
但是反过来思考既然最后的呈现在观众面前的是正常的文字,那其中肯定做了转换的!肯定藏在其中的某一个部分!所以我试着将每一个中间变量打印出来。终于发现

虽然我最后都没弄明白为什么要以image的形式给后面调用,但是不用管以什么形式,解密的过程肯定是有的,所以试着在控制台输出一下中间变量,往往就有意想不到的收获。
既然已经调试出解密的方法了,那么如何在本地完成解密呢?
可以用Python把解密的代码重写一遍,但我觉得没必要,既然人家都写好了拿来用不就好?所以我就用nodejs将上面的代码简单改写了一下。
因为还用到了crypto-js和pako模块,所以需要执行下面的命令来安装:
npm install pako crypto-js
解密代码如下:
var CryptoJS = require("crypto-js"); var pako = require("pako"); var fs = require("fs") var eAB = fs.readFileSync('待解密的字幕文件名'); var wordArray = CryptoJS.lib.WordArray.create(eAB.slice(16)); var hexStr = Array.prototype.map.call(new Uint8Array(eAB.slice(0, 16)), x => ('00' + x.toString(16)).slice(-2)).join(''); var wordArray2 = CryptoJS.enc.Hex.parse(hexStr); var jsdec = CryptoJS.AES.decrypt({ciphertext:wordArray},wordArray2,{ iv: wordArray2, mode: CryptoJS.mode.CBC }); var binary_string = new Buffer(jsdec.toString(CryptoJS.enc.Base64), 'base64').toString('binary'); var len = binary_string.length; var bytes = new Uint8Array(len); for (var i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } var data = pako.ungzip(bytes.buffer,{to:'string'}); console.log(data);
这里做了一些小改动,比如把所有的let换成了var,nodejs中没有window对象,window.atob()实际是base64转换的函数,所以就用nodejs的中自带的函数转换即可。

总结:
整个JS调试过程难度适中,有些很多小trick是可以平时积累下来的。虽然我是搞安全,但也不知道什么时候开始调试起了前端,写起了插件,今天这篇文章本来是弄着玩的,最后还研究出来了,还是挺有成就感的。反正趁年轻各个方面的知识都积累一些总是好的嘛,相信以后工作中也会用得上。
赞赏微信赞赏
支付宝赞赏
10条评论