朋友有个考研的资料快过期了,大几千买的课,过期就没了怪可惜的,让帮看一下,这记录一下分析过程
首先看一下直播回放,开Reqable抓包,然后播放回放,包里面发现有ts文件,但没有m3u8文件,
看到一个vodRecordBuffer链接,数据是这样的:
不知道是些啥,但加密了一定不正常,浏览器下XHR断点:/api/v1/vodRecordBuffer,正常断住,但是。。。却断在debugger位置了,看来是开了反调试功能,看了下混淆的文件结构,
根据经验这种混淆中带debugger的话关键先去掉定时器setInterval,直接替换原js将setInterval时间延长,在debugger中断时跳过一下便可,差不多类似这样:
// 定期检查是否存在调试器
setInterval(function() {
if(debugCheck()) {
debugger;
}
}, 1000000000);
然后在断住的debugger处右击选择不在此处断住。接下来经过一会的单步执行,跟踪到关键代码处:
大体意思是将 api/v 1/vodRecordBuffer? stream=返回的数据进行 base64 解码后得到 bytes 数据,再用 aes 解密,密钥每天更新的。这种格式:b’2024.~12,.11, ().’
# 根据JS写成python代码:
def live_vodRecordBuffer_decrypt(data):
# 密钥是动态的,取年月日加一些特殊字符组成。
# 解密此类链接:/api/v1/vodRecordBuffer?stream=2024090965300415&platform=bos&date=2024-12-09&encrypt=0&curtime=1733709707
#
def to_date(value):
return str(value).zfill(2) # 将数字转换为两位数的字符串,不足两位时前面补零
# Get current date
n = datetime.datetime.now()
year = n.year
month = n.month
day = n.day
a = f"{to_date(year)}.~{to_date(month)},.{to_date(day)},()."
decrypt_key = a.encode('utf-8')
print(decrypt_key)
cipher = AES.new(decrypt_key, AES.MODE_CBC, decrypt_key)
decrypted_padded = cipher.decrypt(base64.b64decode(data))
decrypted = unpad(decrypted_padded, AES.block_size)
return decrypted.decode('utf-8')
这样经过aes解密后得到的数据就是m3u8的内容了,到这步已经可以正常请求下载到头像视频带音频了,但我们要求的是批量的操作,手动这么整显然效率太低了,我们继续再找一下api/v 1/vodRecordBuffer?这个请求是如何生成的,继续往 上找,看到一个/api/user/watch_demand请求,返回信息是这样子的:
再用上面的方式去解密,尝试下失败了,重新在/api/user/watch_demand处下断,这里代码是未加密的那就很明显了
大体意思是生成一个16位的随机数,这里假设是Bvl73GGqyZJyGvGY,然后将此字符串添加前缀offcn|||,得到新的字符串offcn|||Bvl73GGqyZJyGvGY;获取/api/v1/public_key的加密内容,使用密钥wwwoffcncloudcom进行aes cbc解密,得到一个公钥’MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS6VbgEpOwVc8jXYx/uL6ItMS6\naBPVo8fvw0pd90jLJYvfJcFJdYVFh6JPRdpGhlIrED45VdsktcJvJj0cLNI5ZIZ6\n80aS6JTFe3ScBY4Mi7bLKzBNYtMBtnkAFbMmWlCXV4qzZYg8+xNktY5ClZZCvZzz\nlaU5djtUSoxTLkxcmwIDAQAB’,利用公钥加密上面得到的字符串发送请求给/api/user/watch_demand。
那么返回的加密字符串,直接用上面生成的16位随机数进行解密便可,这里有好多方式,比较省事的可以直接把16位随机数固定下来,这样直接用固定的密钥解密返回值便可。
def watch_demand_decrypt(data):
# 得到的数据就可以用此密钥来解密。
key = b'Bvl73GGqyZJyGvGY'
cipher = AES.new(key, AES.MODE_CBC, key)
decrypted_padded = cipher.decrypt(base64.b64decode(data))
decrypted = unpad(decrypted_padded, AES.block_size)
return decrypted.decode('utf-8')
解密后发现内容中确定包含了api/v 1/vodRecordBuffer的链接,这样有了m3u8的内容,有了图片和白板的内容,根据这三部分写一个合成视频的代码,将此三部分合并成一个视频,就大功告成了。
原文链接:http://www.itawp.com/553.html,转载请注明出处。
评论0