使用Wireshark逆向分析BLE设备通信协议:从环境搭建到协议解析实战

发布时间:2026/7/26 5:01:51

使用Wireshark逆向分析BLE设备通信协议:从环境搭建到协议解析实战 1. 项目概述从灯泡到跳蛋BLE协议逆向的通用法则几年前当我第一次尝试用手机App控制一个智能灯泡时脑子里就冒出一个念头它和手机之间到底在“聊”些什么后来从智能手环到一些更“私密”的智能设备我发现它们大多都基于同一种技术——蓝牙低功耗Bluetooth Low Energy, BLE。这让我意识到无论设备的功能是照明、健康监测还是其他其底层通信逻辑有着惊人的相似性。掌握一套通用的逆向分析方法就等于拿到了一把能打开众多智能设备“黑匣子”的钥匙。今天我就以从业者的角度分享如何利用Wireshark这把“瑞士军刀”深入BLE设备的通信腹地完整破解其通信协议。我们会用一个具体的案例——小米手环的部分通信过程——来贯穿整个实操流程但请记住这套方法论的核心是普适的其思路完全可以迁移到其他任何BLE设备上这也是标题“从灯泡到跳蛋”想表达的含义技术原理相通只是应用场景不同。对于开发者、安全研究员、硬件爱好者甚至是想了解自己设备隐私边界的普通用户来说理解BLE通信协议都至关重要。它能帮你实现第三方应用开发、进行安全审计、修复私有协议漏洞或者仅仅是满足那份“知其所以然”的好奇心。整个过程不要求你具备深厚的射频或密码学背景但需要一些耐心、逻辑思维和动手能力。我们将从最基础的抓包环境搭建开始一步步深入到数据包的解析、协议字段的推断最终尝试复现一次完整的通信会话。我会把我在逆向多个品牌设备过程中踩过的坑、总结的技巧毫无保留地分享出来。2. 核心思路与工具选型为什么是Wireshark在逆向工程领域工具有很多从昂贵的专业射频分析仪到简单的串口调试助手。但对于BLE协议逆向Wireshark配合一个合适的蓝牙适配器是目前性价比最高、功能最强大的方案之一尤其适合我们这种个人研究者或小团队。2.1 核心工具链解析Wireshark这不仅仅是网络抓包工具。经过多年发展它对蓝牙协议栈的支持已经非常完善。其强大之处在于协议解析树它能将原始的二进制数据流按照蓝牙核心规范层层解析从物理层的空口包Advertising/Data Channel PDU到链路层LL、逻辑链路控制与适配协议L2CAP、属性协议ATT最后到最上层的通用属性配置文件GATT。你不需要手动计算CRC、解析头长度Wireshark已经帮你做好了。强大的过滤与着色规则可以从海量数据中快速定位你关心的设备、服务或操作。例如只显示某个特定MAC地址的设备或只显示“Write Request”操作。插件与脚本扩展虽然我们主要用其内置的蓝牙解析功能但其扩展性为深度分析提供了可能。蓝牙适配器这是关键硬件。并非所有蓝牙适配器都支持“监控模式”Monitor Mode。监控模式允许适配器被动接收所有范围内的蓝牙数据包而不与任何设备建立连接这是抓包的前提。常见的支持此功能的芯片有Cambridge Silicon Radio (CSR)系列和Intel的部分无线网卡。一个经济实惠的选择是使用基于CSR8510芯片的USB蓝牙适配器它在Linux系统下配合hcidump或更新的btmon工具可以很好地工作。操作系统Linux特别是Ubuntu是首选平台。其开源内核和强大的命令行工具链如hciconfig,hcitool, 以及后来的bluetoothctl对蓝牙监控模式的支持最为成熟和直接。在Windows或macOS上实现类似功能通常更麻烦可能需要购买特定的商业软件或硬件。2.2 逆向分析的核心逻辑我们的逆向目标通常是理解GATT层以上的“应用层协议”。BLE设备的功能如读取心率、控制开关、设置闹钟都是通过GATT协议定义的“服务”Service、“特征值”Characteristic和“描述符”Descriptor来暴露的。逆向流程可以抽象为以下几步发现与嗅探捕获设备广播包获取其MAC地址和广播信息。连接与交互监控在设备与官方App正常交互时捕获整个连接、服务发现、读写通知的全过程。数据关联与模式识别将捕获到的二进制读写操作Write/Read/Notify与App上的实际动作如点击“同步心率”关联起来。协议字段推断通过改变App操作如设置不同数值的闹钟观察数据包的变化推断出数据包中每个字段的含义如偏移量0x02-0x03代表闹钟小时和分钟。验证与复现编写简单的脚本或程序模拟发送推断出的数据包验证设备是否产生预期响应。这个过程中Wireshark扮演了“显微镜”和“记录仪”的角色让我们能看清每一次通信的细节。注意本文所述技术仅用于学习、研究和安全测试目的请务必在你自己拥有完全所有权的设备上进行操作并遵守相关法律法规。未经授权对他人的设备或网络进行抓包和分析可能涉及法律风险。3. 环境搭建与首次抓包实战理论说得再多不如动手试一次。让我们从零开始搭建抓包环境并捕获第一个BLE数据包。3.1 硬件与系统准备我使用的环境是一台安装有Ubuntu 22.04 LTS的笔记本电脑一个CSR8510芯片的USB蓝牙4.0适配器某宝上约20-30元。确保你的系统已安装基本的编译工具和蓝牙库sudo apt update sudo apt install wireshark build-essential libglib2.0-dev libdbus-1-dev bluez bluez-hcidump bluetooth安装Wireshark时可能会询问是否允许非root用户抓包选择“是”可以方便后续操作否则每次都需要sudo。3.2 配置蓝牙适配器进入监控模式这是最关键的一步。首先插入蓝牙适配器查看系统是否识别hciconfig你应该能看到两个蓝牙设备一个是笔记本自带的如hci0另一个是USB适配器如hci1。记住USB适配器的接口名我们接下来要操作它。首先关闭该适配器然后加载监控模式驱动最后再启用它。不同内核版本和BlueZ版本命令略有差异以下是通用性较强的方法# 1. 关闭适配器 sudo hciconfig hci1 down # 2. 启用蓝牙监控模式 (可能需要根据你的系统调整) sudo btmon -t -w /tmp/ble_capture.btsnoop # 或者使用老一些但直接的方法如果上面不行 sudo hcitool -i hci1 lescan --duplicates # 先开启扫描有时有助于激活 sudo hcidump -i hci1 -w /tmp/raw_capture.hci更现代且推荐的方法是使用btmon它可以直接输出到Wireshark兼容的格式。但为了直观我们先用一种更“原始”的方式让Wireshark直接抓包。实际上在较新的BlueZ和内核中更简单的做法是# 设置蓝牙适配器为“嗅探”模式需要先停止蓝牙服务对它的控制 sudo systemctl stop bluetooth sudo hciconfig hci1 up sudo hcitool -i hci1 cmd 0x08 0x0001 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00上面的hcitool cmd是发送一个OGF0x08, OCF0x0001的HCI命令LE Set Scan Enable参数全0表示禁用扫描但这只是示例具体进入监控模式的命令可能因驱动而异。最可靠的方法是使用专门支持监控模式的驱动如hcidump配合btmon或者使用ubertooth等专业硬件。对于CSR8510一个广泛验证的方法是使用btsnoop日志。鉴于步骤的复杂性我提供一个经过验证的简化流程确保bluetooth服务正在运行sudo systemctl start bluetooth使用bluetoothctl扫描确认适配器能发现设备。关键步骤直接使用Wireshark抓取bluetooth接口。在Ubuntu上以root权限启动Wireshark (sudo wireshark)在接口列表中选择你的蓝牙适配器通常是bluetooth0或hci1。如果列表里没有可能需要安装wireshark的蓝牙插件或检查权限。如果Wireshark直接抓不到我们采用“曲线救国”的方式用btmon记录日志然后用Wireshark分析日志文件。# 在终端A运行开始记录所有蓝牙活动到文件 sudo btmon -w /tmp/ble_trace.btsnoop保持btmon运行然后操作你的手机App与BLE设备如小米手环进行交互。交互完成后在终端A按CtrlC停止btmon。用Wireshark打开生成的/tmp/ble_trace.btsnoop文件。这才是最稳定、兼容性最好的方法。3.3 Wireshark中的初次捕获与分析用Wireshark打开.btsnoop文件后你会看到密密麻麻的数据包。别慌我们一步步过滤。首先在过滤栏输入btl2cap或btatt这样可以过滤掉很多底层的控制包聚焦于应用数据。你应该能看到类似ATT协议的数据包操作类型可能是Write Request,Read Request,Handle Value Notification等。找到与你设备MAC地址相关的数据流。你可以通过观察包中的Source或Destination字段找到你设备的MAC地址手机和手环的地址都会出现。然后使用过滤器例如(bthci_acl.src aa:bb:cc:dd:ee:ff) || (bthci_acl.dst aa:bb:cc:dd:ee:ff)将aa:bb:cc:dd:ee:ff替换为你设备的MAC地址。实操心得第一次抓包很可能抓不到预期数据常见问题有适配器不支持监控模式这是最大的坎。务必确认你的蓝牙适配器芯片型号支持。CSR8510是经过社区大量验证的型号。抓包时机不对要在设备建立连接之前就开始抓包因为广播和连接过程包含了重要的信息交换。数据加密如果设备使用了LE Secure Connection配对通信数据是加密的你抓到的将是密文。这时需要获取或破解其长期密钥LTK这难度极大通常不在基础逆向范围内。幸运的是许多消费级设备为了兼容性仍使用或兼容低安全性的“Just Works”配对或者仅在部分敏感操作时加密。4. 小米手环逆向案例深度解析现在我们以小米手环以小米手环4为例原理相通为具体目标演示如何从抓包数据中提取出有意义的协议信息。假设我们已经成功抓取了一次手环与手机“小米运动”App的完整同步过程包括查找设备、配对、读取电量、同步心率数据等。4.1 定位关键服务与特征值在Wireshark中使用过滤器btatt并追踪蓝牙数据流选中一个相关包右键 - Follow - Bluetooth ATT Stream。你会看到一系列ATT操作。首先寻找Read By Group Type Request和对应的Response。这是客户端手机在发现设备提供的所有主服务。在响应中你会看到一系列的服务句柄范围Handle Range和对应的UUID。例如你可能会看到UUID: 0x1800(Generic Access Service)UUID: 0x1801(Generic Attribute Service)UUID: 0x180a(Device Information Service)UUID: 0x180d(Heart Rate Service)UUID: 0x2a37(Heart Rate Measurement) – 这是一个特征值属于Heart Rate Service。以及一些128位的自定义UUID例如6e400001-b5a3-f393-e0a9-e50e24dcca9e。这类UUID就是设备厂商自定义的服务手环的核心功能如运动数据、闹钟设置、屏幕显示等极大概率就在这些自定义服务中。记下这些自定义服务的UUID和它们的句柄范围。然后在数据流中寻找针对这些句柄的Read Request、Write Request或Handle Value Notification。4.2 解析“设置闹钟”的通信过程假设我们想搞清楚App是如何给手环设置闹钟的。动作关联在抓包过程中你在App上精确地点击“添加一个上午8:30的闹钟”。记住这个时间点。数据包定位在Wireshark的时间线附近寻找在点击后瞬间出现的、指向自定义服务句柄的Write Request或Write Command数据包。Write Command无响应常用于发送控制命令。分析数据载荷点击该Write Command数据包在下方协议详情树中展开Attribute Protocol-Value。你会看到一串十六进制值这就是App发送给手环的原始数据。例如你可能看到这样的数据0x01 0x1e 0x08 0x00 0x00 0x01。 我们需要破译它。通过多次实验改变App中的设置设置闹钟为8:30- 数据:01 1e 08 00 00 01设置闹钟为9:45- 数据:01 2d 09 00 00 01关闭闹钟 - 数据:01 00 00 00 00 00对比这些数据我们可以开始猜测第一个字节0x01可能代表“闹钟1”的索引。第二、三个字节0x1e(30) 和0x08(8) 看起来很像分钟和小时。验证一下9:45 对应0x2d(45) 和0x09(9)。假设成立。第四、五个字节0x00 0x00可能代表“星期重复”Bitmask每位代表一周中的一天。最后一个字节0x01可能代表“开启”0x00代表关闭。于是我们推断出该手环设置闹钟的协议格式可能为[索引][分钟][小时][星期重复低字节][星期重复高字节][开关]4.3 解析“同步心率数据”的通信过程心率数据通常通过“通知”Notification方式由手环主动发送给手机。在数据流中寻找Handle Value Notification数据包特别是来自我们之前记下的、可能与心率相关的特征值句柄。找到后观察其Value字段。BLE标准心率测量格式有定义但厂商可能扩展。标准格式可能第一个字节包含标志位如是否包含传感器接触状态、能量消耗值等后续字节是心率值。例如一个值0x16 0x3c。0x16转二进制00010110根据标准可能表示心率值为16位格式、传感器接触良好。接下来的0x3c(60) 就是心率值bpm。如果是16位可能是0x3c 0x00表示60。对于手环自定义的运动数据步数、睡眠通常也是通过通知或读取特定特征值获得。你需要找到对应的特征值句柄然后通过多次同步比如走几步后同步一次对比数据变化来推断格式。例如步数可能是一个4字节的小端序整数。4.4 构建协议命令字典通过上述方法将各个功能点闹钟、来电提醒、屏幕显示、查找手机、运动模式等一一击破后你可以整理出一张属于该设备的“协议命令字典”。这是一个Markdown表格示例功能操作类型句柄/UUID数据载荷格式示例说明设置闹钟1Write Cmd0x0025 (假设)01 1e 08 00 00 0101索引1e分08时0000星期01开读取电量Read Req0x0018 (假设)-返回值如64- 100%电量心率通知Notify0x001e (假设)16 3c16标志位3c心率值(60bpm)同步步数Read Req0x0032 (假设)-返回4字节小端序如e7 03 00 00- 999步踩坑记录很多时候数据包并不是一目了然的。可能会遇到数据压缩或编码厂商可能对数据进行简单的XOR异或、字节交换或自定义编码。如果直接看十六进制找不到规律可以尝试将数值与已知的明文如时间、步数进行对比看看是否存在固定的偏移或算法。分包传输当数据较长时ATT层会进行分包MTU通常为23字节。Wireshark通常会帮你重组但需要留意。句柄动态变化有些设备在每次连接后服务的句柄可能会轻微变化虽然不常见。最好以UUID为标识而不是绝对句柄。5. 从分析到复现编写测试客户端分析出协议格式后最后一步就是验证我们的理解是否正确。我们可以编写一个简单的Python脚本使用bluepy或pybluez库模拟手机向手环发送我们破译出来的命令。这里以bluepy为例需安装pip install bluepyfrom bluepy.btle import Peripheral, UUID, Characteristic # 替换为你的手环MAC地址 DEVICE_MAC AA:BB:CC:DD:EE:FF try: print(f正在连接 {DEVICE_MAC}...) p Peripheral(DEVICE_MAC, addrTypepublic) # 或 random # 获取所有服务 services p.getServices() for svc in services: print(f服务: {svc.uuid}) # 查找我们感兴趣的自定义服务UUID if str(svc.uuid) 6e400001-b5a3-f393-e0a9-e50e24dcca9e: custom_service svc break # 获取该服务下的所有特征值 chars custom_service.getCharacteristics() for ch in chars: print(f 特征值句柄: {ch.getHandle()}, UUID: {ch.uuid}, 属性: {ch.propertiesToString()}) # 根据之前分析找到用于写闹钟的特征值句柄假设是 0x0025 if ch.getHandle() 0x25: alarm_char ch break if alarm_char: # 准备数据载荷设置闹钟1为 8:30 每天重复开启 # 格式: [索引][分钟][小时][星期重复低][星期重复高][开关] # 星期重复: 0x7F (二进制01111111) 表示周一到周日都重复 payload bytes([0x01, 0x1e, 0x08, 0x7F, 0x00, 0x01]) print(f正在写入数据: {payload.hex()}) # 使用 write command (无响应) alarm_char.write(payload, withResponseFalse) print(写入成功请检查手环闹钟是否已设置。) except Exception as e: print(f发生错误: {e}) finally: try: p.disconnect() except: pass重要提示在实际编写前你需要用脚本先扫描并确认服务的UUID和特征值的句柄是否与抓包分析一致。bluepy的getCharacteristics()可以获取属性但写操作可能需要withResponseTrue或False这需要根据抓包中的操作类型Write Request需要响应Write Command不需要来决定。6. 高级技巧与疑难问题排查当你掌握了基础流程后可能会遇到更复杂的情况。这里分享一些进阶技巧和常见问题的排查思路。6.1 处理加密通信如果你发现抓包中的数据在配对后变成了看似随机的乱码且Wireshark在ATT层显示“Encrypted Data”说明通信被加密了。配对过程抓包是关键在配对阶段Just Works或Passkey Entry设备会交换用于生成LTK的参数。如果你能捕获完整的配对过程包括“配对功能请求”、“公钥交换”、“确认值交换”等并且你拥有配对双方的IRKIdentity Resolving Key或LTK理论上可以将密钥导入Wireshark进行解密。Wireshark设置解密密钥在Wireshark的编辑 - 首选项 - Protocols - Bluetooth - Bluetooth ATT中可以添加LTK。格式为[Master MAC Address],[Slave MAC Address],[LTK in hex]。但这需要你先通过其他手段如从已配对的手机中提取获得LTK这对普通用户几乎不可能。现实策略对于大多数消费级设备的非敏感功能如控制开关、读取传感器状态厂商可能为了兼容旧App或简化流程并未启用强加密。我们的逆向目标可以优先放在这些未加密或弱加密的通道上。6.2 过滤与显示技巧使用显示过滤器btatt.opcode 0x52过滤所有Write Command。btatt.opcode 0x1b过滤所有Handle Value Notification。btatt.handle 0x0025只看特定句柄的流量。(btatt.opcode 0x52) (frame.time_relative 10.0 frame.time_relative 12.5)查看特定时间段的写命令。使用着色规则可以为不同的操作类型Read, Write, Notify或不同的特征值句柄设置不同的颜色让数据流一目了然。追踪特定会话分析 - 启用协议确保蓝牙协议已启用。然后使用蓝牙 - Bluetooth设备菜单查看捕获到的所有设备并可以过滤特定设备的对话。6.3 应对复杂协议与状态机有些设备的协议是一个简单的状态机。例如要读取历史运动数据可能需要先发送一个“准备传输”命令0x01设备回复ACK0x02然后手机再发送“请求数据块”命令0x03后跟块索引设备才返回数据块0x04后跟数据。对于这种协议必须按照正确的顺序重放命令才能得到有效响应。在抓包时要完整捕获一次成功的数据交换会话并理清命令与响应的顺序。6.4 常见问题速查表问题现象可能原因排查思路Wireshark看不到任何蓝牙流量1. 适配器不支持监控模式。2. 未选择正确的捕获接口。3. 系统蓝牙服务冲突。1. 确认适配器芯片型号如CSR8510。2. 尝试用sudo wireshark查看所有接口。3. 尝试用btmon -w file.btsnoop命令先记录。只能看到广播包看不到连接后的数据1. 抓包开始时机晚于连接建立。2. 适配器在连接后无法监控某些驱动限制。3. 数据被加密。1. 确保在手机App开始搜索设备前就启动抓包。2. 换用btmon或更新蓝牙驱动。3. 查看ATT层是否显示“Encrypted Data”。数据包看起来是乱码无规律1. 通信已加密。2. 数据是压缩或自定义编码的。1. 检查配对过程看是否使用了Passkey等安全配对。2. 尝试寻找重复出现的模式或与已知明文对比分析编码规则。模拟发送命令设备无响应1. 命令格式错误。2. 句柄不对。3. 需要先发送其他命令初始化。4. 写类型错误Command vs Request。1. 仔细核对抓包数据一个字节都不能差。2. 重新连接确认句柄是否动态变化。3. 完整重放一次成功会话的所有命令。4. 尝试withResponseTrue/False。无法稳定连接手环进行测试1. 手环被手机占用。2. 脚本连接参数不对。1. 关闭手机蓝牙或断开手环与手机的连接。2. 尝试不同的addrTypepublic或random手环通常使用random地址。逆向工程就像解谜需要耐心、细致的观察和大量的假设验证。从最初面对一堆十六进制数的茫然到逐渐能看懂设备与App之间的“对话”最后甚至能自己“开口”对设备下达指令这个过程充满了挑战和乐趣。每个设备都是一座待探索的小城堡而Wireshark和基本的协议分析技能就是你手中的地图和钥匙。记住最重要的不是记住某个手环的具体协议而是掌握这套“发现、关联、推断、验证”的方法论。当你下次遇到一个新的智能灯泡、智能体重秤或者任何其他BLE设备时你都知道该从哪里开始你的探索之旅了。

相关新闻