夜雨聆风学习资料网

ARTICLE · 1158230

当短剧App的请求体不再是 JSON:dreameshort 的 protobuf 逆向

当短剧App的请求体不再是 JSON:dreameshort 的 protobuf 逆向

本文记录 dreameshort 这款短剧 App 的逆向分析。它和常见的 App 不太一样:请求体不是 JSON,而是一段 protobuf 二进制。全文只讲整体思路与踩过的坑,不涉及具体实现、密钥和完整代码,抓包内容、敏感地址均已脱敏。

声明

本文所有内容仅供学习研究使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关。

本文未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责;若有侵权,请通过本平台联系作者立即删除。

设备及工具

Android 版本:13
设备信息:Pixel 4 XL(真机)
抓包工具:Charles
代理工具:Socksdroid
静态分析:jadx
运行环境:Python
目标 App:dreameshort

目标接口

搜索

详情(章节列表)

取流(视频播放地址)+ 字幕

一、抓包的第一个意外:请求体是二进制

正常抓包,会发现请求的 Content-Type 不是 application/json,而是 application/octet-stream,请求体是一段看不懂的二进制。
这里很容易第一反应以为是"加密了",然后一头扎进去找解密逻辑——方向就错了。它不是加密,而是protobuf 序列化:一种二进制的结构化数据格式。先认出这一点,是整篇的起点。

二、没有 .proto,怎么改请求体

protobuf 正常是要配套的 .proto 定义文件才能解析的,但逆向场景下拿不到这个文件。
好在 protobuf 的二进制线格式本身就自带字段编号和类型信息,所以**在没有 .proto 的情况下也能"盲解析"**出字段结构(字段号 → 值),再改回去。整体思路:
每个接口抓一条真实请求体,当作模板存下来→ 盲解析成「字段号 → 值」的结构→ 改掉需要改的字段(如搜索关键词、视频 id)→ 重新编码回 protobuf 二进制→ 算好签名,发出
一个很容易栽的坑:模板请求体通常以 hex 字符串存下来,这个 hex 必须单行完整,手动换行、复制时多一个少一个字符,重编码就会直接失败,而且报错不直观,排查很费时间。

三、签名:对请求体做哈希加盐

请求头里有个 sign 字段。规律并不复杂:它是对protobuf 请求体的字节做一次哈希(MD5),中间掺一段固定的盐(硬编码在 App 里)。
所以只要请求体一改,sign 就要跟着重算,否则服务端不认。盐的具体值这里不放。
protobuf 请求体字节 + 固定盐 → MD5 → sign

四、token 与付费墙

token 放在请求体的某个字段里,会过期,过期后重新抓包更新即可。
付费墙同样是服务端控制:详情接口里,付费集对应的取流字段是空的,服务端根本不下发,客户端识别到空就跳过。免费集正常返回,付费集靠会员账号,客户端这边没有可绕的口子。

五、视频是 DES 加密的

拿到的视频直链不是明文,而是DES-CBC 加密后的内容。
关键点在于:解密密钥不是固定写死的,而是由"详情里的一个字段"和"从 token 里解出的一个值"一起派生出来的(做哈希后取前若干字节,同时当 key 和 iv)。把这条派生关系理清,就能解出真实直链,再正常下载。具体字段和算法细节不放。
详情里的某字段 + 从 token 解出的某值→ 哈希后取前若干字节→ 作为 DES 的 key / iv→ 解出真实视频直链 → 正常下载

六、字幕

字幕是明文直链,在详情响应里直接能拿到,单独下载成 srt 文件即可,不烧进视频。两条线(视频、字幕)分开处理。

总结

这篇的核心难点和上一篇完全不在一个方向:不在反调试,而在**"请求体是 protobuf 二进制"这件事本身**。认出它、在没有 .proto 的情况下解析并重编码,是整篇的关键。至于签名,是常规的"请求体哈希加盐";视频是 DES 加密,难点在密钥的派生关系,而不是算法本身。
三条较实用的经验:
  1. 抓包看到 Content-Type是 octet-stream、请求体一片二进制,先别当成加密,很可能是 protobuf;
  2. 没有 .proto 也能靠盲解析改 protobuf 请求体,抓一条真实请求当模板最省事;
  3. 模板用 hex 存一定要单行完整,别手动折行,否则重编码会莫名失败。
以上为本次 dreameshort 逆向分析的整体思路记录。

相关学习资料