Skip to content

Latest commit

 

History

History
250 lines (185 loc) · 12.9 KB

File metadata and controls

250 lines (185 loc) · 12.9 KB

Da Rings 安卓 App 蓝牙(BLE)协议分析

  • 应用名:Da Rings
  • 包名com.moyoung.ring
  • 版本:1.3.0 (versionCode 33, targetSdk 35)
  • 硬件厂商:Moyoung(冒蓝)智能戒指
  • BLE 协议栈com.crrepa.ble(CRREPA BLE,国产手环/戒指通用库)+ Goodix(汇顶)OTA 模块
  • APK 来源:从三星 SM-S9360 设备 base.apk 直接拉取,jadx 反编译

1. 协议总览

Da Rings 与戒指之间是 经典 GATT + 自定义应用层帧协议,无中转云。要点:

结论
物理通道 BLE 4.0+,GATT
应用层帧头 FD DA(与 GATT 服务名 …fdda… 呼应)
帧长度字段 单字节,最大 255 B/帧
分片 大帧按协商 MTU 自动分片发送
MTU 连接后主动请求 512
校验 无应用层 CRC/校验和,完整性靠 BLE 链路层 CRC
加密 无应用层加密(明文载荷)
写类型 默认 WRITE_TYPE_NO_RESPONSE(writeWithoutResponse),更快

⚠️ 由于无加密、无应用层校验,任何能建立 GATT 连接的设备均可解析/伪造帧。绑定仅靠 MAC/用户态逻辑,非密码学绑定。


2. GATT 结构

服务发现逻辑在 p185q1.C7224a,按 UUID 子串匹配。戒指暴露以下 GATT 服务/特征值:

2.1 自定义 Moyoung 服务(UUID 含 fdda

主数据通道服务,UUID 形如 …fdda…(设备实际广播的完整 128-bit UUID 末段含 fdda)。

特征值 (UUID 含) 方向 用途 代码引用
fdd1 Notify(收) 主数据通道:戒指→App 业务数据(实时步数、历史数据、测量结果等) m16663F → m16590B0 / m16637k1
fdd2 Write(发) 主命令通道:App→戒指 默认写特征值 C6886g.m16733o 默认分支
fdd3 Notify(收) 辅助通知通道(与 fdd1 一起开 notify) m18544c 列表第 1 项
fdd5 Write(发) OTA/大数据写通道(命令字 0xF1 m18545d
fdd6 Write(发) OTA/大数据写通道(命令字 0xF2 m18548g

设备识别:服务里必须同时存在 fdd1fdd2fdd3 才被判定为 Moyoung 设备(C7224a.m18550i → "isMoYoung")。

2.2 标准 GATT 服务

服务 UUID 特征值 用途
0x180F(Battery) 2A19 电量百分比(开 notify)
0x180D(Heart Rate) 2A37 标准心率测量(开 notify)
0x180A(Device Information) 2A28 软件版本 / 2A29 厂商名 / 2A24 设备信息(只读)

启用 notify 的特征值集合:[fdd3, 2A19(电量), fdd1, 2A37(心率)]C7224a.m18544c)。CCCID 为标准 00002902-0000-1000-8000-00805f9b34fb

注:代码里另有 a6ed0402 / a6ed0403 两个 UUID(p002a1.InterfaceC0010a),但仅用于 Goodix 固件恢复(Restore)流程,普通业务通信不经过它们。


3. 连接 / 握手流程

BluetoothGattCallback 实现在 p095h1.C5961a。状态机:

connectGatt()
   │
   ▼
onConnectionStateChange(STATE_CONNECTED=2)
   │  C7225b.m18553b(gatt)  → 延迟 500ms 调 discoverServices()
   ▼
onServicesDiscovered()
   │  C7224a 解析服务 → isMoYoung 校验
   │  C6887h 对 [fdd3, 2A19, fdd1, 2A37] 逐个开启 notify(写 CCCD 0x0001)
   ▼
onDescriptorWrite()  (每个 notify 使能回调)
   │  全部使能后 → gatt.requestMtu(512)
   ▼
onMtuChanged(512)
   │  设置内部 MTU=512、分片大小;状态 → STATE_CONNECTED(2),业务就绪
   ▼
业务收发
  • MTU 强制 512BluetoothGatt.requestMtu(512)。后续单次写入按 AbstractC5654k.m13162a()(= 协商后的有效负载大小)分片。
  • 写类型:满足条件时 setWriteType(1)WRITE_TYPE_NO_RESPONSE),即 fire-and-forget;但仍走 onCharacteristicWrite 驱动下一片。

4. 应用层帧格式(核心)

组帧器:p052d1.AbstractC5654k.m13164c(type, feature, payload)发送侧证实帧布局如下(接收侧 p155n1.C6880a.m16637k1 同步解析,完全一致):

 偏移  字节     含义
 ────────────────────────────────────────────────────
  [0]   0xFD     同步字节 1 (signed -3)
  [1]   0xDA     同步字节 2 (signed -38)        ← "FDDA"
  [2]   0x10     标志/版本字节,固定 16          (其 bit0 兼作长度高位,恒为 0)
  [3]   N        总长度 (低 8 位),= payload 长度 + 6
  [4]   type     命令字 (command)
  [5]   feature  子命令字 (feature/sub-cmd)
 [6..]  payload  载荷(可选,长度 = N - 6)

关键细节

  • 总长度 N = payload.length + 6,写在 [3][2] 固定 0x10
  • 接收侧解码:length = (((b[2] & 0x01) << 8) | (b[3] & 0xFF))。因 b[2] & 1 == 0,实际有效长度 = b[3]单帧上限 255 字节
  • 重组:接收侧以同步字 FD DA 起始识别一帧,按 length 字段累计字节直到收齐,再交给 m16597F0type/feature 分发。跨多个 BLE 通知包自动拼接。
  • 无 CRC、无加密:组帧器只填头 + 拷贝 payload,结尾不追加任何校验字节;接收侧也只校验同步字与长度。
  • 字节序:多字节整数普遍 大端(如 AbstractC0011a.m33g(hi, lo) = (hi<<8)|lo)。

示例帧(App→戒指,请求历史步数汇总)

构造:AbstractC5639a0.m13114a(day)m13164c(type=2, feature=13, payload={day}),设 day=0x00(今天):

FD DA 10 07 02 13 00
│  │  │  │  │  │  └── payload: {0x00}  (day=0=今天)
│  │  │  │  │  └───── feature = 0x13 (历史步数汇总请求)
│  │  │  │  └──────── type = 0x02 (历史数据组)
│  │  │  └─────────── 总长 7 (=1+6)
│  │  └────────────── 标志 0x10
└──┘───────────────── 同步字 FDDA

⚠️ 早期版本误记:曾把 m13218b(day,0)→(2,16,{day,0}) 当作步数请求,经读码实证 feature=16 实为 HRV 请求;步数汇总正确值为 feature=13、payload 仅 {day}。详见第 5.3 节。

5.3 已验证命令与载荷语义(2026-07-29 读码实证)

下列由反编译源码直接证实(AbstractC5631k / C6326f / C6880a 分发表),覆盖第 5.1/5.2 节中先前仅为"推断"的部分;Swift 实现见 RingProtocol/(31 单测金标准)。

命令 type feature payload(请求) 响应载荷布局
历史步数汇总 2 13 {day} 16B:day(1) + steps/dist/cal/time 各 3B 大端(m46t),字段间 1B 填充。AbstractC6331k.m14842a
历史步数明细 2 18 {day} day(1) + N×uint16,每对线序小端 m33g(b[i+1],b[i]),30 分钟/桶,全天 48 桶。m14844c
实时心率 开/关 1 9 {01} / {00} 响应同 type/feature,payload = 单字节 BPM。C6326f.m14819b;开关 AbstractC5660q.m13215d
  • type=8 是死代码C6880a.m16597F0case 8: default: return;——先前"实时测量在 type=8"的推断不成立,实时心率实际走 type=1/feature=9
  • 标准 2A37 心率路径存在但 App 特化:m16654tbyte[1] 为 BPM,并要求 byte[2..3]==0x0400(大端) 才回调,蓝牙规范解析;以 type=1/feature=9 为权威实时心率源。
  • 多字节整数默认大端;唯一例外是步数明细(feature=18)的每桶 uint16 为小端
  • 单位(米/千卡/分钟)由 CRPStepsInfo 字段名推断,帧内无单位标记。

5. 命令体系

命令由帧 [4]=type[5]=feature 两级定位。下面是反编译统计出的主要命令组。

5.1 App → 戒指(发送)常见命令

(type, feature) 来自 m13164c/m13163b 调用统计;语义根据命名/回调推断。

type feature 语义(推断)
1 4,5,6,7,8,9 设备基本设置(含目标步数 m13219c → (1,7))
1 10 某开关(布尔)m13220d
1 37,38,39,40 设置类(亮度/振动/显示等,(1,40) 高频)
2 13–22, 27, 47 历史数据查询:步数/心率/睡眠/血氧/压力/HRV/体温/活动详情/训练 等(2,20 高频)
3 9, 12 实时测量类
4 4 (成对出现,疑似请求/查询)
5 1,3,6,12 用户信息/目标类
6 2,8,11,14 闹钟/提醒类(6,2 高频)
7 3,5,6,9,14 闹钟/提醒配置
9 0,1,2 常用命令(9,1 高频,疑似同步/查询)
0xF1 fdd5 通道(OTA/大数据)
0xF2 fdd6 通道(OTA/大数据)
  • 0xF1 / 0xF2C6886g.m16744r / m16746t 触发,发送时分别写入 fdd5 / fdd6,与普通命令(fdd2)分流。

5.2 戒指 → App(接收)type 分发

接收在 C6880a.m16597F0,先按 type(b10)分组,再按 feature(b11)派发到具体 listener。

  • type = 2(历史/数据同步组):feature 2–44 共 30+ 子项,覆盖:

    feature 数据类型 feature 数据类型
    2 步数详情 14 睡眠
    9 历史心率 15 压力
    10 历史 HRV 16/17 体温
    11 历史血氧 18 训练
    12 测量结果 20/27 电压/活动
    19 活动详情 26/40 远程控制
  • type = 8 组(实时测量):feature 9=心率实时、10=HRV、11=血氧、12=测量完成 等,分别回调 onHeartRate / onHrv / onBloodOxygen / onMeasureComplete

  • 其余 type 走各自的监听器(电量、SOS、远程控制、消息提醒、阈值、用户绑定等)。

完整业务回调接口见 com/crrepa/ble/conn/listener/CRPStepsChangeListenerCRPHeartRateChangeListenerCRPSleepChangeListenerCRPBloodOxygenChangeListenerCRPHrvChangeListenerCRPStressChangeListenerCRPTempChangeListener 等共 30+ 个)。


6. OTA / 固件升级

  • 模块:com.crrepa.ble.ota.goodix.*(汇顶 Goodix 芯片的固件恢复/升级)。
  • 通道:大数据通过 fdd5(cmd 0xF1)/ fdd6(cmd 0xF2) 写入,与业务通道隔离。
  • 备用 UUID:固件恢复模式下使用 a6ed0402 / a6ed0403BleRestoreDeviceServices),并复用标准 CCCD 00002902-…
  • 还有 LZO 压缩支持(com.crrepa.ble.lzo.MiniLzoHelper),OTA 数据可能压缩传输。

7. 安全性观察

  1. 明文协议:所有业务帧无加密、无签名。BLE 链路层加密(配对后)是唯一保护。
  2. 无应用层校验:组帧不含 CRC,仅靠同步字 + 长度。恶意邻居理论上可注入伪造帧。
  3. 绑定弱:用户 ID(checkUserId/deleteUserId)是逻辑绑定,非密钥协商。
  4. 隐私数据明文:健康数据(心率、睡眠、位置相关 GPS 走 com.moyoung.ring.health.workout.gps)在 BLE 上明文传输。
  5. 若戒指未强制配对/加密配对,邻近攻击者可嗅探或重放命令。

建议(如做安全评估):用 nRF Connect / Wireshark + btsnoop 抓包验证;检查是否启用 LE Secure Connections 配对。


8. 关键代码索引(反编译后)

文件 作用
p185q1/C7224a.java GATT 服务/特征值绑定,fdd1~fdd6 映射
p185q1/C7225b.java 服务发现单例,isMoYoung 判定
p095h1/C5961a.java BluetoothGattCallback:连接/MTU/notify/write 回调
p155n1/C6886g.java 发送管理器:分片、写特征值选择、发送队列推进
p155n1/C6887h.java notify 使能管理(写 CCCD)
p155n1/C6880a.java 接收分发器:帧重组(m16637k1)+ type/feature 派发
p175p1/C7136c.java 发送队列调度器
p175p1/C7134a.java 命令对象(优先级 + 帧字节)
p052d1/AbstractC5654k.java 组帧器m13164c):帧头/长度/结构
p052d1/AbstractC5661r.java 各命令构造(type,feature + payload)
p003a2/AbstractC0011a.java 字节/整数编解码工具(m33g 大端 uint16 等)
com/crrepa/ble/conn/CRPBleConnection.java 公开命令 API 接口(query*/enable*/send*)
com/crrepa/ble/ota/goodix/* Goodix 固件 OTA

反编译产物目录:/Users/netseye/Desktop/smartring/smartring-decompiled/ 原始 APK:/Users/netseye/Desktop/smartring/apk/darings.apk


9. 复现 / 抓包建议

  1. 静态验证:用 nRF Connect 连接戒指,在 fdd2 上写入第 4 节示例帧,观察 fdd1 通知返回。
  2. 动态抓包
    • 开发者选项 → 启用「蓝牙 HCI 信息收集日志」,操作 App,adb bugreport 取 btsnoop_hci.log,用 Wireshark 解析。
    • 或在已 root 设备上用 hcitool / Android HCI snoop。
  3. 重放/模糊测试:基于本协议格式构造帧,遍历 (type, feature) 探测未知命令。

分析日期:2026-07-28 · 工具:jadx 1.5.5 · 设备:Samsung SM-S9360