4、BLE抓包实战:Advertising信道跳频机制、连接事件捕获、LLID解析、ATT读写请求分析、MTU协商
好,咱们进入第四章。这一章是实打实的硬核操作。
前几章我们把工具链和基础协议栈捋了一遍。现在,是时候把抓包工具怼到BLE的物理层和链路层,看看那些在空口上飞来飞去的报文到底长什么样。
我个人习惯,做蓝牙抓包分析,一定要先理解它的“节奏”。BLE的节奏,就是跳频和连接事件。你抓不到这个节奏,看到的只是一堆乱码。
4.1 Advertising信道的跳频机制
很多人以为BLE的广播信道就是固定在37/38/39三个频点上。对,也不对。
这三个信道确实是固定的,但它们的“固定”是为了让扫描设备能快速找到广播包。真正有意思的是,广播本身也有一套简单的跳频逻辑——虽然它不叫跳频,叫“广播信道索引选择”。
核心要点: BLE广播在三个信道上依次发送,每次切换信道的时间间隔由 AdvInterval 和 AdvDelay 决定。抓包时,如果你只盯一个信道,会漏掉大量数据。
我在项目中遇到过一个问题:某款智能门锁经常掉线。抓包一看,发现广播包只在37信道出现,38和39信道完全静默。后来定位到是芯片的射频前端在38信道上有硬件缺陷。你看,如果我只盯着一个信道抓,这个问题根本发现不了。
抓广播包的正确姿势:
- 使用Sniffer的“全信道扫描”模式,同时监听37/38/39
- 观察三个信道上的RSSI是否一致,差异过大说明天线或匹配电路有问题
- 注意广播包的时序——正常应该是三个信道轮流发,间隔均匀
小技巧: 我习惯在Wireshark里添加一个自定义列,显示“RF Channel”。这样一眼就能看出当前包是在哪个信道上收到的。配合时间戳,跳频模式一目了然。
4.2 连接事件的捕获与分析
当两个设备建立连接后,通信模式从广播切换到了连接事件。这时候,跳频就真正开始了。
连接事件的数据信道跳频,使用的是 Channel Map 和 Hop Increment 算法。简单说,就是主设备在每个连接事件里,根据当前信道索引和跳频步长,计算出下一个信道。
抓连接事件的难点在于:你不知道它下一秒跳到哪个信道上去。
所以,专业的Sniffer必须能“跟随”连接。它需要先抓到连接请求包(CONNECT_REQ),从中解析出 Access Address、Hop Increment、Channel Map 等参数,然后才能实时跟踪跳频序列。
注意: 如果你用的Sniffer不支持自动跟随跳频,那抓连接数据基本就是碰运气。我曾经在早期用普通频谱仪抓BLE,手动调频,效率极低。后来换了支持“连接跟随”的抓包工具,才真正解放了生产力。
连接事件的结构:
- 每个连接事件由主设备发起的 M->S 包 开始
- 从设备在 T_IFS(150μs)后回复 S->M 包
- 双方可以连续交换多个包,直到事件结束或数据传完
抓包时,重点关注:
- 连接间隔(Connection Interval):是否稳定?有没有漂移?
- 从设备延迟(Slave Latency):从设备有没有跳过某些事件?
- 空包(Empty PDU):如果频繁出现空包,说明应用层数据吞吐不够,或者链路质量差导致重传
4.3 LLID解析:数据通道的“交通警察”
LLID,全称是 Link Layer ID。它只有2个bit,但作用非常大。
在数据信道PDU中,LLID告诉接收方:这个包是控制命令,还是普通数据,还是数据包的开始或结束。
| LLID值 | 含义 | 说明 |
|---|---|---|
| 00 | LL Control | 链路层控制包,用于连接参数更新、信道映射更新等 |
| 01 | LL Data Start | L2CAP数据包的起始片段,或完整数据包 |
| 10 | LL Data Continue | L2CAP数据包的后续片段 |
| 11 | Reserved | 保留,目前未使用 |
为什么这个字段重要?
你想想看,如果抓包时看到一堆LLID=01的包,但后面没有LLID=10的包,说明数据被截断了。或者,如果LLID=00的包频繁出现,说明链路层在频繁调整参数,可能连接不稳定。
实战经验: 我调试过一个蓝牙耳机,声音断断续续。抓包发现,每隔几百毫秒就出现一个LLID=00的包,内容是“Connection Parameter Update Request”。原来是耳机在频繁请求调整连接间隔,导致音频数据流被中断。后来在固件里限制了参数更新频率,问题解决。
4.4 ATT读写请求分析
ATT层是BLE应用数据的核心。所有的读写操作,最终都通过ATT协议完成。
抓包时,ATT层的报文非常直观:
- Read Request / Response:客户端请求读取某个属性的值
- Write Request / Response:客户端写入数据,需要服务器确认
- Write Command:客户端写入数据,不需要确认(速度快,但不可靠)
- Notify / Indicate:服务器主动推送数据给客户端
我建议你重点关注 Handle 字段。每个属性都有一个唯一的16位句柄。通过抓包,你可以看到客户端到底在读写哪些句柄,从而反推出应用层的逻辑。
分析技巧: 在Wireshark里,右键点击ATT包,选择“Follow ATT Stream”。这样可以把一次完整的读写交互串联起来,方便查看请求和响应的对应关系。我经常用这个功能来验证协议栈的实现是否正确。
常见问题:
- Read Request 没有 Response:可能是设备掉线了,或者句柄不存在
- Write Request 返回 Error:检查错误码,0x01表示句柄无效,0x03表示写入不被允许
- Notify 频率过高:导致数据拥塞,连接断开
4.5 MTU协商:别让数据包“撑破”了
MTU,最大传输单元。BLE默认的ATT MTU是23字节,其中有效载荷只有20字节。对于大多数应用来说,这太小了。
所以,连接建立后,双方通常会协商一个更大的MTU。这个过程通过 Exchange MTU Request / Response 完成。
抓包时,你会看到:
- 客户端发送
Exchange MTU Request,带上自己支持的MTU大小 - 服务器回复
Exchange MTU Response,带上自己支持的MTU大小 - 双方取较小值作为最终的MTU
坑: 有些设备虽然回复了MTU Response,但实际发送的数据包仍然只有20字节。这说明协议栈实现有问题,没有真正使用协商后的MTU。我曾经遇到过一款健康手环,协商MTU到247字节,但每次Notify还是只发20字节。抓包确认后,厂商更新了固件才解决。
MTU协商的抓包要点:
- 确认协商是否成功:看Response中的MTU值是否合理
- 确认后续数据包是否使用了新MTU:看L2CAP层的长度字段
- 如果MTU协商失败,后续的ATT读写请求会被分片,增加延迟和丢包风险
嗯,这张图基本概括了本章的抓包思路。从广播信道开始,一步步深入到连接事件、链路层、ATT层,最后到MTU协商。每一步都有对应的抓包要点和常见问题。
记住,抓包不是目的,解决问题才是。工具只是手段,理解协议才是根本。