播放任意一个视频,F12找到m3u8的请求 发现其中没有Key的信息
图片1.png (27.85 KB, 下载次数: 0)
下载附件
2023-11-16 09:42 上传
这种我们从ts的启动器下手
图片2.png (45.67 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
点进去然后搜decryptdata.key、aes-128、buffer 等关键字
搜decryptdata.key 有5个结果 全部打断点 刷新
图片3.png (49.41 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
断住了 这个this.decryptkey 非常像解密时用的key
可以使用m3u8下载工具 验证一下想法是不是对的
首先将this.decryptkey转为十六进制字符串,代码如下
[Python] 纯文本查看 复制代码decryptkey = [53, 98, 97, 53, 97, 100, 50, 53, 51, 54, 99, 57, 50, 55, 100, 54]
hex_string = bytes(decryptkey).hex() # 35626135616432353336633932376436
使用工具下载(这里十六进制key会被自动Base64编码)
图片4.png (59.25 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
结果可正常下载 正常播放
至此 key已经找到 接下来需要找key生成的地方
上面得知this.decryptkey = t.decryptdata.key = new Uint8Array(this.qiniuDRMKey)
文件内搜qiniuDRMKey = 只有一个结果
图片5.png (39.86 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
往上跟找e.config
图片6.png (165.15 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
t = this
t.config = e
e里面有qiniuDRMKey
往上跟找e
图片7.png (65.5 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
又一个this.config 往上找this.config.DRMKey
图片8.png (70.85 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
r = this
r.config = t
t 里面有DRMKey t是传过来的 继续往上跟...
图片9.png (93.59 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
一路跟 跟到这 这个e里面有两个关键字段 一个是key 一个m3u8的url(意外惊喜)
继续往上跟 要换js文件了 不行了来感觉了
图片10.png (82.31 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
成功找到了key、url的生成位置
这里o 和 v 分别是加密后的url 和key
进入关键函数X看一下 是个AES加解密函数。
图片11.png (21.86 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
X接收三个参数 e=要解密的内容 t=固定字符串 n控制加密还是解密
接下来就是找被加密的url 和key字符串 也就是o 和v
一般这两个参数都是通过api返回的,可以用抓包工具搜索一下(这里用的Charles)
图片12.png (33.23 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
这里Search In 只勾选 Response Body
图片13.png (57.51 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
这里有两个搜索结果 一个html 一个api 两个里面都包含加密内容
图片14.png (24.7 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
点开api的Response Body 可以看到 o、v 都是该api返回
至此整个分析结束 接下来我们来实现一下解密算法
JS实现:
[JavaScript] 纯文本查看 复制代码const CryptoJS = require('crypto-js');
function decrypt(e) {
var t = CryptoJS.MD5("固定字符串").toString();
var i = CryptoJS.enc.Utf8.parse(t.substring(0, 16));
var r = r = CryptoJS.enc.Utf8.parse(t.substring(16));
return CryptoJS.AES.decrypt(e, r, {
iv: i,
padding: CryptoJS.pad.Pkcs7,
}).toString(CryptoJS.enc.Utf8);
}
var annex_secret = '';
var key = JSON.parse(decrypt(annex_secret));
console.log(key)
图片15.png (19.24 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
对比控制台执行结果 完全一致
Python 实现:
[Python] 纯文本查看 复制代码from utils import AESCrypto
import hashlib
import json
def get_md5_string(s: str):
return hashlib.md5(s.encode('utf-8')).hexdigest()
def decrypt(e: str):
t = get_md5_string("固定字符串")
i, r = t[:16], t[16:]
cipher = AESCrypto(key=r, mode='CBC', padding='Pkcs7')
return cipher.decrypt(e, iv=i)
if __name__ == '__main__':
annex_secret = ''
key = json.loads(decrypt(annex_secret))
print(key)
对比下结果也是一样的
图片16.png (58.08 KB, 下载次数: 0)
下载附件
2023-11-16 09:51 上传
最后:
其实刚开始的时候就发现了在控制台里面有key的log信息...
本着学习的态度 还是从头到尾撸了一遍...