遇到了一个网站的课想下载到本地看,发现视频的链接是m3u8格式的,直接扔到自已的下载工具里发现下载不下来,试了下N_m3u8DL也不行,那看来是m3u8本身有事了。看了下m3u8的内容,没有加密URI地址,但是EXT-X-KEY:METHOD=QINIU-PROTECTION-10,正常这里都写的是METHOD=AES-128啥的,那这个肯定是有加密,但密钥没写在m3u8文件里。
分析下请求,发现有m3u8链接,却没有从JSON信息中搜索到该链接,看了下JSON请求中,其中有一个链接的返回信息是这样:
这看起来就比较可疑了,一看就是加密字符串,啥信息还得写成这种样子,先搞一下这个看看,下断,跟踪,找到这里:
这里就是annex_path 和annex_secret的解密函数了,annex_path就是加密的m3u8链接,annex_secret就是加密的DRMKey,但这个DRMKey还不是m3u8_key,仍然是加密的还需要解密一次才是m3u8_key,先说一下如何解密annex_path 和annex_secret,上代码:
@staticmethod
def X(e, t= "R1ZX1kLKkKQFAWWM", n=True):
# 从json中得到的加密base64字符串,解密得到url或者是加密的key_list
t = MD5.new(t.encode('utf-8')).hexdigest()
# 获取前16个字符作为IV
i = t[:16].encode('utf-8')
# 获取后16个字符作为密钥
r = t[16:].encode('utf-8')
if n:
# 解密
cipher = AES.new(r, AES.MODE_CBC, i)
decrypted = unpad(cipher.decrypt(base64.b64decode(e)), AES.block_size)
return decrypted.decode('utf-8')
else:
# 加密
cipher = AES.new(r, AES.MODE_CBC, i)
encrypted = base64.b64encode(cipher.encrypt(pad(e.encode('utf-8'), AES.block_size))).decode('utf-8')
return encrypted
annex_secret解密后会得到一个类似这样的东西:[101, 101, 101, 102, 50, 101, 50, 49, 53, 97, 52, 102, 50, 52, 53, 56],像是一个列表,解密过程不讲了,直接上代码:
def get_m3u8_key(key_str_or_list):
# 通过一个列表 生成m3u8的 key_base64
def hex_string_to_ascii(hexstring):
bytes_data = bytes.fromhex(hexstring)
ascii_str = bytes_data.decode('ascii')
return ascii_str
aes_key = ""
if isinstance(key_str_or_list, str):
key_list = key_str_or_list.split(",")
for item in key_list:
tmp = hex(int(item.strip()))[2:].upper() # 10进制转16进制
tmp = hex_string_to_ascii(tmp)
aes_key += tmp
return aes_key
elif isinstance(key_str_or_list, list):
# print(f"长度:{len(key_str_or_list)}")
# print(f"aes_key: {aes_key}")
for item in key_str_or_list:
tmp = hex(int(item))[2:].upper() # 10进制转16进制
tmp = hex_string_to_ascii(tmp)
aes_key += tmp
# 得到一个16位的 bytes的aes_key,接下来转成base64
aes_key_bytes = aes_key.encode('utf-8')
aes_key_base64 = base64.b64encode(aes_key_bytes).decode('utf-8')
return aes_key_base64
有了m3u8_url,有了m3u8_key,再随便操作下,就可以愉快的批量下载了。
原文链接:http://www.itawp.com/528.html,转载请注明出处。