对 Bionic Bird 仿生扑翼机 X-FLY 的蓝牙遥控系统进行逆向工程分析,实现基于自定义软硬件的第三方控制。

一、目标任务
X-FLY 是 Bionic Bird 公司推出的仿生扑翼机,可通过 Flying App 进行连接控制。若想在此扑翼机上进行二次开发(如加装里程计实现闭环控制),就不可避免研究其底层蓝牙通信机制。
本文旨在对 XFLY 蓝牙遥控系统进行逆向工程分析,理解其通信协议与控制逻辑。核心目标是抓取并分析遥控器(手机 APP)与接收机之间的蓝牙通信数据包,最终实现对该遥控系统的逆向控制。此过程对于研究遥控设备安全、开发第三方控制应用或进行协议兼容性测试具有参考意义。
二、蓝牙协议抓包
2.1 BLE 协议架构简介
BLE 协议架构总体上分为 3 层(从下到上):
| 层级 | 名称 | 说明 |
|---|---|---|
| 底层 | Controller(控制器) | 蓝牙芯片,负责射频、基带与链路层处理 |
| 中层 | Host(主机) | 手机 / 电脑 CPU 上的协议栈,负责逻辑链路与应用层 |
| 顶层 | Application(应用) | 用户态 APP,生成原始控制指令 |
三者既可以在同一芯片内实现,也可以分布在不同芯片中。

2.2 抓包方式对比
蓝牙数据抓包是逆向分析的第一步,目的是捕获遥控器与接收机之间完整的通信数据流。主要有两种抓包方式:
方式一:HCI 层抓包(推荐)
捕获 Host 与 Controller 之间的指令和事件,优势在于可以直接获取明文的应用层数据。
Windows 环境:使用 Microsoft Bluetooth Test Platform (BTP) 中的
btvs.exe配合 Wiresharkbtvs.exe -Mode WiresharkAndroid 环境(本文采用):利用系统自带的 HCI 日志功能,通过 ADB 导出
为什么选择 HCI 层抓包?
当前许多 BLE 设备的空口信号是加密的。安卓 HCI 抓包针对的是 CPU 与蓝牙芯片之间的通信,目的是绕过底层硬件加密,直接获取 APP 层面最原始的“明文应用数据”:
- 应用层 → Host(手机 CPU):生成明文指令
- Host → Controller(蓝牙芯片):打包、加密、调频后通过天线发射
注意:HCI 抓包无法获取物理层和链路层数据包,但对于应用层协议逆向已经足够。
方式二:空口抓包(Over-the-Air)
直接捕获物理无线信道上的所有数据(广播、连接请求、跳频数据等),能提供最完整的物理层和链路层信息。通常需要专用硬件抓包设备:
- 基于 nRF52832 的 RF-DG-32A 抓包工具
- TI CC2540 USB Dongle
以 RF-DG-32A 为例,插入 USB 后在 Wireshark 中选择对应 COM 端口并指定目标 MAC 地址即可监听。此方法不依赖主机协议栈,对分析私有协议至关重要,但成本较高。
2.3 Android HCI 抓包实操步骤

在正式抓包之前,可以先通过蓝牙调试软件(如 nRF Connect)扫描 XFLY 的 GATT 服务,通过只读 / 可写属性识别出控制信号服务和反馈服务(如电量反馈)。
Step 1:开启开发者模式
打开 关于手机,连续点击 版本号 直至提示 “开发者模式已开启”。
Step 2:开启 HCI 日志记录
- 进入 设置 → 开发者选项
- 找到并开启 启用蓝牙 HCI 信息收集日志
- 重要:开启后必须关闭并重新打开一次蓝牙,日志才会开始记录
Step 3:操作 APP 并导出日志
使用 Flying App 对扑翼机进行操作(推动摇杆、起飞、转弯等),操作完成后日志文件会写入设备存储。
Step 4:通过 ADB 导出数据包
# 进入手机 shell
adb shell
su
# 进入蓝牙日志目录(不同品牌路径可能不同)
cd /data/misc/bluetooth/logs
ls
# 复制到 SD 卡并拉取到电脑
cp btsnoop_hci_xxx /sdcard/
exit
exit
adb pull /sdcard/btsnoop_hci_xxx .
导出的 btsnoop_hci 文件可以直接拖入 Wireshark 进行 BLE 通信分析。不同手机品牌抓取的文件格式可能有差异(如小米手机可能导出为 .cfa 格式),但均可用 Wireshark 打开。
三、Wireshark 数据包分析
3.1 界面概览
使用 Wireshark 打开捕获的数据包文件,主界面分为三部分:
- 顶部 — 数据包列表:按时间顺序显示所有包(序号、时间戳、源 / 目标地址、协议类型)
- 中部 — 协议详情:所选数据包的协议树状解析
- 底部 — 原始字节流:数据包的十六进制内容

3.2 协议过滤与识别
初始数据流中会包含大量广播包(LE LL 格式)。针对 XFLY 的控制数据,需重点关注建立连接后的应用层数据:
- 输入
bluetooth可筛选所有蓝牙相关数据包 - 输入
att可筛选 ATT(属性协议) 数据包 — BLE 设备进行数据读写的主要载体,很可能承载了 XFLY 的舵机控制指令

3.3 关键信息提取
- 连接参数:分析连接建立过程,获取连接间隔等参数
- 定位控制指令:在连接后的数据交互中,定位
Write Request / Command(写操作)或Notification(通知)数据包,这些包通常包含实际的控制指令 - 功能映射:通过对比不同操作(推动摇杆、拨动开关)产生的数据包差异,逐步映射出数据字节与具体控制功能(副翼、升降舵、襟翼偏移量)之间的对应关系
技巧:启用 “起飞混控” 等特殊功能时,观察数据流中是否出现特定的特征字节序列,有助于识别功能控制字段。
筛选出手机与扑翼机的通信数据包后,根据时间戳和 value 值即可大致推断出发送信号与对应功能的映射关系。
四、实现逆向
在完成协议分析并理解数据包结构后,即可着手实现逆向控制。
4.1 协议模拟与重现
根据分析结果,编写程序模拟 XFLY 接收机的行为:
- 使用蓝牙库(如 Python 的
bleak、Android 的BluetoothGattAPI)按照捕获到的连接序列与参数发起连接 - 构造符合 XFLY 协议格式的数据包,向接收机发送控制指令
- 关键:精确复现指令的数据结构、校验方式(如果有)以及发送时序
4.2 功能映射与控制
将分析得到的字节映射关系转化为可编程的控制接口。例如,确定控制副翼偏转量的具体字节位置和取值范围(对应 “混控比率”,调整范围为 ±100%)。在此基础上,开发上层控制应用,将用户输入(虚拟摇杆、外部硬件)实时转换为正确的协议数据包。
4.3 测试与验证

在受控环境中进行严格测试:
- 验证能否成功建立连接、稳定传输指令并准确驱动舵机
- 测试边界情况:所有通道极限值、混控功能开关等
- 可能需要反复抓包 → 分析 → 调整代码的迭代过程
示例:Python bleak 测试脚本片段
try:
# await client.write_gatt_char(CHAR_ACC1, bytes.fromhex("f9045101565a5201535a"))
await asyncio.sleep(0.3)
await client.write_gatt_char(CHAR_ACC1, bytes.fromhex("f1fb")) # 油门控制
await asyncio.sleep(0.2)
# await client.write_gatt_char(CHAR_ACC1, bytes.fromhex("fc3d72cc1bad602bde853a047de6d7fee1"))
await asyncio.sleep(0.2)
# await client.write_gatt_char(CHAR_ACC1, bytes.fromhex("fd6a1e11dcf394c8799f8862c05da38654"))
await asyncio.sleep(0.2)
print(" ACC1 序列发送完成")
except Exception as e:
print(f" 发送失败: {e}")
完整代码见:XFLY / scripts
通过以上步骤,即可完成对 XFLY 蓝牙遥控系统的逆向工程,并实现基于自定义软硬件的第三方控制能力。
五、参考资料
- 项目源码:https://cnb.cool/1255027942/cloud/XFLY(强劲动力,源自 CNB)
- BLE 蓝牙协议:抓包实战 (HCI + 空口) — 萌蘖向阳成参天