最近有空研究了下小X通的视频协议,下面记录下研究过程
首先我们要了解下m3u8是什么
m3u8基础
首先我们需要了解什么时HLS,所谓HLS(HTTP Live Streaming)是一个由苹果公司提出的基于 HTTP 的流媒体网络传输协议。而m3u8是HLS协议的一部分,但是在直播,视频网站等用处很广泛。
HLS协议规定,视频的封装格式是TS(Transport Stream),除了TS视频文件本身,还定义了用来控制播放的M3U8文件(文本文件)。HLS协议的工作原理是把整个视频流分割成一个个小的TS格式视频文件来传输,在开始一个流媒体会话时,客户端会先下载一个包含TS文件URL地址的M3U8文件(相当于一个播放列表),给客户端用于下载TS文件。这样可以让用户更方便的选择视频节点播放,给用户更好的体验,其次提供了加密方式,可以更好的保护视频不被窃取。
下面是m3u8的一个基本字段
#EXTM3U:M3U8文件头,必须放在第一行。
EXT-X-MEDIA-SEQUENCE :第一个TS分片的序列号,一般情况下是0,但是在直播场景下,这个序列号标识直播段的起始位置; #EXT-X-MEDIA-SEQUENCE:0。
#EXT-X-TARGETDURATION:每个分片TS的最大的时长; #EXT-X-TARGETDURATION:10 ,表示每个分片的最大时长是10秒。
#EXT-X-ALLOW-CACHE:是否允许cache,#EXT-X-ALLOW-CACHE:YES 、#EXT-X-ALLOW-CACHE:NO,默认情况下是YES。
#EXT-X-ENDLIST:M3U8文件结束符。
#EXTINF:extra info,分片TS的信息,如时长,带宽等;一般情况下是 #EXTINF:<duration>,[<title>] 后面可以跟其他的信息,逗号之前是当前分片的TS时长。分片时长要小于 #EXT-X-TARGETDURATION 定义的值。
#EXT-X-VERSION:M3U8版本号。
#EXT-X-DISCONTINUITY:该标签表明其前一个切片与下一个切片之间存在中断。
#EXT-X-PLAYLIST-TYPE :表明流媒体类型。
#EXT-X-KEY:是否加密解析。例如:#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/video.key?token=xxx" 加密算法是AES-128,密钥通过请求 https://example.com/video.key?token=xxx 来获取,密钥请求回来以后存储在本地,并用于解密后续下载的TS视频文件。
请求流程
-
客户端发起对m3u8的请求,服务器在校验完成后会下载m3u8文件到本地。
-
客户端解析m3u8文件,在#EXT-X-KEY中找到密钥key地址,并访问拿到加密的密钥key。
-
客户端解析m3u8文件拿到分割文件的大小和对应ts文件地址,并访问拿到视频流。
-
客户端使用拿到的key地址和#EXT-X-KEY中对应的加密算法对视频流进行解密,播放视频。
所以我们看到这里真正重要的就几个部分,首先一定要找到m3u8文件的链接地址,然后从中找到#EXTINF和#EXT-X-KEY两个字段
-
#EXTIN字段中我们可以拿到ts协议流的分段大小信息,和视频流下载链接信息,并且可以通过start和end参数得到视频的最终大小
-
#EXT-X-KEY字段中我们可以拿到ts视频是否加密,如果加密可以拿到对应的加密方式和加密key地址。
-
最后用得到的key和VI对ts文件使用openssl解密即可。
实战分析
了解了HLS的加密过程下面我们对小X通进行一个分析,首先我们通过抓包拿到了这个m3u8的链接地址,前面做了很多校验,但是不属于这个视频加解密分析范畴,这里不做分析。拿到以后我们可以对字段进行分析。如下图:
下面对m3u8进行分析,我们可以得到如下信息:
-
#EXTIN中我们可以发现文件的分割大小,然后到最后可以看到文件的最终大小为141809727
v.f421220_0.ts?start=0&end=603679&type=mpegts
v.f421220_0.ts?start=141595968&end=141809727&type=mpegts
-
#EXT-X-KEY中我们可以发现文件的加密方式为AES-128的加密方式,对应得到下载key链接,并知道加密IV为0.
首先访问key地址,发现报错,提示缺少uid。
可以看到这里需要校验对应的uid,js代码中也可以看到,那通过自有验证抓取uid。
通过得到的uid信息得到对应的key文件
然后拼接拿到整个是视频流
https://encrypt-k-vod.xet.tech/*****/****/drm/v.f421220_0.ts?start=0&end=141809727&type=mpegts&sign=*****&t=***&us=***
使用openssl解密
openssl aes-128-cbc -d -in 001.ts -out 001_dec.ts -iv 00000000000000000000000000000000 -K ********************************
但是发现报错,解密失败。哈哈我猜也不会这么简单
报错分析
既然报错了,那由可能是这个几个地方存在问题
-
选择的加密工具openssl工具解密出错
-
加密所用的key或IV出错
-
视频原始文件出错
具体分析尝试三个点可以发现
-
我尝试了自己使用AES加密文件后使用openssl解密,发现没有问题,证明不是openssl的问题
-
视频文件在页面可以播放,证明不是视频的问题
那么问题就出在key或iv上了,继续分析。如果我是写系统的人,为了加密视频通常会选择如下方式:
-
对key的二次加密,再来解密视频
-
实现一个自己的加密解密算法,来解密视频
逻辑推导一下可以看到对key的二次加密最简单快速,且最终可以调用公共的解密库执行,如果自己实现难度高而且bug多,估计多数不会选择。
那么我们从二次解密出发,首先再js中找关键字encrypted关键字,找到如下关键点:
替换js并打印log尽然发现数组数据正好16位,可能是key文件
但是抓到的是十进制数据,转换为十六进制
printf '%x\n' 84 43 *******
然后用得到的十六进制key进行解密操作
openssl aes-128-cbc -d -in uu.ts -out uu_out.ts -K ********************* -iv 00000000000000000000000000000000
发现并无报错,证明解密成功
播放也没有问题,视频解密流程搞定。
为了避免不必要的麻烦,对key等关键部分做了处理,本文只做研究分析,不想带来不必要的麻烦。
小结
最后来个小结,对整个流程分析下来还是很顺畅,难点也不多,真正难的算是对js的分析,js已经做了混淆,很多代码中找到对应的解密地址还是很麻烦,花了不少时间。
最后对视频加防下载的一些思考
-
目前大部分视频网站都采用的是HLS来进行视频流的获取和播放,因为首先对应的资源很丰富,各个云平台厂商均有对应的接口,方便开发者快速的搭建,但是对应的加密方式还是由很多问题
-
首先是加密方式,有些小厂商也不会对视频进行加密处理,直接可以进行下载播放,这种破解很简单就不提了。
-
有些选择了对m3u8文件进行加密,但是个人感觉这个和对key二次加密是一样的,均可以在js中找到对应的解密方法和最终的key或m3u8文件,这个只是时间问题,毕竟js文件在客户端,服务器不可控。
-
即便解密对应的key很费时间,但是如果采用对浏览器hook可以解决所有的加密方法,毕竟最终还是要在网页进行播放,只要抓取最终的数据流并dump就可以拿到最终解密完成的视频。
-
个人感觉加水印等防止小白录屏是可以,但是对懂一点技术的其实整个破解只是时间和熟练问题,我测试有些监控是自己通过c实现了一个加密解密算法,对视频进行加密保存,解密读取流程,虽然很安全,但是对.dll进行逆向还是可以找到对应的key和加密算法,只是时间问题。
-
说了这么多感觉什么都不安全,都可以被破解,事实也确实是这样,但是我们可以经常更新加密算法和加密key,来增加破解者的时间成本,也是可行的,让攻击者自己放弃,哈哈差不多就这样。