保利威视频云(polyv.net) HLS视频解密

保利威视频云(polyv.net) HLS视频解密

通过chrome抓包可以看到几个重要文件,其中josn是配置文件,m3u8中是加密的视频文件链接,key是播放密钥。

json文件是加密内容。json解密的key和iv是文件名的md5值。
解密后的内容中包含m3u8的链接、解密.key文件的参数。

.key和.m3u8的文件的内容:

播放密钥(.key)有32字节,解密需要的ase-key为md5(seed_const)[0:16],aes-iv固定。

使用python解密key文件:

1
2
3
4
5
6
7
8
9
10
from M2Crypto.EVP import Cipher
import binascii

data = open('e2fe557cf3ba2677493ca47ed4f601f6_1.key','rb').read()
key = binascii.unhexlify('36663439323266343535363831363161')
iv = binascii.unhexlify('0204060a0e161a22262e3a0e0a060402')
c = Cipher(alg = 'aes_128_cbc', key = key, iv = iv, op = 0)
buf = c.update(data)
buf = buf + c.final()
print binascii.hexlify(buf)

解密后的密钥为:f7b6d9dc18836edee88e06d8db43dc60,将密钥写入文件,将ts文件下载到本地,编辑m3u8中的密钥链接、ts视频链接。

使用ffmpeg保存成mp4文件:

1
ffmpeg -allowed_extensions ALL -i test.m3u8  -vcodec copy -acodec copy test.mp4

解密成功:

附: 完整解密流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from M2Crypto.EVP import Cipher
import binascii
import json
import base64
import hashlib

def md5(s):
return hashlib.md5(s).hexdigest()

# 将json文件名的md5分成两部分,分别作为key,iv,解密json文件内容
config_json_filename = '/Users/zhighest/tmp/hls/e2fe557cf3ba2677493ca47ed4f601f6_e.json'
#s = 'e2fe557cf3ba2677493ca47ed4f601f6_e'
s = config_json_filename.split('/')[-1].strip('.json')
filename_md5 = md5(s)
txt = open(config_json_filename).read()
d = json.loads(txt)
data = d.get('body')
data = binascii.unhexlify(data)
key = filename_md5[0:16]
iv = filename_md5[16:32]
cipher = Cipher(alg = 'aes_128_cbc', key = key, iv = iv, op = 0)
buf = cipher.update(data)
buf = buf + cipher.final()

# json中包含m3u8的链接地址
# seed_const与.key文件的解密有关
# .key文件的解密密钥为md5(seed_const)[0:16], iv固定
config_json_str = base64.b64decode(buf)
config_json = json.loads(config_json_str)
seed_const = config_json.get('seed_const')
print 'seed_const',seed_const
aes_key_hex = md5(str(seed_const))
print aes_key_hex
key_filename = '/Users/zhighest/tmp/hls/e2fe557cf3ba2677493ca47ed4f601f6_1.key'
data = open(key_filename, 'rb').read()

key = aes_key_hex[0:16]
iv = binascii.unhexlify('01020305070b0d1113171d0705030201')
data = open(key_filename, 'rb').read()
c = Cipher(alg = 'aes_128_cbc', key = key, iv = iv, op = 0)
buf = c.update(data)
buf = buf + c.final()

# .key文件解密后就是最终解密视频文件的密钥了,iv在m3u8中
ts_filename = '/Users/zhighest/tmp/hls/e2fe557cf3ba2677493ca47ed4f601f6_1_0.ts'
iv = binascii.unhexlify('0f302b9ff60d53afd4cb608a8fef1d3a')
key = buf
data = open(ts_filename, 'rb').read()
c = Cipher(alg = 'aes_128_cbc', key = key, iv = iv, op = 0)
buf = c.update(data)
buf = buf + c.final()

# 保存解密后的文件
with open('/Users/zhighest/tmp/hls/e2fe557cf3ba2677493ca47ed4f601f6_1_0_decrypted.ts', 'wb') as fo:
fo.write(buf)