WidevineDRM,现代流媒体的加密与解密
本帖最后由 Kagamia 于 2024-3-14 22:20 编辑试试抓取流媒体
给你一个网页,帮我把页面上这个视频下载下来。
https://reference.dashif.org/dash.js/latest/samples/drm/widevine.html
初识流媒体
用浏览器打开网页,按F12(或其他快捷键)打开开发者工具,刷新页面,你就可以在“网络”选项卡中看到所有网络请求了。
如果你对流媒体不够熟悉,这里我会简单讲述一下现代流媒体的常见术语和工作流程。
[*]流媒体,用大白话说就是在线音视频。
[*]流媒体可以简单分成两类:随时间流逝提供新内容的直播流(Live),和发布后内容不变的点播流(VOD),但技术上没有本质区别。
[*]现代流媒体早已不是网站直接提供一个mp4或视频文件,由浏览器下载、解析、解码、播放,这么简单的事情了。它有自己的封装格式和元数据声明格式。
[*]你最好能够区分容器(container)、编码(codec)、轨(track)、采样(sample)、切片(segment)这些基础概念。
[*]逻辑上,现代流媒体通常由“元数据及切片索引文件”和“切片文件”两部分构成。
[*]比较主流的元数据文件格式有m3u8(HLS)和mpd(Dash),但实际场合中,任何等效内容声明都可以作为元数据文件,不拘泥于实现,比如一串json。
[*]比较主流的切片文件格式有ts(transport stream,不是typescript辣)和m4s。
[*]B站直播仍在使用一种非常古老的技术:http-flv,不在本文的讨论范围内。
我在上一节提供的视频,就是由mp4Dash技术提供的,你可以在devtools中监视到“Manifest_1080p.mpd”元文件,以及init.mp4、0001.m4s等分片文件的请求。
mpd文件是一个标准xml格式的文本文件,即使你不去查schema,大概也可以看出,它声明了媒体总时长、切片时长、一系列不同编码、码率、尺寸的分轨信息。
事实上,想要获取一个轨,只要把对应轨上的init.mp4和xxxx.m4s切片文件连接起来,串成一个文件(是的,就这么简单暴力),就能作为一个合法的mp4文件播放。
当你凑齐了视频轨、音频轨、字幕轨后,就可以用ffmpeg命令行,把它们mux成一个文件,我交给你的任务就完成了。
事情就是这么简单。。。吗?当然!不信你试试!
当你拿着一个时长正确但播放花屏的文件回来时,我们就可以进入下一个章节了。
数字内容版权管理
数字内容版权管理(DRM),就是本文真正想讨论的内容。用大白话说就是,流媒体加密。
DRM技术其实早已有之,20多年前,微软主导的wmv文件格式及编码,就已经支持DRM了,它要求文件所有者在播放文件时,需通过播放器连接到指定的线上服务进行授权解密,才能够正常播放。
wmv格式非常顽强,在日本最大的AV制造商在线内容提供商DMM.com上,wmv结合silverlight播放器,一直是付费媒体文件的唯一分发方式,并一直坚持到现代浏览器抛弃NPAPI插件为止。
后来它们怎么办了呢?它们转成了HLS现代流媒体,也就是m3u8+ts格式。而m3u8协议标准支持一种简单的,基于AES-128-CBC的加密方式。
HLS with AES-128
m3u8也是一个文本文件,#开头的行代表元数据声明,如下示例标记声明了切片文件加密:
#EXT-X-KEY:METHOD=AES-128,URI="key.bin"
(此处参考文档:https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.2.4)
这个标记声明了对称加密使用的密钥文件路径,在实践中,m3u8文件与密钥文件的请求都可以添加请求鉴权,同时实现基于身份验证与数字内容的加密保护。
但是已经精通F12的你一扶眼镜:这不是掩耳盗铃么,只要我正常购买了数字内容,就可以请求到密钥,就可以解密,就可以二次分发。它保护了什么呢?
你他娘的说得太对了。但事实上,这种分发方式是有存在意义的,这就要说到内容分发网络(CDN)了。
对国内流媒体供应商有了解的同学一定知道,网费成本是非常高的,大多数流媒体供应商都会把内容分发任务委托给第三方CDN,减少服务器集中的请求,专业的事情交给专业的人来做,以提供更好的服务质量。
而对于版权内容,CDN分发方式依然适用。即使非授权用户获取了来自CDN的m3u8(有时它不需要签名或令牌鉴权),它依然无权请求密钥,对加密的分片媒体文件自然束手无策。
好了,你现在掌握了第一种现代流媒体的DRM方案和解密方式,但是它太Naive了,有没有更科学的方案呢?
不仅有,而且有的是。现存的DRM方案可能有几十种,比较主流的是如下三个方案:
[*]Apple主导的Fairplay
[*]Google主导的Widevine
[*]Microsoft主导的Playready
下面我会着重聊聊本文的标题,也就是Widevine。
初识WidevineDRM
从头讲解WideVine的来历与协议细节可能一天一夜都讲不完,所以我只会聊一些非常印象化的概念,让你理解它和上面的DRM方案有什么不同。
[*]Widevine是一个中心化的解决方案,它解决了之前密钥通信都是明文的根本安全问题。
[*]Widevine定义了设备的安全等级,从高到低为L1、L2、L3。这允许内容提供商可以按照客户设备安全等级,提供不同质量的加密内容,也可因设备在黑名单中拒绝提供内容。
[*]这里的设备可以是硬件设备,也可以是软件“设备”(如web浏览器)。
[*]至于加密通信,显然就是密码学那一套,非对称加密、对称加密、哈希、签名。
既然通信中引入了非对称加密与签名机制,那么一切监听、伪造、篡改通信内容的操作就变为不可能。
而L1级的安全设备,甚至做到通信载荷的生成和计算完全在安全操作系统中运行,所有运算不直接经过HostCpu,最大程度阻挠硬件调试破解。
就连L3级的web浏览器,也做到了最基本的防截图防录屏功能。
在这种固若金汤的保护下,有没有任何方式把它破解呢?
聪明如你会立即想到虚拟机录屏,RDP录屏,HDMI录屏等一系列方案。
然而翻录必然带来质量损耗(或许还无法绕过播放器水印),它可能成为潜在的保底方案,但并非是无可挑剔的。
另外很容易想到的是,直接破解设备,想方设法提取出设备信息,就可以从源头模拟与Widevine服务器通信了。
这种操作是可能的吗?
答案是,可。这个世界上存在很多方法,可以获取到L3设备信息。
WidevineDRM的解密
警告:本章节内容和任何提到的工具或链接,都有可能因数字千年版权法(DMCA)被要求删除。如果在你阅读文章之时相关链接失效,请自行按照关键字寻找镜像。
破解版权内容并不是一件光彩的事。虽然论坛秉承技术至上,但我不愿意剖析技术细节,那太长了!让我们直接进入实战吧。
第一步,我们要获取到device_client_id_blob和device_private_key两个文件,它描述了设备信息与私钥。
在历史上这不是唯一方法,其实很早有神秘方案可以直接借助浏览器抓取密钥,但我相信现在已经不适用了。
https://github.com/tomer8007/widevine-l3-decryptor
那么如何获取这两个文件呢?最简单的方案是,从一个安卓设备上提取。如果没有安卓设备,也可以从支持DRM的安卓虚拟机中提取。
https://cdm-project.com/How-To/Dumping-L3-from-Android
第二步,在网页调试工具中找到两个信息:请求许可的API地址,以及pssh(Protection System Specific Header)。
在示例页面中,这个地址很容易找到或猜测:https://drm-widevine-licensing.axtest.net/AcquireLicense
而pssh,其实可以在mpd文件中找到,它就是这一段落
<ContentProtection value="Widevine" schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh>AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQnrQFDeRLSAKTLifXUIPiZg==</cenc:pssh>
</ContentProtection>
pssh在xml中用base64表示,本质上是一段以proto2编码的二进制信息。
以及,整个Widevine协议都是以proto2编码的。至于具体的协议细节,一会我会告诉你怎么阅读。
第三步,使用Widevine客户端模拟获取密钥。
这可以有很多选择,你可以在开源社区用关键字搜到很多项目实现。
而我比较喜欢用这个:https://github.com/NooodyFR/WidevineClient
有时候,请求许可API会要求携带一些额外的header,你也需要在示例代码中实现。
比如,该示例中,API需要一个名为'X-Axdrm-Message'的header,在仿写代码时,需要从浏览器devtool中把对应的值拷贝过来。
var resp2 = PostData(licenseUrl, new Dictionary<string, string>()
{
{ "X-Axdrm-Message", "COPY-YOUR-OWN-VALUE" }
}, challenge);
这个项目没有任何文档,你需要稍微阅读一下代码理解逻辑,然后在运行文件夹下创建cdm/devices/your-device目录,把第一步获取的两个文件放进去,并且修改Widevine/CDM.cs,把你的设备设置为默认设备。
如果运气比较好,你就能在运行后拿到它的加密密钥,由两个32位长度的hex字符(也就是128-bit)由:连接
<id>:<key>
第四步,使用解密工具移除drm。
这依然有很多选择,我比较喜欢使用Bento4 SDK(https://www.bento4.com/downloads/)工具包,当然万能的ffmpeg也可以实现解密。
使用工具输入你从第二章节获取的,串联起来的分轨mp4文件,就可以获得解密后的文件了。
$ mp4decrypt --key <id>:<key> ./merge.mp4 ./merge-decrypt.mp4
# 或者
$ ffmpeg -decryption_key <key> -i ./merge.mp4 -codec copy ./merge-decrypt.mp4
总结
本文简述了现代流媒体和数字内容保护的基础知识,并通过一个示例介绍了一系列工具链,手把手教你如何解密并移除流媒体的DRM。
如果你是第一次接触现代流媒体或DRM,并按照本文内容动手实操且最终成功,那恭喜你学会了一个非常实用的生活小妙招。
如果你想要更进一步了解流媒体或DRM,除了仔细阅读上述程序源码外,还有如下标准文档供您参考:
https://developers.google.com/widevine/drm/overview
https://w3c.github.io/encrypted-media/
https://github.com/cryptonek/widevine-l3-decryptor/blob/master/license_protocol.proto
https://mpeg.chiariglione.org/standards/mpeg-dash
https://datatracker.ietf.org/doc/html/rfc8216
杂谈
这篇文章整整写了5个月才完成,中间陷入了名词解释陷阱,差点就要发一部万字流媒体百科出来了。
正如文章里所说的,破解版权内容并不是能拿上台面说的事情。我们在尊重版权方和创作者的同时,也会有私心想要把喜欢的内容分享出去让更多人知晓。
这篇文章也只是给自己过去的技术探索留一篇总结,以便日后查阅。
如果能帮助到您,那是我的荣幸。
好 每次在 Firefox 设置里勾选 Play DRM-controlled content 之后,
插件里就会多出一个 Widevine Content Decryption Module provided by Google Inc.
原来是这样阿,长见识了。
页:
[1]