1. 为什么我要折腾 BLE 抓包这件事
搞低功耗蓝牙开发的人大概都有过这种体验:设备连不上、配对失败、数据偶尔丢一包,日志里什么都看不出来,代码翻来覆去检查也没毛病,最后只能靠猜。我最早接触 BLE 调试的时候,就是在这种“盲调”状态里耗了整整两周,后来才意识到,问题根本不在应用层,而是空中接口上某一帧握手包压根没发出去或者被干扰掉了。从那时候起,抓包就成了我调试 BLE 的常规手段。
这次要聊的是用 NRF52xx 系列芯片做 BLE sniffer,也就是把一颗支持蓝牙的 NRF52 开发板刷成抓包固件,配合上位机软件,把空中飞行的广播包、连接包、数据包统统抓下来分析。这件事的价值在于:它让你从“猜”变成“看”。不管你是做智能穿戴、蓝牙门锁、医疗传感,还是单纯想搞清楚某个蓝牙设备到底在广播什么内容,这套方案都能用极低的成本给你一双“空中之眼”。
适合谁看?如果你是有一定嵌入式基础、手里正好有 NRF52 开发板(比如常见的 NRF52840 开发板)、想深入理解 BLE 协议行为的开发者,这篇内容基本可以照着复现。哪怕你是刚入门的蓝牙新手,只要跟着步骤走,也能把环境搭起来。我会把原理、选型、实操步骤、踩过的坑全部摊开讲,重点放在“为什么这么做”和“实际会碰到什么”,而不是干巴巴地贴命令。
需要先说明一点:NRF52xx sniffer 的核心原理是利用 Nordic 芯片自带的无线电外设,在特定信道上做被动监听,把捕获到的射频数据交给上位机解析。它不参与连接、不发送任何信号,纯监听,所以对被测设备完全无侵入。这一点很关键,意味着你可以拿它去分析任何在 2.4GHz 频段工作的 BLE 设备,而不用担心干扰对方正常工作。
2. 方案选型:为什么是 NRF52xx 而不是别的路子
2.1 几种常见 BLE 抓包方案的横向对比
在动手之前,我先把市面上能抓 BLE 包的几条路子捋了一遍,因为选错方案后面全是坑。大致分三类:专用硬件嗅探器、通用软件无线电、以及用现成开发板刷固件。下面这张表是我自己整理的实际体验对比,参数基于常见实践,具体型号价格会浮动,但思路是通用的。
| 方案类型 | 典型代表 | 成本区间 | 抓包能力 | 上手难度 | 适用场景 |
|---|---|---|---|---|---|
| 专用嗅探器 | 商用 BLE 分析仪 | 较高 | 完整,含连接跟随 | 低 | 预算充足、要开箱即用 |
| 通用软件无线电 | SDR 平台 | 中等偏高 | 灵活但需自行处理 | 高 | 研究射频层、非标协议 |
| 开发板刷固件 | NRF52xx 开发板 | 低 | 广播+连接跟随 | 中 | 日常开发调试、性价比首选 |
我最终选 NRF52xx 开发板这条路,理由很实在:一是手里本来就有板子,边际成本几乎为零;二是 Nordic 官方对 sniffer 固件的支持比较成熟,配套的上位机工具链完整;三是它支持连接跟随,也就是设备建立连接、跳频之后还能继续抓,这一点很多廉价方案做不到。SDR 虽然灵活,但要自己写解调、处理跳频同步,投入产出比对日常调试来说不划算。
2.2 NRF52xx 做 sniffer 的硬件基础
为什么偏偏是 NRF52xx 能这么干?得从它的无线电外设说起。NRF52 系列芯片内部集成了一个 2.4GHz 收发器,支持 BLE 的物理层调制,同时芯片有一个叫 RADIO 的外设,允许在底层直接配置频率、调制方式、包格式。sniffer 固件本质上就是绕过了协议栈的高层,直接操作 RADIO 外设,把每个信道上收到的数据包原样搬出来。
这里有个关键点:BLE 广播在 37、38、39 三个信道上来回跳,连接建立后会在 0 到 36 号数据信道上按跳频序列跳。sniffer 要能跟上,就必须知道当前的跳频序列和连接参数,这就是所谓的“连接跟随”。NRF52 的固件通过先抓广播包拿到连接请求(CONNECT_IND),从中解析出接入地址、CRC 初始值、跳频参数,然后按同样的算法跟着跳,才能持续抓到连接后的数据包。这个机制是整个方案能用的核心,理解了它,后面排查“为什么抓不到连接后的包”就有方向了。
2.3 固件与上位机的搭配选择
固件层面,常见做法是刷 Nordic 提供的 sniffer 固件(基于 nRF Sniffer for Bluetooth LE 这套东西),它跑在开发板上,通过串口把抓到的包吐给电脑。上位机这边,Wireshark 配合专用的 extcap 插件是最主流的组合,插件负责和开发板通信、把原始数据转成 Wireshark 能识别的格式。这套组合的好处是 Wireshark 的协议解析能力极强,BLE 的每一层字段都能展开看,还能过滤、着色、导出。
我试过另一条路:自己写个简单的串口解析脚本,把原始字节打印出来。实测下来,调试初期看看广播内容还行,一旦涉及连接后的加密数据、多设备混杂,没有 Wireshark 的解析和过滤根本没法用。所以我的建议很明确:固件用官方 sniffer 固件,上位机老老实实用 Wireshark 加插件,别自己造轮子,省下的时间够你调好几个 bug 了。
3. 环境搭建:从一块空板到能抓包
3.1 硬件与软件清单准备
动手前把东西备齐,能省掉中途来回找的麻烦。硬件上,你需要一块 NRF52xx 开发板(NRF52840 最常见,NRF52833 也行),一根能传数据的 USB 线(注意有些线只能充电,这个坑我踩过,折腾半天以为是驱动问题),被测的 BLE 设备一台。软件上,需要固件烧录工具(比如 nRF Connect for Desktop 里的 Programmer,或者命令行工具)、Wireshark、以及 sniffer 的 extcap 插件包。
这里要强调一个细节:开发板的 USB 口要能同时供电和通信,因为 sniffer 固件是通过串口和上位机交互的。有些开发板有两个 USB 口,一个接调试器一个接芯片,要确认你插的是能通到芯片串口的那个。我第一次就插错了口,Wireshark 里死活看不到设备,查了半天才发现是物理连接的问题。
3.2 固件烧录的关键步骤与参数
烧录固件这一步,核心是把 sniffer 的 hex 文件写进开发板。用 Programmer 工具的话,流程是:开发板进入烧录模式(通常是按住复位键再上电,或者双击复位键进入 bootloader),工具里选中板子,加载 hex 文件,点烧录。烧录完成后板子会自动复位运行固件。
参数上没什么需要调的,但有个地方要注意:烧录前最好先整片擦除(erase all),避免旧固件残留的配置干扰。我有一次没擦除直接烧,结果板子跑起来行为诡异,抓包断断续续,重新整片擦除再烧就正常了。这个经验告诉我,固件切换场景下,整片擦除是保平安的常规操作,别图省事。
烧录成功的判断标准:板子上的指示灯会有特定闪烁模式(具体看固件版本),同时电脑设备管理器里能识别出一个串口设备。如果灯不亮或者串口没出现,先检查 USB 线和烧录模式是否进对。
3.3 Wireshark 插件配置与设备识别
固件跑起来后,接下来是让 Wireshark 认识这块板子。把 extcap 插件放到 Wireshark 的 extcap 目录下(不同系统路径不同,插件包里一般有说明),重启 Wireshark,在捕获接口列表里应该能看到一个类似“nRF Sniffer”的接口。选中它,如果配置正确,接口旁边会显示开发板连接的串口号。
这一步最常见的失败是插件版本和 Wireshark 版本不匹配。我遇到过插件加载了但接口不出现的情况,换了个匹配的插件版本就好了。所以建议插件和 Wireshark 都从官方渠道拿对应版本,别混搭。另外,如果电脑上装了多个串口设备,插件可能会认错,需要在插件配置里手动指定串口号。
提示:设备识别成功后,先别急着抓连接包,从广播包开始验证。找一个正在广播的 BLE 设备(手机开个蓝牙广播或者手环都行),在 Wireshark 里应该能看到 ADV_IND 之类的广播包,能抓到就说明链路通了。
4. 抓包实操:广播、连接与数据包的全流程
4.1 抓广播包:验证链路与读懂广播内容
广播包是最好抓的,因为它在固定的 37、38、39 信道上周期性发送,sniffer 只要在这几个信道上轮询监听就行。操作上,Wireshark 选中 sniffer 接口开始捕获,让被测设备进入广播状态,几秒内就能看到包。
读广播包的时候,重点看几个字段:广播地址(判断设备身份)、广播类型(ADV_IND 是可连接非定向,ADV_NONCONN_IND 是不可连接)、以及广播数据里的各个 AD 结构。AD 结构是理解设备“想说什么”的关键,比如 Flags 字段告诉你设备支持什么能力,Local Name 是设备名,Service UUID 是它提供什么服务,Manufacturer Data 往往是厂商自定义数据,很多设备的传感器读数、状态就藏在这里。
我实际调试一个传感器设备时,就是靠广播包里的 Manufacturer Data 定位到问题的:设备广播的数据长度和协议文档对不上,导致手机端解析错位。这种问题光看应用层日志根本发现不了,抓包一看字段长度立刻水落石出。
4.2 连接跟随:抓连接建立与后续数据包
抓连接包比广播复杂,因为要跟随跳频。流程是:sniffer 先监听广播信道,当它抓到一个 CONNECT_IND 包(也就是发起方发给广播方的连接请求),会从中解析出接入地址、CRCInit、hop 增量、信道图等参数,然后按 BLE 的跳频算法计算出后续每个连接事件用哪个信道,跟着跳过去继续抓。
实操中,你要做的是在 Wireshark 里开始捕获后,让主设备(比如手机)去连接被测设备。连接建立的那一瞬间,Wireshark 里会出现 CONNECT_IND 包,之后就是一连串的数据包。如果连接后抓不到包,八成是连接跟随没成功,常见原因有两个:一是 CONNECT_IND 包没抓到(可能连接太快或者信号弱),二是跳频参数解析出错。
这里分享一个提高成功率的小技巧:让主设备和从设备靠近 sniffer 板子,信号强一点,CONNECT_IND 被抓到的概率高很多。另外,如果设备支持扩展广播或者用了 Coded PHY(远距离模式),普通 sniffer 固件可能抓不全,需要确认固件版本是否支持。
4.3 数据包解析:加密前后的区别与字段含义
连接建立后,数据包分两类:加密前和加密后。如果连接没开加密,LL 层的数据直接可见,能看到 ATT 层的读写请求、通知等。一旦开了加密(配对绑定后通常都会),LL 层载荷就是密文,Wireshark 里显示为一串看不懂的字节。
这时候能不能解密,取决于你有没有拿到密钥。如果配对过程被完整抓到,且配对方式允许(比如 Just Works 或 Passkey 且你抓到了完整流程),Wireshark 插件有能力根据抓到的配对交互推导出密钥并解密后续数据。但如果是 LE Secure Connections 且用了带外认证,推导就困难了。我的经验是:调试阶段尽量在未加密或可解密的状态下抓,能省大量精力;如果必须分析加密流量,先确保配对全过程被完整捕获。
字段层面,重点看 LL 层的控制字段(比如 LL_CHANNEL_MAP_REQ 反映信道图更新)、ATT 层的操作码(0x12 是写请求、0x1B 是通知)、以及 L2CAP 层的长度和 CID。这些字段组合起来,基本能还原设备之间在“聊什么”。
5. 常见问题与排查技巧实录
5.1 抓不到包或抓包不完整
这是最高频的问题,我把它拆成几个排查方向。先看物理层:开发板天线附近有没有金属遮挡、被测设备距离多远、USB 线是否接触良好。再看固件层:板子是否真的跑在 sniffer 模式(看指示灯)、串口是否被其他程序占用。最后看软件层:Wireshark 选的接口对不对、插件版本是否匹配。
下面这张速查表是我踩坑后整理的,遇到问题按顺序过一遍,大部分能定位。
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 接口列表里没有 sniffer | 插件未加载或版本不匹配 | 检查 extcap 目录、换匹配版本 |
| 有接口但抓不到任何包 | 串口选错或被占用 | 手动指定串口、关闭占用程序 |
| 只抓到广播抓不到连接 | 连接跟随失败 | 靠近设备、确认 CONNECT_IND 被抓到 |
| 抓到的包大量 CRC 错误 | 信号弱或干扰 | 缩短距离、换信道环境 |
| 加密后数据无法解析 | 未捕获完整配对流程 | 重新抓配对全过程 |
5.2 连接跟随失败的深层原因
连接跟随失败往往不是单一原因。我遇到过一次特别隐蔽的:设备用了信道图更新(Channel Map Update),连接中途把某些信道禁用了,而 sniffer 固件版本较老,没正确处理这个更新,导致跳频算错,后面全丢。升级固件后解决。这提醒我,sniffer 固件要跟被测设备的 BLE 特性匹配,设备越“新潮”(用扩展特性多),固件越要新。
另一个原因是连接参数里的 hop 增量解析。BLE 的跳频算法里 hop 增量是 5 到 16 之间的值,如果 CONNECT_IND 包有比特错误导致这个值解析错,跳频就全乱。所以抓 CONNECT_IND 时信号质量很重要,宁可多抓几次取一个干净的。
5.3 多设备环境下的干扰处理
实验室里往往同时有好几个 BLE 设备在广播,抓包时全混在一起,看着头疼。处理办法有两个:一是用 Wireshark 的显示过滤器按地址过滤,比如btle.advertising_address == xx:xx:xx:xx:xx:xx;二是在 sniffer 插件配置里指定目标地址,让固件层面就只关注特定设备,减轻数据量。
我一般两个都用:固件层过滤减少串口带宽压力,Wireshark 层过滤方便切换分析对象。要注意的是,固件层过滤如果设错了地址,会以为“抓不到包”,其实是过滤掉了,这个坑我踩过,排查时先确认过滤配置。
注意:抓包分析时养成随手保存的习惯。BLE 交互是时序相关的,一次没抓全,重现可能要等很久。Wireshark 里及时保存 pcapng 文件,后面复盘、对比都靠它。
6. 我个人的几条实操心得
折腾这套东西断断续续有一段时间了,有几条心得是文档里不会写、但实际特别管用的。第一条是关于“先广播后连接”的验证顺序:每次换新设备或新固件,我一定先用广播包验证链路通不通,通了再抓连接。这样一旦出问题,能快速判断是链路问题还是连接跟随问题,缩小排查范围。
第二条是关于信号强度的直觉。sniffer 板子不是专业接收机,它的接收灵敏度有限,被测设备离远了或者中间隔了东西,抓包质量断崖式下降。我现在的习惯是把 sniffer 板子放在离被测设备半米以内,中间尽量无遮挡,抓包成功率明显提升。别指望它像商用分析仪那样隔着几米还能稳定抓。
第三条是关于固件和工具的版本管理。sniffer 固件、extcap 插件、Wireshark 三者版本要配套,我专门建了个目录存对应版本的组合,换电脑或重装系统时直接整套拷过去,省得重新试版本。这个习惯帮我避免了好几次“明明昨天还能用今天就不行”的莫名其妙。
最后说个扩展方向:这套 sniffer 抓到的原始数据其实不止能给 Wireshark 看,如果你有自定义分析需求,比如统计某类广播包的发送频率、分析连接间隔的稳定性,可以把串口数据接出来自己写脚本处理。我做过一个简单的统计脚本,把抓到的包按时间戳和类型归类,用来评估设备的广播功耗表现,比单纯看波形直观多了。这个方向适合对 BLE 行为做量化分析的人,后面有空可以再展开聊。