ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

dy web端直播弹幕逆向学习:protobuf 抓包解析与字段还原

dy web端直播弹幕逆向学习:protobuf 抓包解析与字段还原 1. 从浏览器 Network 面板看懂 dy web 端直播弹幕请求dy web 端直播间里弹幕是一条条实时刷出来的但你在 Network 面板里点开某条请求Response 里看到的往往是一堆乱码或者二进制。这不是接口坏了而是它用了 protobuf 作为载荷格式。protobuf 是什么你可以把它理解成一种「压缩过的结构化数据」——字段名不写在数据里只写字段编号和值接收方靠一份 .proto 描述文件把编号翻译回字段名。它能做什么让弹幕这种高频、小体积的消息传输更省带宽。适合谁看想搞懂 web 端实时消息链路、想学 protobuf 逆向分析流程的开发者。我试过直接盯着那串二进制看完全没头绪后来才意识到得先找到「谁在解码」。浏览器能显示弹幕说明前端 JS 里一定有一段代码把二进制还原成了对象。所以逆向的第一步不是硬啃字节而是顺着请求找到解码入口再反推字段结构。这篇就按这个思路走先定位弹幕请求再抓 protobuf 载荷然后用脚本还原字段最后跑一次完整的消息验证。整个过程只做学习分析不涉及任何绕过平台限制的操作。需要提前说明一点web 端直播间的可用性和你本地网络环境有关如果页面本身加载异常先确认基础网络能正常访问页面再谈抓包。下面所有操作都在浏览器开发者工具和本地 Python 环境里完成。2. TaoToken 前置准备给逆向脚本配一个稳定的模型调用入口逆向过程中经常需要让脚本或助手帮你解释一段 JS、补全 .proto 字段、或者把还原出来的 JSON 做二次分析。这时候如果每次都要手动切模型、管密钥节奏很容易断。我的做法是先把调用入口统一好后面写解码脚本时直接复用。TaoToken 在这里的角色就是一个统一的 API 入口兼容常见的模型调用格式。你可以在官网了解它的能力范围https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。真正写代码时用的是 API 地址https://taotoken.net/api 注意这个地址不带跟踪参数直接填进配置即可。如果你只是偶尔问几个问题用模型对话页面就够了https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。但如果你打算长期做逆向分析、写脚本、跑 Agent 辅助建议直接上 Coding Plan额度更稳https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。密钥在控制台里建https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 建完去 API Keys 页面复制https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。接入细节看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。这里要提醒一句TaoToken 是模型调用入口不是抓包工具也不参与你和目标站点之间的任何网络请求。抓包、解码这些事仍然在你自己浏览器和本地脚本里完成。3. 可复制配置抓包过滤条件与 protobuf 解码脚本骨架3.1 浏览器侧定位弹幕请求打开直播间按 F12 进 Network 面板勾选 Fetch/XHR然后在过滤框里输入关键词。弹幕相关的请求路径通常带有im、fetch、message这类字样你可以先用下面的过滤条件缩小范围im/fetch如果列表还是太多就按请求类型再筛一层只看 POST并且按 Size 排序弹幕长连接拉取的响应体通常体积不大但会周期性出现。找到候选请求后点开看 Response如果显示的是乱码或提示二进制基本可以确认是 protobuf。请求参数里几个关键字段的作用可以对照下表理解字段作用备注resp_content_type声明响应格式值为 protobuf 时说明返回二进制room_id直播间房间号需先通过另一个接口获取cursor翻页游标从上一包 protobuf 响应里取internal_ext内部扩展字段同样来自响应体msToken会话令牌短时间内可复用X-Bogus请求签名由前面若干字段参与计算_signature签名参数实测不校验可忽略3.2 用 Python 写一个 protobuf 解码骨架确认是 protobuf 后本地装好依赖。如果运行时报AttributeError: NoneType object has no attribute message_types_by_name执行下面这条命令升级即可pip install --upgrade protobuf解码脚本的骨架长这样核心思路是把抓到的二进制载荷喂给解析器再按字段编号逐层展开import requests from google.protobuf.descriptor_pb2 import FileDescriptorProto # 这里放你从 JS 里还原出来的 .proto 描述 # 实际使用时用 protoc 编译成 _pb2.py 后 import # from dy_im_pb2 import Response def decode_payload(raw_bytes): resp Response() resp.ParseFromString(raw_bytes) return resp def walk_message(msg, depth0): indent * depth for field, value in msg.ListFields(): if hasattr(value, ListFields): print(f{indent}{field.name}:) walk_message(value, depth 1) else: print(f{indent}{field.name}: {value}) if __name__ __main__: # raw 为从 Network 面板复制出来的二进制响应 with open(danmu.bin, rb) as f: raw f.read() result decode_payload(raw) walk_message(result)3.3 还原 .proto 字段结构在浏览器 Sources 面板全局搜索protobuf或decode找到解码函数后打断点单步跟进去就能看到它读取了哪些字段编号。把这些编号和你在响应里看到的值对应起来写成 .proto 文件。下面是一段简化后的结构示例syntax proto3; message Response { repeated Message messages 1; string cursor 2; string internal_ext 3; } message Message { string method 1; bytes payload 2; int64 msg_id 3; } message ChatMessage { string content 1; User user 2; } message User { int64 id 1; string nickname 2; }字段编号不是猜的是跟着断点里实际读取的 tag 值填的。填错编号会导致解析出来的字段名对不上但值还在这时候回头核对断点即可。4. 验证请求跑一次完整的弹幕消息还原配置写好后先做一次最小验证。把 Network 里抓到的那条弹幕响应体保存成danmu.bin然后运行第 3 节的脚本。如果 .proto 结构正确你会看到类似下面的输出messages: method: WebcastChatMessage payload: content: 主播好厉害 user: id: 123456789 nickname: 某用户 cursor: CjRiYW... internal_ext: CnRi...看到content和nickname被正确还原说明字段映射是对的。接下来做一次动态验证保持脚本运行在直播间发一条测试弹幕重新抓一包确认新消息也能被解析出来。这一步能验证你的字段结构不是只对某一条数据生效。如果你想把还原结果接到模型做进一步分析比如统计弹幕情绪或提取关键词可以在脚本里把解析出的 JSON 通过 TaoToken 的 API 发出去。Base URL 填https://taotoken.net/apiKey 用你在 API Keys 页面建的那个Model ID 按文档里支持的模型名填。三件套齐了就能跑通。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth做这类逆向分析报错基本集中在几个地方对照着排会快很多。401 Unauthorized如果你是在调用模型接口时遇到先检查 API Key 是否复制完整、有没有多余空格以及 Base URL 是不是写成了带路径的地址。TaoToken 的 API 地址就是https://taotoken.net/api不要自己拼/v1之类的后缀具体以文档为准。local proxy failed这个通常出现在你本地开了某些网络工具的情况下。web 端直播页面本身对网络环境敏感如果页面加载异常先关掉本地代理类工具再刷新页面。注意这里说的是本地网络配置问题不是让你去用什么特殊手段。reading choices或解析时报字段缺失多半是 .proto 字段编号填错了或者响应体保存时被截断。重新抓一次完整响应核对断点里的 tag 值。另外确认pip install --upgrade protobuf已经执行过版本过低会导致解析器初始化失败。OAuth相关报错如果你用的是 Claude Code 这类工具接入认证方式要选对。走 API Key 模式时Base URL、Key、Model ID 三件套必须齐全缺一个都会在握手阶段失败。Claude Code 的接入配置可以参考文档里的说明https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。还有一个容易忽略的点cursor和internal_ext必须从上一包响应里取不能写死。写死的话第一包能过第二包就会返回空或者报错。6. 语义 CTA把逆向流程沉淀成可复用的分析链路整套流程跑通后你会发现真正花时间的不是解码本身而是定位解码入口和还原字段结构。这两步一旦完成后面就是重复劳动。我的建议是把 .proto 文件和解析脚本放进同一个仓库每次遇到新消息类型时只增量补字段不要每次从头抓。如果你后续想让脚本自动解释 JS 片段、补全 .proto、或者对还原出的弹幕数据做批量分析可以用 TaoToken 的模型对话快速验证想法https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。要长期跑自动化分析任务Coding Plan 更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。密钥统一在 API Keys 页面管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。最后留一个实用技巧抓包时把cursor的变化过程打印出来能帮你判断长连接是否正常续包。如果 cursor 一直不变说明请求参数有问题先回去检查internal_ext有没有正确带上。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进