资讯详情

Galaxy Buds Client 逆向工程指南:RFCOMM/SPP 专有协议解析与跨平台管理实现

📅 2026/10/4 13:32:41 | 华诺云谱 👁 阅读
Galaxy Buds Client 逆向工程指南:RFCOMM/SPP 专有协议解析与跨平台管理实现
桌面应用智能硬件蓝牙【免费下载链接】GalaxyBudsClientUnofficial Galaxy Buds Manager for Windows, macOS, Linux, and Android项目地址https://gitcode.com/gh_mirrors/ga/GalaxyBudsClient点击查看免费下载Galaxy Buds Client 是一款面向 Windows、macOS、Linux 与 Android 的非官方 Galaxy Buds 管理工具其核心能力建立在逆向工程得到的 RFCOMM/SPP 二进制协议之上。本文以中文版项目文档docs/README_chs.md为主线完整讲解该协议的封包结构、帧类型、CRC16-CCITT 校验算法、常用消息Message ID的字段布局与触控动作映射并结合 SppMessage.cs、Crc16.cs 与 ExtendedStatusUpdateDecoder.cs 等源码与测试用例给出可复现的解析与验证方法。读完本文你将能够理解 Galaxy Buds 系列设备与上位机之间二进制指令的编解码全过程并掌握如何借助仓库内协议笔记与解码器实现二次开发。项目背景为什么要逆向 RFCOMM 协议蓝牙设备之间要高效通信必须协商并解析特定的蓝牙配置文件。Galaxy Buds 系列设备定义了两个核心配置文件A2DPAdvanced Audio Distribution Profile负责音频流传输与控制该配置文件已标准化并有公开文档SPPSerial Port Profile负责传输二进制数据流其底层依赖 RFCOMM 协议。制造商三星通常借助 SPP 交换配置数据、执行固件更新、下发各类控制命令。A2DP 是公开的但通过 RFCOMM 交换的二进制数据格式是专有格式。作者采用了两条逆向路径先直接抓取并分析耳塞发出的二进制数据流结构再反编译官方 Android 版 Galaxy Buds 应用以理解设备内部工作机制。逆向成果沉淀为三份文档2019 年初代 Galaxy Buds 协议笔记GalaxyBudsRFCommProtocol.mdGalaxy Buds Plus 协议笔记Galaxy Buds Plus RFComm Protocol Notes.mdBuds Plus 隐藏调试特性记录GalaxyBudsPlus_HiddenDebugFeatures.md在进一步研究 Buds Plus 时还发现了固件调试模式、未使用的配对模式、蓝牙密钥转储等不寻常特性并配套开发了固件下载与固件提取工具用于获取和分析官方固件二进制文件另有脚本可实时流式读取 Buds Pro 的头部追踪数据。这些都属于协议逆向的衍生成果本文聚焦于协议本体。SPP 封包结构非分片帧的字节布局根据 GalaxyBudsRFCommProtocol.md一条完整的 SPP 消息非分片帧由以下字段构成名称值十六进制大小Preamble前导码FE1 字节TypeReq0 或 Rsp10x1 字节Payload size负载大小xx1 字节Message ID消息 IDxx1 字节Message payload消息负载...动态ChecksumCRC16-CCITTxx xx2 字节Postamble后导码EE1 字节关键计算规则FrameType负载大小 250时为1否则为0ExtendedFrameType负载大小 250时为2否则为11 字节负载大小计算x payload size - 1 字节(msg_id) - 2 字节(crc)即负载大小字段本身包含 Message ID 与 CRC 所占的 3 字节校验和范围对Message ID 与负载内容计算 CRC16-CCITT。分片Fragmented帧目前暂未在笔记中展开仅用于大数据量传输场景例如固件 OTA 升级与 Core Dump 转储。该字节布局在源码中有完整对应。在 SppMessage.cs 中各字段长度以常量定义SomSize1、TypeSize1、BytesSize1、MsgIdSize1、CrcSize2、EomSize1Size负载大小等于MsgIdSize Payload.Length CrcSize与笔记中负载大小字段包含 msg_id 与 crc的约定一致TotalPacketSize则进一步累加前导码、类型、大小字段与后导码。Encode()方法SppMessage.cs按前导码 → 头 → Message ID → Payload → CRC → 后导码的顺序写入Decode()SppMessage.cs则逐字节校验 SOM、解析大小、读取 ID 与负载、验证 CRC 是否为 0并校验 EOM任何一步失败都会抛出 InvalidPacketException。帧类型与大小字段新旧设备的头格式差异笔记中 Type 字段取值为0Request或1Response并注明可能还有其他类型由 isFragment() 判断。在代码实现中这一可能变成了现实不同代际设备对头部大小的编码方式并不相同。SppMessage.cs 依据DeviceSpec.Supports(Features.SppLegacyMessageHeader)区分两种头格式旧式Legacy头直接写 1 字节Type与 1 字节Size即笔记中描述的FE | Type | Size | MsgId | Payload | CRC | EE新式头以 2 字节 short 作为头部其中bit130x2000标记IsFragment分片bit120x1000标记TypeResponse 时置位低 10 位0x3FF为Size。解码时SppMessage.cs读取 2 字节 header 后draft.IsFragment (header 0x2000) ! 0draft.Type (header 0x1000) ! 0 ? Request : Response注意此处新旧设备的 Request/Response 语义恰好相反size header 0x3FF。这解释了笔记中Type 可能不止两种取值的注释分片标志正是通过头部高位传递的。此外新式 Buds 还会将内部消息包裹在UNK_SPP_ALTMsgIds1信封中传输实际消息 ID 位于负载首字节见 SppAlternativeMessage.cs。CRC16-CCITT 校验从查表法到解码验证笔记将校验算法标注为CRC16-CCITT并指出校验范围为 Message ID 与内容。仓库中的 Crc16.cs 给出了完整实现采用查表法预计算的Crc16Tab表包含 256 个条目配合crc table[((crc 8) ^ byte) 0xFF] ^ (crc 8)迭代累加crc16_ccitt(IEnumerablebyte data)返回 16 位校验值crc16_ccitt(MsgIds msgId, byte[] payload)将msgId与payload拼接为crcData后计算对应笔记对 Message ID 和内容求校验。源码注释中还保留了原始抓包样本作为参照{0x61, 0x02, ...}中前两个字节0x61MsgID与后续负载内容参与校验末尾两个字节0x4B 0x5F此处即 CRC1/CRC2在计算前需要字节序交换这与解码路径中crcData[^2] crc2; crcData[^1] crc1;SppMessage.cs的读取方式互相印证。Decode()的校验逻辑SppMessage.cs在消息尾部的 CRC 字段被交换填充进crcData后重新计算当draft.Crc16 0时判定校验通过正常构造下 [IDpayload] 的 CRC 与携带的 CRC 异或应为 0否则抛出InvalidPacketException(Checksum)。发送方向Send消息字段详解协议笔记的Send部分逐一列出了上位机 → 耳塞消息的负载布局仓库的 Encoder 实现与之一一对应。以下为完整字段表MSG_ID_UPDATE_TIME更新时钟Index名称描述大小0Timestamp自 1970 年以来的毫秒数long 字节缓冲8 字节8Timezone时区偏移需累加的毫秒数int 字节缓冲4 字节实现见 UpdateTimeEncoder.csTimestamp默认取DateTime.Now与 Unix 纪元之差的总毫秒数Offset取TimeZoneInfo.Local.BaseUtcOffset.TotalMilliseconds拼成 12 字节负载。Android 官方应用在收到 RESP 响应后总会发送一条时间更新以保持设备时钟同步。MSG_ID_MANAGER_INFO上报客户端信息Index名称描述大小0Hardcoded恒为 11 字节1IsSamsungDeviceSamsung 设备 1其他 21 字节2AndroidSdkAndroid 版本SDK 整数1 字节实现见 ManagerInfoEncoder.cs默认以ClientDeviceTypes.Samsung与AndroidSdkVersion34构造[1, type, sdk]三字节负载。笔记提示该消息可能用于启用仅手机端可用的功能。MSG_ID_VOICE_NOTI_STATUS语音通知状态Index名称描述大小0Status0 或 11 字节用于为基于客户端的 TTS 语音通知做准备笔记注明似乎没有任何效果。MSG_ID_NOTIFICATION_INFO通知信息Index名称描述大小0?0 或 1可能用于播放内部蜂鸣声1 字节用于通知笔记同样注明似乎没有任何效果。MSG_ID_GAME_MODE游戏模式Index名称描述大小0Mode?若手机支持 Game Mode 则设为 2否则未知1 字节效果未知仅在支持 Game Mode 的三星设备上使用。MSG_ID_EQUALIZER均衡器Index名称描述大小0Enabled0 或 1启用 EQ1 字节1Preset0-10预设1 字节预设取值Preset ID如下Preset ID描述0Bass boost针对 Dolby 优化1Soft针对 Dolby 优化2Dynamic针对 Dolby 优化3Clear针对 Dolby 优化4Treble boost针对 Dolby 优化5Bass boost6Soft7Dynamic8Clear9Treble boost实现见 SetEqualizerEncoder.cs对于初代 Buds非 Dolby 模式DolbyModefalse下rawPreset 5后写入负载即把 UI 层 0-4 的预设映射为线缆上的 5-9对于 Buds/Live/Pro 等新设备则简化为单字节[!IsEnabled ? 0 : Preset 1]因为 Dolby 模式对新设备无效。可见同一消息 ID 在不同设备代际间存在两种负载编码这正是逆向笔记与源码对应关系中最典型的差异点。MSG_ID_LOCK_TOUCHPAD锁定触控板Index名称描述大小0Enabled0 或 1触控板锁定1 字节现代设备的编码器 LockTouchpadEncoder.cs 已扩展为多个布尔位LockAll、TapOn、DoubleTapOn、TripleTapOn、HoldTapOn以及支持AdvancedTouchLockForCalls特性时的DoubleTapCallOn、HoldTapCallOn可分别控制不同手势的启停。MSG_ID_SET_AMBIENT_MODE环境音开关Index名称描述大小0Enabled0 或 1启用环境音1 字节MSG_ID_AMBIENT_VOICE_FOCUS环境音人声聚焦Index名称描述大小0Type0 或 1Default 或 VoiceFocus1 字节对应解码侧 AmbientVoiceFocusDecoder.cs 中的msg.Payload[0] 1该 Message ID 在较新设备上已被复用于ADJUST_SOUND_SYNC见 SppMessageEnums.cs 中LegacyMsgIds.AMBIENT_VOICE_FOCUS 133的兼容性说明。MSG_ID_AMBIENT_VOLUME环境音音量Index名称描述大小0Volume1-5环境音音量1 字节MSG_ID_MUTE_EARBUD单耳静音Index名称描述大小0LeftMuteStatus0 或 1静音1 字节1RightMuteStatus0 或 1静音1 字节仅在 FindMyGear 模式下可用编码见 FmgMuteEarbudEncoder.cs。MSG_ID_SET_TOUCHPAD_OPTION设置长按触控动作Index名称描述大小0LeftOption在左耳设备上设置的动作 ID1 字节1RightOption在右耳设备上设置的动作 ID1 字节可用动作Available Actions如下ID描述0语音助手1快速环境音2音量若设置在左耳音量减否则音量加3环境音4Spotify SpotOn需要客户端兼容5Other...仅左耳6Other...仅右耳实现见 SetTouchOptionsEncoder.cs动作 ID 经DeviceSpec.TouchMap.ToByte()转换不同设备代际的映射表不同初代 Buds 使用 BudsTouchMap.cs0VoiceAssistant、1QuickAmbientSound、2Volume、3AmbientSound、4SpotifySpotOn、5OtherL、6OtherRBuds Plus 使用 BudsPlusTouchMap.csBuds Live 使用 BudsLiveTouchMap.csNoiseControl 取代 QuickAmbientSound新设备则使用 StandardTouchMap.cs。枚举定义位于 Constants.cs。MSG_ID_MAIN_CHANGE主连接切换Index名称描述大小0Device移交主连接1左0右1 字节无参数消息Parameter-less messagesMessage ID描述MSG_ID_FIND_MY_EARBUDS_START开始播放响亮的哔哔声MSG_ID_FIND_MY_EARBUDS_STOP停止播放并恢复到默认蓝牙音频MSG_ID_DEBUG_SERIAL_NUMBER返回两只设备的序列号MSG_ID_RESET将设备重置为出厂默认设置并返回结果码MSG_ID_DEBUG_GET_ALL_DATA返回版本数据与传感器测量值MSG_ID_DEBUG_BUILD_INFO返回两只设备的设备字符串MSG_ID_LOG_SESSION_OPEN打开日志会话并断开音乐流MSG_ID_LOG_SESSION_CLOSE关闭日志会话并恢复音乐流MSG_ID_BATTERY_TYPE返回两只设备的电池类型字符串这些无参数命令在接收方向的解码器均已在仓库中落地例如 DebugGetAllDataDecoder.cs 将原始负载解析为硬件/软件版本、左右耳蓝牙 MAC、加速度计 XYZ、接近传感器、热敏电阻温度、ADC 电量/电压/电流与 Hall 数据BatteryTypeDecoder.cs 按 ASCII 读取左右耳各 2 字节的电池类型字符串DebugSerialNumberDecoder.cs 与 DebugBuildInfoDecoder.cs 分别解析序列号与构建字符串。接收方向Receive消息字段详解MSG_ID_EXTENDED_STATUS_UPDATED扩展状态更新Index名称描述大小0VersionOfMR1 或 2也用于检测新的环境音模块1 字节1EarType0 或 1未使用1 字节2DeviceBatGageL0-100%电池左1 字节3DeviceBatGageR0-100%电池右1 字节4TwsStatus0 或 1耦合设备状态1 字节5MainConnection0右或 1左当前主连接1 字节6WearingStatus0无、1左、16右、17两者1 字节7AmbientSoundEnable0 或 1环境音是否启用1 字节8AmbientSoundType0 或 1人声聚焦模式是否启用1 字节9AmbientSoundVolume环境音音量1 字节10EqualizerEnable0 或 1EQ 是否启用1 字节11EqualizerType0-10EQ 类型1 字节12dynamic触摸锁定状态若字节 13 未使用则附带一个选项槽1 字节13dynamic可选触控选项左与右1 字节笔记补充的换算规则附加代码-1测试代码环境音音量后处理int saved vol -1;预期范围[1;5]EQ 类型范围[0;10]if (type 5) type - 5;实际范围[0;5]字节 13 仅在长按触控动作需要同时为左右耳设置两个不同动作时才传输若单个选项槽足够则字节 13 不传输动作存储在字节 12 中与触摸锁定状态0 或 1共享该字节。字节 12 与 13 的位布局Single touch optionbyte lock_touchpad_status (sppMessage.getParameters()[12] 240) 4; byte touchpad_option sppMessage.getParameters()[12] 15; storeLeftTouchpadOption(touchpad_option);字节 12 与 13 的位布局Double touch optionbyte lock_touchpad_status sppMessage.getParameters()[12] 255; byte touchpad_option_l (sppMessage.getParameters()[13] 240) 4; byte touchpad_option_r sppMessage.getParameters()[13] 15;仓库中的 ExtendedStatusUpdateDecoder.cs 是这套布局的现代实现并且比笔记走得更远对于初代 Buds当msg.Size 13双选项槽时从字节 13 拆分左右耳触控选项否则从字节 12 拆分并通过Revision 3判断无缝连接字段对于 Buds 及以上设备负载被扩展为包含佩戴状态、充电盒电量、设备颜色2 字节、侧音、额外高环境音、无缝连接、Fmm Revision、通话路径控制、降噪模式、语音唤醒、空间音频、充电状态等数十个字段每个字段按[Device(Models.X, Selector.GreaterEqual)]特性标注关联的设备代际。该解码器还实现了IBasicStatusUpdate接口由 SppMessageReceiver.cs 分发BaseUpdate与ExtendedStatusUpdate事件并在设备连接时更新设备颜色。MSG_ID_STATUS_UPDATED状态更新Index名称描述大小0EarType0 或 1未使用1 字节1DeviceBatGageL0-100%电池左1 字节2DeviceBatGageR0-100%电池右1 字节3TwsStatus0 或 1耦合设备状态1 字节4MainConnection0右或 1左当前主连接1 字节5WearingStatus0无、1左、16右、17两者1 字节实现见 StatusUpdateDecoder.cs初代 Buds 按上述 6 字节布局解析EarType 在索引 0Buds 及更新设备则将索引 0 变为 Revision、索引 5 变为佩戴状态高低位左耳高 4 位、右耳低 4 位并在索引 6 追加充电盒电量、索引 7 追加充电状态位bit4左充电、bit2右充电、bit0充电盒充电。MSG_ID_RESP通用响应Index名称描述大小0Action发送给耳塞的原始消息 ID1 字节1ResultCode结果/错误码0 成功1 字节2ExtraData可选仅在手动更改主连接时使用2 字节通用响应。Android 应用收到后总是发送一次时间更新。例外情况[未验证] 若字节 0 对应 112即MAIN_CHANGE则该消息是手动主连接切换的响应此时字节 2 描述哪个耳塞被声明为主连接0右1左。实现见 GenericResponseDecoder.csResultCode映射到SdkEarbudResult枚举负载长度大于 2 时读取ExtraData。该消息对应ResetResponse、ResetResponseDecoder等事件通路可在 SppMessageReceiver.cs 中看到ResetResponse事件携带ResultCode的派发逻辑。响应机制状态更新后的应答协议笔记在两个状态更新消息下都标注了同一要求设备可能期望一个响应。应将同一个 SPPMessage 以响应类型response type发送回去之后还应发送基本的Android管理器应用信息参考 MSG_ID_MANAGER_INFO。也就是说一次完整的状态同步交互至少包含三步耳塞推送STATUS_UPDATED或EXTENDED_STATUS_UPDATED上位机将该消息以Response 类型原样回发上位机随后发送MANAGER_INFO告知客户端设备类型三星/其他与 Android SDK 版本。这条握手约定在实际代码中同样可见SppMessageReceiver.MessageReceiverSppMessageReceiver.cs对解码后的消息统一走DispatchEventByDecoder分发而消息生命周期从DecodeRawChunkSppMessage.cs的字节流切分开始——该函数循环从入站缓冲中解码单条消息遇到损坏包时向后搜索下一个 SOM 字节尝试重同步连续失败超过 5 次则放弃整段数据块体现了对不稳定蓝牙链路的容错设计。测试与验证用仓库测试固件校验解码器仓库提供了可执行的验证途径。测试基类 MessageTests.cs 从嵌入式资源GalaxyBudsClient.Tests.TestData.ExtendedStatusUpdate.{Model}_rev{Revision}.bin读取原始抓包字节调用SppMessage.Decode(data, model, false)后断言解码结果与期望对象逐属性相等。以初代 Buds 的测试用例 Buds/ExtendedStatusUpdateTests.cs 为例其期望结果为Revision3、EarType0、BatteryL70、BatteryR95、IsCoupledtrue、MainConnectionDevicesInverted.RWearStateNone、EqualizerMode7、TouchpadLockfalseTouchpadOptionL/TouchpadOptionRVolume、SeamlessConnectionEnabledfalseAmbientSoundEnabledfalse、AmbientSoundVolume2、AmbientSoundModeDefault、EqualizerEnabledtrue。测试数据目录还包含 Buds2、Buds2Pro、BudsPlus、BudsLive、BudsPro、BudsFe 等多个代际的.bin抓包样本见 GalaxyBudsClient.Tests 各子目录可运行dotnet test验证完整协议栈。若你自行抓取设备流量也可以对照 GalaxyBudsRFCommProtocol.md 的字段表逐字节校验。安装与使用让协议能力落地到桌面逆向协议最终服务于桌面端管理能力。项目中文文档列出的能力包括详细电池统计、诊断与工厂自检、大量隐藏调试信息、可定制的长按触控动作、固件写入与降级Buds、Buds Pro等全部建立在本协议之上。各平台安装方式如下Flatpak所有 Linux 发行版flatpak install me.timschneeberger.GalaxyBudsClientFlatpak 版本默认不支持开机自启动除非手动配置。可使用galaxybudsclient /StartMinimized让应用在系统启动时静默运行。注意 Flatpak 运行在沙盒中默认只能访问~/.var/app/me.timschneeberger.GalaxyBudsClient/目录。AURArch Linuxyay -S galaxybudsclient-binwingetWindowswinget install ThePBone.GalaxyBudsClient桌面版二进制文件发布在项目的 Releases 页面安装前请阅读发行说明Android 移动版可在应用商店获取付费。安装后即可连接 Galaxy Buds 系列设备通过 Interface/Pages 下的各页面均衡器 EqualizerPage.axaml、触控板、高级选项 AdvancedPage.axaml、开发者工具 DevTools.axaml 等与设备交互——每一次交互背后都是一条符合本文所述格式的 SPP 消息。从笔记到代码进一步阅读指引协议原始笔记GalaxyBudsRFCommProtocol.md、Galaxy Buds Plus RFComm Protocol Notes.md隐藏调试特性 GalaxyBudsPlus_HiddenDebugFeatures.md编解码核心SppMessage.cs、SppMessageReceiver.cs消息 ID 枚举含兼容性说明SppMessageEnums.cs校验算法Crc16.cs解码器全集Message/Decoder56 个解码器涵盖状态更新、自检、日志、FOTA、隐藏命令等编码器全集Message/Encoder测试用例GalaxyBudsClient.Tests含各代际真实抓包样本消息抓包分析工具imhex 的固件与消息 dump 模式文件 imhex_message_dump_pattern.hexpat、imhex_firmware_pattern.hexpat注意事项与限制协议数据格式是专有格式笔记本身标注为不完整新设备Buds2 及以后的扩展状态负载字段随固件 Revision 动态增长请以仓库源码为准同一 Message ID 在不同代际设备间可能被复用如 133、137、142 等仓库通过 LegacyMsgIds 枚举保留兼容性说明部分功能如语音通知、通知蜂鸣声、游戏模式在笔记中注明无实际效果或效果未知属逆向过程中的客观记录并非使用承诺本项目以 GPLv3 许可开源与三星公司无任何关联也不受其监管本协议仅用于非官方的设备管理研究场景。赞分享桌面应用智能硬件蓝牙【免费下载链接】GalaxyBudsClientUnofficial Galaxy Buds Manager for Windows, macOS, Linux, and Android项目地址https://gitcode.com/gh_mirrors/ga/GalaxyBudsClient点击查看免费下载相关推荐Galaxy Buds ClientGalaxy Buds 全系列设备的开源跨平台管理器与 SPP/RFCOMM 协议逆向工程实战Galaxy Buds ClientGalaxy Buds 全系列设备的开源跨平台管理器与 SPP/RFCOMM 协议逆向工程实战 Galaxy Buds C桌面应用智能硬件蓝牙Galaxy Buds Client 完全指南功能特性、跨平台安装与 RFCOMM 私有协议逆向解析Galaxy Buds Client 完全指南功能特性、跨平台安装与 RFCOMM 私有协议逆向解析 Galaxy Buds Client 是一款面向三星 G桌面应用智能硬件蓝牙CyberStrikeAI完整指南一条命令启动让AI智能体替你驱动安全测试CyberStrikeAI完整指南一条命令启动让AI智能体替你驱动安全测试 CyberStrikeAI 是一个用 Go 编写的 AI 原生安全测试平台你用桌面应用智能硬件蓝牙上一篇PerfView 代码库 C 编码规范指南从缩进、类布局到命名与注释的实战要求下一篇Wand-Enhancer终极指南三步免费解锁WeMod Pro完整功能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑