这篇文章上次修改于 515 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

2023/07/15 勘误

实际上借鉴widevine_eme_fingerprinting项目的做法并不能确定浏览器的唯一性

这是因为Chrome所使用的widevinecdm.dll每个版本(或者相邻的几个版本)都有一个相同的keybox

通过深入理解DRM(二)——了解Widevine与OEMCrypto可以知道,Device Id就是keybox的一部分

即:每个keybox都有唯一的Device Id,但是widevinecdm.dll大家用的都一样,所以同版本的widevinecdm.dll下,按照widevine_eme_fingerprinting的方法拿到的Device Id自然是一样的。

感谢eddie的指正!

注:Device Id也就是Serial Number

Ref: Widevine Partner License SDK v4.3.4.pdf

2023-07-15T01:24:14.png

这是windows chrome的请求,解析可以知道USER_DEVICESerialNumber就是后文获取的Cert Serial Number

>>> "\352\021\365K\036\014f\263\363\014>t\251\235VF".encode('latin-1').hex()
'ea11f54b1e0c66b3f30c3e74a99d5646'

2023-07-15T01:29:59.png

这是Android上的,注意这里的ServiceCertificateSerialNumber是服务端证书的,对应的是widevine_eme_fingerprinting/script_eme_full.js的serverCert ,即安卓上该方法不适用(目前看来)

>>> "\027\005\271\027\314\022\004\206\213\0063:/w*\214".encode('latin-1').hex()
'1705b917cc1204868b06333a2f772a8c'

2023-07-15T01:31:56.png

也许有人想知道这个怎么解析的

import wv_proto2_pb2 as wv_proto2
resp = bytes.fromhex('...')
license_resp = wv_proto2.SignedLicenseRequest()
license_resp.ParseFromString(resp)
print(license_resp)

还需要补充说明的是,根据文档说明device id确实是唯一的,但是这是对应于每一个keybox来说的,但这通常需要的设备具有TEE之类的功能,比如这里有很多keybox,可以看到device id都是不同的,即每个设备唯一

2023-07-15T02:01:32.png


原文

widevine通常用来做drm授权,具体能做什么还请自己查询资料

其工作原理简单来说就是:客户端内置一个RSA私钥,当然这个私钥通常是白盒实现或者存放在安全可信的硬件中,然后通过一系列的加解密,和授权服务器交互数据实现DRM物料的加密key的交换

当然其中的过程还是相当复杂的,总而言之很难把私钥搞到,即使搞到了,widevine官方也会很快下发新版本然后revoke这个私钥

在上述提到的授权及交换数据的过程中,会涉及到客户端的唯一标识符,也就是要确定客户端的唯一性(要不然怎么鉴权)

现代浏览器基本上都对widevine做了支持,同时也提供了一个叫EME的接口,在客户端可以通过该接口记录一些数据交换的信息

通过EME的接口,我们可以拿到一些关键性的数据,这里恰好有一个项目可以向你演示如何通过EME记录授权过程的关键数据获取:

先搞一个服务器,要https域名,把html放上去;搞定之后直接访问你的域名+index.html

然后你可以在console中看到一些日志,其中有什么company_name的这一条,复制下来

然后转成二进制保存,用项目中的utils/get_device_info.py做下信息提取

2023-06-14T03:30:19.png

然后你就能得到这样的结果,这里的Cert Serial Number就是你电脑浏览器的唯一标识符了,即使你使用隐身模式也不会改变

2023-06-14T03:32:52.png

那么这个我们怎么拿来为己所用呢?

简单来说就是你可以在记录之后,传到自己的服务器上,收集这个信息

你说客户端可以篡改这个消息?不怕,我们可以在收集到这个信息之后做验证

怎么操作呢?答案很简单:重放

通过抓包可以知道刚才那个log打印出来的就是这个请求的payload

2023-06-14T03:36:08.png

我们尝试修改Cert Serial Number的内容进行重放会发生什么?

如图,如果改变了原来的Cert Serial Number部分,响应将会出现INVALID_LICENSE_CHALLENGE

也就是说如果客户端想伪造这个Cert Serial Number部分,那么我们可以检查出来

2023-06-14T03:38:18.png

你可能想问Cert Serial Number部分之外的部分一起修改,有没有可能变成合法的?

答案是:当然可以,但前提条件是你把客户端的私钥搞出来,再做一系列的签名运算

前面也说了:

私钥通常是白盒实现或者存放在安全可信的硬件中

一般人真搞不出来:)

总结:

  • 借助EME记录关键的信息,上传自己的服务端
  • 在自己的服务端重放请求,确定payload合法性
  • 从payload中提取Cert Serial Number作为客户端唯一标识