目录
以慕课网下载的视频为例:下载到手机后得到N个.all结尾的文件夹,每个文件夹为一个视频,里面包含多个ts文件,json.txt,key.hxk,down.m3u
8。如下图
第一步,分析 m3u8文件
分析down.m3u8,
拿着URI那串地址去请求,提示tonken过期。这边可以用模拟http请求,然后获取到tonken,再请求这串URI,这边嫌麻烦就不做了,但是我们可以去web抓取http请求呀,于是兴高采烈的,打开开发者工具,过滤XHR
but 得到的是一串被加密过的字符串,并不是AES的key...
反过来思考,既然下载视频,当然是为了离线观看,所以解密操作必定在客户端。
首选当然是去反编译App,噼里啪啦下载App,打开jadx,完蛋,卡住了,电脑呼呼的叫,这个方法行不通。
另外一个web端呢,随便打开一个视频播放,打开开发者工具,找到播放器代码所在文件各种断点,调试
理论上就是这个js文件,在解密,一键格式化JS复制下来。搜索一下关键字encrypt等等,还真有
第二步、获取解密key
把对应的函数拷贝出来保存,死马当活马医。那总得验证一下是不是这个函数,于是,把URI请求得到的值进行解密
这看起来像个map,但是在js是Uint8Array ,长度刚好是16,总算有所收获。但是在python里面没有这种类型,
看着和字典类似,试一下,顺便看一下js,Uint8Array 转化为字符串,是通过String.fromCharCode将数字转化为字符,拼接字符。那python肯定也有,了解一下chr()函数,动手:
注意:需要从key为0的位置,开始读取字典。
得到字符数组之后,转化为字符串,写到文件video.key,大小只要16B就正确,文件与down.m3u8同级。
做到这里,似乎漏掉了一个key.hxk文件的存在,里面也是一个字符串,不知道和URI请求下来的一不一样,肉眼能直接看出了,他们不一样,but,解密后呢,于是,我去找到web端对应的播放地址,抓取请求,拿到“Akmq2hpCJ9c+DBCnbRVgCjx93B5zFwcxQr3vBQ==b3P9dO9JYFL3QhQsJjCDexAV”
key.hxk得到“Z2mkmPmGeWpjNVReDFQiZVT5AxVjHeMeMhVcDXY2ZY4MYz8gyQ==WYb1A7XkJIAv”
def runJs(str):
js = execjs.compile(readFile('decypt.js'))
result = js.call('n', str, 1)
print result
if __name__ == '__main__':
key = "Akmq2hpCJ9c+DBCnbRVgCjx93B5zFwcxQr3vBQ==b3P9dO9JYFL3QhQsJjCDexAV"
print runJs(key)
key = "Z2mkmPmGeWpjNVReDFQiZVT5AxVjHeMeMhVcDXY2ZY4MYz8gyQ==WYb1A7XkJIAv"
print runJs(key)
果然,一模一样。到这里,我们已经拿到解密函数和 解密key。
第三部,解密合成mp4
这里选用FFmpeg
命令:ffmpeg -allowed_extensions ALL -i down.m3u8 -c copy output.mp4
将down.m3u8里面#EXT-X-KEY这行的URI替换成“vide.key”
执行命令
喝杯茶,等一小会儿
当前目录下就生成out.mp4文件,打开播放器,就可以播放了,ffmpeg果然牛批
第四步,按课程重命名
打开json.txt,是个json格式字符串
chapter_seq章,section_seq节,sectionName课程名称