4. BLE 抓包实战(上):使用 nRF Sniffer 与 Wireshark 抓取广播包、解析 ADV_IND 与 ADV_DIRECT_IND

做 BLE 开发,最怕什么?

怕设备连不上,怕数据发丢了,怕功耗下不来。这时候,光靠看代码是没用的。你得亲眼看看空口上到底发生了什么。

抓包,就是给无线通信装上一台「行车记录仪」。今天咱们就来实战,用 nRF Sniffer 配合 Wireshark,把 BLE 的广播包抓下来,一条一条拆开看。

4.1 准备工作:硬件与软件环境

先说说硬件。我手头最常用的是 nRF52840 DK 开发板,它自带一个 J-Link 调试器,刷个 Sniffer 固件就能当抓包器用。如果你手头是 nRF52832 DK 或者 nRF51 DK,也一样,步骤完全相同。

软件方面,你需要装三样东西:

  • nRF Sniffer for BLE —— 这是 Nordic 官方的抓包固件和配套插件。去 Nordic 官网下载,版本建议选 4.x 以上,支持 BLE 5.x。
  • Wireshark —— 网络抓包神器,版本 3.x 以上都行。我个人习惯用 3.6 或 4.0,界面更清爽。
  • Python 3 —— nRF Sniffer 的 Wireshark 插件依赖 Python 运行。
小提示: 装 Wireshark 时记得勾选「Install Npcap」或「WinPcap」,否则抓不到 USB 接口的数据。我刚开始就踩过这个坑,折腾了半小时才发现是 Npcap 没装。

4.2 刷写 Sniffer 固件

把开发板用 USB 线连到电脑。打开 nRF Connect Programmer,选择你的开发板,把下载好的 nrf_sniffer_for_ble_4.x.hex 文件拖进去,点「Write」。几秒钟就刷好了。

刷完后,板子会变成一个 BLE 嗅探器。你可以在设备管理器里看到一个新的 COM 口,或者一个 Wireshark 能识别的 USB 设备。

注意: 刷了 Sniffer 固件后,这块板子就不能再当普通开发板用了。想恢复的话,得重新刷回原始固件。建议专门留一块板子当抓包器,别跟开发板混用。

4.3 配置 Wireshark 与 nRF Sniffer 插件

装好 Wireshark 后,把 nRF Sniffer 包里的 extcap 文件夹复制到 Wireshark 的安装目录下。重启 Wireshark,你应该能在接口列表里看到一个叫 nRF Sniffer for BLE 的接口。

选中它,点开始。如果一切正常,Wireshark 会立刻开始显示空口上的 BLE 数据包。

嗯,这里要注意:默认情况下,Sniffer 会扫描所有信道(37/38/39),但只抓广播包。如果你想抓连接后的数据包,需要指定一个目标设备的 MAC 地址。这个我们下一节再细说。

4.4 抓取广播包:ADV_IND 与 ADV_DIRECT_IND

现在,让一个 BLE 设备(比如你的手机或另一块开发板)开始广播。Wireshark 里应该会刷出一堆包。

咱们先看最常见的两种广播包:

广播类型 PDU 类型值 含义 典型场景
ADV_IND 0x00 可连接的非定向广播 普通 Beacon、设备可被发现
ADV_DIRECT_IND 0x01 可连接的定向广播 快速重连、已知设备配对
ADV_NONCONN_IND 0x02 不可连接的非定向广播 iBeacon、Eddystone
ADV_SCAN_IND 0x06 可扫描的非定向广播 被动扫描场景

在 Wireshark 里,展开一个广播包,你会看到这样的结构:

Bluetooth LE Link Layer
  [Direction: Advertised (0)]
  Advertising Channel PDU
    Header: 0x00 (ADV_IND)
      PDU Type: ADV_IND (0x00)
      ChSel: 2
      TxAdd: Random (1)
      RxAdd: Public (0)
      Length: 31
    Advertising Address: xx:xx:xx:xx:xx:xx
    Advertising Data: ...

关键字段就这几个:

  • PDU Type —— 告诉你这是哪种广播包。
  • TxAdd / RxAdd —— 地址类型,是 Public 还是 Random。很多设备为了隐私会用 Random 地址。
  • Advertising Address —— 广播者的 MAC 地址。
  • Advertising Data —— 广播数据,最多 31 字节。

4.5 深入解析 ADV_IND 广播数据

ADV_IND 是最常见的广播包。它的广播数据部分,由若干个 AD Structure(Advertising Data Structure)组成。每个 AD Structure 的格式是:

+--------+--------+--------+--------+--------+
| Length | Type   | Data ...                |
+--------+--------+--------+--------+--------+
  • Length:1 字节,表示 Type + Data 的总长度。
  • Type:1 字节,表示数据类型。比如 0x01 是 Flags,0x09 是 Complete Local Name。
  • Data:Length - 1 字节,具体数据。

举个例子,我在项目中遇到过一款智能灯,它的广播数据里同时包含了 Flags、Complete Local Name 和 Manufacturer Specific Data。Wireshark 会自动解析这些字段,你直接看就行。

但有时候,Wireshark 解析不出来某些厂商自定义数据。这时候就得手动看 Hex 了。我习惯在 Wireshark 里右键 ->「Copy」->「Bytes as Hex Stream」,然后贴到 Hex 编辑器里慢慢看。

核心要点: 广播数据最多 31 字节,这是 BLE 4.x 的限制。BLE 5.x 引入了 Extended Advertising,可以发更多数据,但那是后话了。

4.6 解析 ADV_DIRECT_IND:定向广播的秘密

ADV_DIRECT_IND 跟 ADV_IND 长得有点像,但有个关键区别:它包含两个 MAC 地址。

  • AdvA:广播者的地址。
  • TargetA:目标设备的地址。

说白了,定向广播就是「我只想跟这个设备说话,其他人别理我」。这种广播包在快速重连场景里很常见。比如你的手机靠近一个已配对的蓝牙耳机,耳机就会发 ADV_DIRECT_IND,直接找手机。

定向广播的优点是:

  • 连接建立更快,因为扫描器不需要做过滤。
  • 功耗更低,因为广播间隔可以设得很短(比如 3.75ms)。

但缺点也很明显:

  • 目标设备必须知道广播者的地址,否则收不到。
  • 定向广播不包含广播数据,只有两个地址。

你想想看,如果两个设备之前已经配对过,互相知道对方的 MAC 地址,那用 ADV_DIRECT_IND 重连,速度会快很多。我在做智能门锁项目时,就用这个机制实现了「靠近即开锁」的效果,用户体验非常好。

4.7 抓包实战中的常见问题

抓包过程中,你可能会遇到几个坑。我一个个说:

  1. 抓不到包? 检查 Sniffer 固件是否刷对,Wireshark 接口是否选对。有时候 USB 线质量不好也会导致数据丢失。
  2. 包太多,眼花缭乱? 在 Wireshark 里加过滤条件。比如只显示某个 MAC 地址的包:btle.advertising_address == xx:xx:xx:xx:xx:xx。
  3. 广播数据解析不全? 有些厂商自定义数据,Wireshark 不认识。这时候可以装一个 Wireshark 的 Lua 解析器,或者手动看 Hex。
  4. Sniffer 掉线? 我遇到过几次,原因是 USB 供电不足。换个 USB 口,或者用带外接电源的 USB Hub 就能解决。
避坑指南: 我曾经在抓包时发现广播包里的 MAC 地址一直在变,以为是设备坏了。后来才意识到,这是设备的「私有地址」功能在作祟。BLE 设备可以定期更换 Random 地址来保护隐私。如果你发现地址对不上,先确认一下设备是不是用了 Privacy 功能。

4.8 知识结构图:BLE 广播包抓包流程

下面这张图,把整个抓包流程串起来了。从硬件准备到数据解析,每一步都标清楚了。

BLE 广播包抓包流程 BLE 广播包抓包流程 1. 硬件准备 2. 刷 Sniffer 固件 3. 配置 Wireshark 4. 开始抓包 5. 过滤广播包 6. 解析 PDU ADV_IND 可连接非定向广播 ADV_DIRECT_IND 可连接定向广播 其他类型 ADV_NONCONN_IND 等 7. 分析广播数据 8. 定位问题 / 验证 💡 说明:ADV_IND 包含广播数据(最多 31 字节),ADV_DIRECT_IND 只包含两个 MAC 地址,无广播数据。 抓包时注意区分地址类型(Public / Random),以及是否启用了 Privacy 功能。

4.9 实战小结

今天咱们把 BLE 广播包的抓包流程走了一遍。从硬件准备到 Wireshark 配置,再到 ADV_IND 和 ADV_DIRECT_IND 的解析,每一步都有实操价值。

我个人觉得,抓包是调试 BLE 协议栈最有效的手段。没有之一。你写再多代码,不如亲眼看看空口上到底发了什么。很多连接失败、功耗异常的问题,一抓包就原形毕露。

下次遇到设备连不上的问题,别急着改代码。先抓个包看看,说不定问题就出在广播数据上。