虎牙、B站APP流量分析

虎牙直播

img

对于直播来说,拉流采用的时http-flv。在建立连接过程中,建立TCP连接以及发送GET请求即可。可以从历史的GET请求携带的中获取直播源并进行请求。

B站直播

img

建立连接的过程中需要建立TCP连接后进行协商tls加密信息。

对于断开重连的场景,有两种方式:

session id会话复用:对于已经建立的SSL会话,使用session id为key(session id来自第一次请求的server hello中的session id字段),主密钥为value组成一对键值,保存在本地,服务器和客户端都保存一份。

当第二次握手时,客户端若想使用会话复用,则发起的client hello中session id会置上对应的值,服务器收到这个client hello,解析session id,查找本地是否有该session id,如果有,判断当前的加密套件和上个会话的加密套件是否一致,一致则允许使用会话复用,于是自己的server hello 中session id也置上和client hello中一样的值。

session ticket会话复用:客户端和服务器端建立了一次完整的握手过程后,服务器端将本次的会话数据进行加密,例如会话标识符、证书、密码套件和主密钥等,加密后生成一个ticket票据,并将票据通过NewSessionTicket子消息发送给客户端,由客户端来保存,下一次连接时客户端如果希望恢复上一次会话而不是重新进行握手,就将“票据”一起发送给服务器端,待服务器端解密校验无误后,进行一次简短的握手,恢复上一次会话。

这种方式适用于重连的服务器变化的情况。

B站点播

基于UDP的DTLS、QUIC协议占主要部分。

img

推流

对于推流,则以RTMP协议为主:

B站推流

img

虎牙推流

img

RTMP的建联过程

img

握手阶段

  • 客户端发送 C0+C1
  • 服务端发送 S0+S1+S2
  • 客户端发送 C2

建立网络连接:服务端反馈确认窗口大小、带宽大小

  • ①、客户端发起连接请求
  • ②、服务器设置客户端的应答窗口大小
  • ③、服务器设置客户端的发送带宽大小
  • ④、服务器设置客户端的接收块大小
  • ⑤、服务器响应连接结果
  • ⑥、客户端设置服务器的接收块大小

建立网络流

  • 客户端发送命令消息中的“创建流” (createStream) 命令到服务器端。
  • 服务器端接收到“创建流” 命令后, 发送命令消息中的“结果” (_result), 通知客户端流的状态
  • 客户端向服务器获取指定流的长度

播放/推流

  • 客户端发送命令消息中的“推流” (publish()) 命令到服务器。
  • 服务器发送用户控制消息中的 “stream begin” ,告知客户端流 ID
  • 服务器发送客户端要播放的音频和视频数据

HTTP-FLV

HTTP-FLV 是将音视频数据以 FLV 文件格式进行封装,再将 FLV 格式数据封装在 HTTP 协议中进行传输的一种流媒体传输方式。

HTTP-FLV 被广泛采用的原因:

  1. HTTP 优点: a. 一些防火墙会墙掉 RTMP 或者其他的一些协议,但是防火墙对 HTTP 非常友好,不会墙掉 HTTP,因此基于 HTTP 传输的成功率更高。
  2. FLV 优点: a. MP4、MKV 等封装格式将音视频数据和音视频元数据、索引、时间戳等分开存放,必须拿到完整的音视频文件才能播放,因为里面的单个音视频数据块不带有时间戳信息,播放器不能将这些没有时间戳信息的数据块连续起来,因此不能实时的解码播放。(当然 MP4 后来扩展了 FMP4 用于流媒体) b. FLV 格式的 FLV Tag Header 中携带时间戳,FLV 将每一帧音视频数据(Tag Body)封装成包含时间戳等音视频元数据(Tag Header)的数据包(Tag)。当播放器拿到 Tag 后,可根据时间戳等音视频元数据进行解码和播放。

HTTP-FLV 的实现原理: HTTP-FLV 利用 HTTP/1.1 分块传输机制发送 FLV 数据。虽然直播服务器无法知道直播流的长度,但是 HTTP/1.1 分块传输机制可以不填写 content-length 字段而是携带 Transfer-Encoding: chunked 字段,这样客户端就会一直接受数据。

img

解析后的协议使用的依然是http-flv

img

可以通过设置SSLKEYLOGFILE的环境变量, 就能够获取到每次对话产生的log文件。利用每次对话中,存储下来的log来解密报文。

设置SSLKEYLOGFILE环境变量

img

通过ssl.log中的client random(在TLS握手期间由客户端发送的随机非加密值)来标识会话,并从中获取对应的密钥。

img

切换操作流程:

拉流端:http-flv

建立TCP连接;

建立TLS连接(对于B站APP);

通过首次建立连接时收集到的session id或者是session ticket进行会话恢复。

发出HTTP-GET请求FLV视频数据;

通过历史信息获取直播源并生成URI请求。

推流端:RTMP

建立TCP连接;

RTMP握手;

建立网络连接:客户端与服务端交换确认窗口大小、带宽大小;

建立网络流;

设置SSLKEYLOGFILE环境变量

img

在Wireshark中通过”编辑->首选项->Protocols->TLS“配置TLS协议中的(Pre)-Master-Secret log filename,将其配置成环境变量SSLKEYLOGFILE指向的log文件。

img

再重新进行抓包即可解析出TLS文件。

对话窗不能是通过恢复协议而恢复的窗口, 报文中一定要包含有 ClientKeyExchange的握手消息

如果是使用RSA密钥交换算法,那么报文中一定要包含ClientKeyExchange的消息, 这样wireshark 才能拿到客户端产生的随机数(预主密钥),才能把密钥和报文匹配起来, 而恢复会话就很难确定之前的密钥是什么值了。


虎牙、B站APP流量分析
http://example.com/2024/03/07/虎牙、B站APP流量分析/
作者
Nuts
发布于
2024年3月7日
许可协议