网页抓取解密(腾讯课堂缓存文件分析进展缓存分析获取资源 )

优采云 发布时间: 2021-10-05 20:00

  网页抓取解密(腾讯课堂缓存文件分析进展缓存分析获取资源

)

  背景

  众所周知,腾讯课堂这样的视频是有时间限制的。

  如果我付了钱并想永远保留它,我该怎么办?

  录屏?也许这是一种思维方式。但是这个时间成本可能比较大。

  接下来,我将提供一个解锁加密视频的思路,仅供参考。

  发现

  对分析过程不感兴趣的可以跳到最后一节

  腾讯课堂网页版分析网络请求和过滤器关键词m3u8

  

  直接复制这个url,发现可以下载一个m3u8文件,但是只有几十kb,显然不是视频。以文本方式打开文件,查找类似配置的相关信息。那么什么是m3u8?

  关于 m3u8

  详细请参考文档m3u8文件格式详细解释

  m3u8文件作为媒体播放列表(Meida Playlist)时,其内部信息记录了一系列媒体片段资源。依次播放片段资源,充分展示多媒体资源。格式如下:

  #EXTM3U

#EXT-X-TARGETDURATION:10

#EXTINF:9.009,

http://media.example.com/first.ts

#EXTINF:9.009,

http://media.example.com/second.ts

#EXTINF:3.003,

http://media.example.com/third.ts

  分析网络请求并过滤关键词.ts

  原来m3u8是一个媒体播放器列表,里面收录了多个ts播放片段资源,再看看.ts视频片段相关的请求

  

  浏览器下载 .ts 视频文件

  直接访问ts视频的url,发现可以直接下载ts视频文件。But when the player is selected to play, it cannot be played. 可以肯定视频是加密的。看一下m3u8文件(以文本模式查看):

  ......

#EXT-X-KEY:METHOD=AES-128,URI="https://ke.qq.com/cgi-bin/qcloud/get_dk?edk=CiC61gXccR0pWqrCSxxx&fileId=5285890801738655666&keySource=VodBuildInKMS&token=dWluPTE0NDExNTIwMDM0NjIwNTA",IV=0x00000000000000000000000000000000

.......

  METHOD:该值是一个可枚举的字符串,用于指定加密方法。AES-128:表示使用 AES-128 进行加密。

  URI:指定密钥路径。密钥是一个 16 字节的数据。此键是必需参数,除非 METHOD 为 NONE。

  IV:该值为 128 位十六进制值。AES-128 加密和解密需要相同的 16 字节 IV 值。使用不同的IV值可以增加密码的强度。

  分析缓存文件分析进度获取缓存文件

  腾讯课堂缓存文件存放在/sdcard/Android/data//files/tencentedu/video/txdownload/

  可以通过adb把手机中的缓存文件拉到电脑上

  adb pull /sdcard/Android/data/com.tencent.edu/files/tencentedu/video/txdownload/

  分析缓存文件sqlite

  既然是sqlite文件,放到Navicat或者Datagrip里看看

  

  元数据和缓存,这里的重点是缓存表。从数据库中可以看出,数据库中插入了.ts视频文件片段、m3u8目录信息和解密密钥,与分析网页得到的数据基本一致。

  分析ts片段

  可以看出ts片段的格式是

  https://1258712167.vod2.myqcloud.com/fb8e6c92vodtranscq1258712167/af9366775285890801738655666/drm/v.f56150.ts?start=0&end=250431&type=mpegts

...

...

https://1258712167.vod2.myqcloud.com/fb8e6c92vodtranscq1258712167/af9366775285890801738655666/drm/v.f56150.ts?start=37710016&end=38045039&type=mpegts

  开始和结束是连续的,并确定片段的开始和结束

  修改链接为start=0&end=38045039(即end是最后一个片段的结尾),访问链接,但是提示需要签名信息。显然,它缺乏与符号相关的信息。可以轻松获取签到信息(ts从链接或m3u8文件中获取)

  分析待解决问题的进度 破解加密缓存文件,从sqlite文件中获取必要信息

  import sqlite3 as db

# 获取m3u8文件的下载链接,视频base_url,aes解密key

def get_url_key(sqlite_file):

con = db.connect(sqlite_file)

cu = con.cursor()

result = cu.execute('SELECT * FROM caches')

data = result.fetchall()

m3u8_url = data[0][0]

# video_base_url = data[2][0]

video_base_url = data[2][0].split("?")[0]

aes_key = data[1][1]

return m3u8_url, video_base_url, aes_key

  拼接完整的视频剪辑链接

  import m3u8

import re

def get_seg_uri(m3u8_file):

m3u8_obj = m3u8.load(m3u8_file)

seg_start_uri = m3u8_obj.segments[0].uri

seg_end_uri = m3u8_obj.segments[-1].uri

end_time = re.search('end=([0-9]*)', seg_end_uri).group(1)

pattern = r'end=[0-9]*'

seg_uri = re.sub(pattern, r'end={}'.format(end_time), seg_start_uri)

return seg_uri.split('?')[-1]

  引入第三方库m3u8解析库,详细请参考m3u8解析库github地址

  解密完整的视频文件

  import os

from Crypto.Cipher import AES

import requests

import threading

THIS_FILE_PATH = os.path.dirname(os.path.realpath(__file__))

OUTPUT_FILE_PATH = os.path.join(THIS_FILE_PATH, 'output')

SQLITE_FILE_PATH = os.path.join(THIS_FILE_PATH, 'sqlite')

def decrypt_video(sqlite_file):

print("thread start......")

file_saved_name = sqlite_file.split('.')[0] + ".mp4"

m3u8_url, video_base_url, aes_key = get_url_key(os.path.join(SQLITE_FILE_PATH, sqlite_file))

# print(m3u8_url, video_base_url, aes_key, sep='\n')

seg_uri = get_seg_uri(m3u8_url)

video_url = video_base_url + '?' + seg_uri

# print(video_url)

res = requests.get(video_url, stream=True)

video_stream = b''

for chunk in res.iter_content(chunk_size=1024 * 20):

if chunk:

video_stream += chunk

decrypted_video = AES.new(aes_key, AES.MODE_CBC).decrypt(video_stream)

with open(os.path.join(OUTPUT_FILE_PATH, file_saved_name), 'ab') as f:

f.write(decrypted_video)

print("thread end .....")

for file in os.listdir(SQLITE_FILE_PATH):

if file.endswith('sqlite'):

decrypt_video_thread = threading.Thread(target=decrypt_video, args=(file,))

decrypt_video_thread.start()

  介绍加密解密库Crypto。引导包遇到问题请参考python3中的Crypto ModuleNotFoundError

  一些结论:下载完整视频然后解密是受网络影响的。考虑直接转到 sqlite 文件以获取完整视频。16byte的码流可以叠加合并得到完整的视频,但是声音不能同步。它放弃了通过单个 ts 段解密多个视频。把一个视频看成100+个片段很不方便。如果sqlite文件缓存很久,方法无效,sign等信息可能无效。如果要解密视频文件,需要有很多最近缓存的sqlite文件。视频网站的视频加解密方法与此类似,下面以开课为例,其他类型的网站视频如果需要,可以自己尝试

  from Crypto.Cipher import AES

import requests

# key_url = "https://p.bokecc.com/servlet/hlskey?info=50E8E2C985FD43379C33DC5901307461&t=1601024556&key=92E401B7B37EC52BF51B9B71B15DABF8"

# key = requests.get(key_url)

# print(key.content)

# iv = 0x50E8E2C985FD43379C33DC5901307461

# iv = 0x50E8E2C985FD43379 # 取高16位

# iv = iv.to_bytes(length=16, byteorder='big')

# iv = b'0000000000000000' # 经过测试,iv在这里不起作用

for i in range(725):

video_url = "https://cd15-ccd1-2.play.bokecc.com/flvs/0118CC77B985808D/2020-07-29/50E8E2C985FD43379C33DC5901307461-20.ts?video={}&t=1601134081&key=B23C32BEF607876499FF469AA5B4B46C&tpl=10&tpt=112".format(i)

print("download video-{}....".format(i))

res = requests.get(video_url)

# hlskey通过key_url可下载到,也可通过requests.get下载,然后aes_key=key_res.content

with open("hlskey", "rb") as f:

key = f.read()

content_video_part = AES.new(key, AES.MODE_CBC).decrypt(res.content)

with open("kaikeba.mp4", 'ab') as f: # 追加保存解密结果

f.write(content_video_part)

  写在最后

  有任何问题请关注我的公众号CodeMonkeyJerry,欢迎留言

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线