-
-
BLE 蓝牙协议:抓包实战 (HCI + 空口)
-
发表于: 3天前 578
-
在对智能 IoT 设备进行安全测试时,比如汽车的无钥匙进入系统、智能手环、智能门锁等等设备核心通信交互都使用了 BLE(低功耗蓝牙)技术。
因此,进行 BLE 流量抓取与分析,是破解 IoT 设备的第一步。
蓝牙的来历
“蓝牙”(Bluetooth)一词取自一千多年前丹麦国王哈拉尔的名字Harald Bluetooth。传说这位国王特别喜欢吃蓝莓,吃到牙齿都变成蓝色了,因而当时的欧洲人民称这位国王的牙齿为蓝牙。
1998年爱立信联合5家厂商联合宣布一种短距离无线通信新技术。由于是这几家大公司一起合作制定的技术,与哈拉尔统一挪威与丹麦的经历类似,所以这项新技术便以“蓝牙”命名。
蓝牙和BLE
蓝牙通常是指在两个电子设备之间无线传输数据的技术。
随着物联网的发展,经典蓝牙太“重”,它在小型终端设备中的实施将占用更多的电量和系统资源。
因此,蓝牙4.0标准引入了低功耗蓝牙(Bluetooth Low Energy,BLE),这个蓝牙技术是专门针对系统资源、电量有限的智能设备的。
BLE具有极其省电,连接速度快的特点,在日常生活里汽车的无钥匙进入、智能手表、智能灯泡、智能门锁、体脂秤、Apple AirTag等等很多很多都是使用BLE进行通信的。
蓝牙的协议栈
BLE协议架构总体上分成3块,从下到上分别是控制器(Controller)、主机(Host)和应用(Application),三者既可以在同一芯片内实现,也可以分不同芯片内实现。
控制器(Controller): 通常在底层蓝牙射频芯片内实现,主要包含物理层(PHY)和链路层(LL)。它与硬件强相关,负责最底层的 2.4GHz 无线电波收发、跳频机制以及维持物理层面的连接。
主机(Host): 通常运行在设备的主 CPU 中(如手机的安卓系统内)。它包含了 L2CAP、SMP、GAP、GATT 等核心协议栈,负责上层数据的拆包组装、设备发现策略、以及配对加密体系的管理。
应用层(Application): 运行在最顶层,调用 Host 提供的接口来实现真正的业务逻辑(比如决定什么时候发送“开锁”指令,或者解析收到的“心率”数据)。

本文主要是介绍抓包,大家可以阅读书籍或者查阅资料去了解学习这个协议栈架构,或且听下回分解。
如何抓包?
我们使用智能设备的时候,通常都是使用手机去对设备进行控制,比如汽车解锁,手环的查找。
在手机里,蓝牙功能其实是由两个完全独立的部门合作完成的。
应用层-->Host(主机 / 手机CPU)
APP 发送一条指令,主 CPU 会生成这段最原始的明文数据。
Host-->Controller(控制器 / 蓝牙底层芯片)
主CPU把数据再交给蓝牙芯片,蓝牙芯片将指令打包、加密、调频,然后通过天线转换成 2.4GHz 的无线电磁波发射出去。
那么既然数据经过了主机到控制器(HCI层),控制器和另外一个设备之间又通过无线电磁波发射出去(空口)。那么这个时候我们对其过程中的HCI层和空口进行抓包,两者互相进行补充,就可以抓取到完整的BLE通信数据了。
进行安卓 HCI 抓包,抓的是CPU和蓝牙芯片之间的通讯,是为了绕过底层的硬件加密,直接拿到 App 层面最干净、最原始的“明文应用数据”,但是无法获取到物理层和链路层的的数据包。
进行空口抓包,获取到物理层和链路层的的数据包,完全不接触交互双方设备,通过空中抓包获取原始的信号数据,因此包含了所有的信息。
Android手机HCI层抓包
通过Android原生自带的hcidump功能抓低功耗蓝牙,由于比较简单,这里就直接一笔带过了,具体遇到问题的可以去查阅资料。
开启Android开发者模式
打开“关于手机”,点击版本号,一直点到提示“开发者模式”
抓包
用测试机(已root),“开发者选项”中,找到并开启 “启用蓝牙 HCI 信息收集日志”
非常重要: 开启该选项后,必须关闭并重新打开一次手机蓝牙,日志才会开始记录。
App进行操作,操作完成后数据包会写入/data/misc/bluetooth/logs目录中
adb shell
su
cd /data/misc/bluetooth/logs
ls
cp btsnoop_hci_xxx /sdcard/
adb pull /sdcard/btsnoop_hci_xxx .
导出后,拖入wireshark就可以进行BLE通信的分析了。
Tips:在有些案例里,可以到看到日志路径是这个 /sdcard/btsnoop_hci.log,我抓包就比较疑惑,问了AI才知道,/sdcard/btsnoop_hci.log是较老的安卓系统(Android 7 及以前)的路径,/data/misc/bluetooth/logs/btsnoop_hci.log是较新的安卓系统(Android 8 及以后,一直到现在的 Android 14/15),这是 Google 官方现在的标准存放路径。
空口抓包
第一次听到“空口”这个词,什么意思呢?顾名思义就是空气接口。
“空口抓包”(Over-The-Air, OTA Sniffing)抓的是真正在空气中传播的 2.4GHz 射频物理波。
空口蓝牙抓包的方案有多种,我使用的方案是nRF Sniffer+wireshark
(一些方案可以参考:c22K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2&6N6i4q4#2k6g2)9J5k6h3y4G2L8g2)9J5c8X3S2^5k6Y4q4Y4z5g2)9J5c8X3W2G2N6q4)9J5c8X3E0J5x3o6S2@1M7r3u0C8x3X3y4C8M7Y4V1^5k6i4Z5`. yichen师傅的文章)
设备
为什么空口抓包需要用设备?
低功耗蓝牙使用短波特高频无线电波,经由2.4~2.485GHz的ISM频段来进行通信。蓝牙有两种通信信道——广播信道和数据信道。
在数据传输时,设备间会使用跳频算法在数据信道间跳频。如果想要捕获到数据信道中的数据,则需使用专业蓝牙设备进行跳频追踪。

我自己使用的设备是E104-BT5040UA,成本是45RMB,产品链接是bffK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2W2j5Y4W2@1k6g2)9J5k6h3y4G2L8g2)9J5c8Y4m8J5L8$3c8#2j5%4c8Q4x3V1j5I4x3U0l9$3i4K6u0W2K9s2c8E0L8l9`.`.
芯片是采用的nRF52840,抓包固件默认为nrfsniffer3.0版本,可以在手册里看到289K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2W2j5Y4W2@1k6g2)9J5k6h3y4G2L8g2)9J5c8X3c8G2N6$3&6H3k6r3k6Q4x3V1j5I4x3U0l9$3i4K6u0W2K9s2c8E0L8l9`.`.



抓包环境配置
抓包环境直接按照文档一步步来即可,很简单。
Tips:这里我踩了一个坑,我使用的官网的nrfutil工具安装的nrfutil ble-sniffer bootstrap,官网的版本是4,而我的设备固件是3,Wireshark 插件版本和板子里的固件版本必须一致,如果用的是其他的新设备可以用nrf官网的nrfutil工具配置。
抓包
环境配置好之后,wireshark就具有了这个插件。

然后插上设备,点击刷新接口列表,在下面可以找到我们的设备,点击进去,抓包环境配置好的话应该可以看到很多广播包不断发送。


将目标设备(这里我用的小米手环)手环重新绑定,就在wireshark可以识别到,选择目标设备的mac,开始捕获。
思考:为什么要专门选择目标设备的 MAC 地址?
因为蓝牙连接后会开启“狡兔三窟”般的“跳频机制”。抓包设备只有一个接收器,如果不指定 MAC 地址,它就只能在3个广播频道瞎逛,永远抓不到连接后的数据;只有选中了特定 MAC,设备才能精准截获 CONNECT_IND 这个包,并根据里面的“暗号”算出跳频轨迹,跟着设备一起在 37 个数据频道里跳频,从而抓到后续的完整通信数据。

可以看到设备在不断发送广播

接下来对目标设备和手机进行绑定


再观察数据包,可以看到数据和之前的广播数据不一样了,并且有一个关键节点CONNECT_IND,建立连接。(可以wireshark Ctrl+F搜索字符串CONNECT_IND),接下来就可以对抓取到的通信包进行分析了。

Tips:
wireshark使用时显示的问题:有人会发现,为什么我抓到包后wireshark看着和一些大佬界面不太一样,没有目的端,界面看着差别很大,这个是wireshark的右下角配置文件的问题,可以选择Default默认配置,也可以用Nordic的nRF_Sniffer官方的配置文件,自己选择即可。

参考资料: