JS调试之破解某视频网站字幕文件加密

JS调试之破解某视频网站字幕文件加密

https://ddrk.me/

一个还不错的视频网站,资源不多但质量都比较好

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

分析之前听小伙伴说之前能在控制台直接搜索到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是可以平时积累下来的。虽然我是搞安全,但也不知道什么时候开始调试起了前端,写起了插件,今天这篇文章本来是弄着玩的,最后还研究出来了,还是挺有成就感的。反正趁年轻各个方面的知识都积累一些总是好的嘛,相信以后工作中也会用得上。

赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。

6条评论

t 发布于5:02 下午 - 7月 27, 2020

win7装完后要执行npm init,否则报错

匿名 发布于1:37 上午 - 7月 5, 2020

站长真牛逼!感谢!字母是srt格式的,解密完直接就能用!

避坑指南 发布于7:21 下午 - 7月 3, 2020

感觉很牛逼,看个热闹

萝卜 发布于12:29 上午 - 6月 28, 2020

tql

匿名 发布于11:07 上午 - 6月 22, 2020

安静‘ 发布于10:17 下午 - 6月 20, 2020

我就是那个文中小伙伴(~咳咳) 前来报道学习 Zgao赛高!