mahdi-salmanzade/BeatsBar

GitHub: mahdi-salmanzade/BeatsBar

macOS 菜单栏工具,实时显示 Powerbeats Pro 2 电量与心率,并附带对苹果专有 AACP 蓝牙协议及内核拦截机制的深度逆向工程文档。

Stars: 0 | Forks: 0

BeatsBar

BeatsBar

在 macOS 菜单栏中实时显示您的 Powerbeats Pro 2 的电量和按需读取的心率。

此外,还包含一份对 Apple 专有 AACP 协议的深度逆向工程日志 —— 包括 IOBluetooth.framework 中阻止第三方应用像 iOS 那样读取心率的具体 ARM64 指令。

## 目前提供的功能 - 一个始终显示**实时电量**(左耳塞 · 右耳塞 · 充电盒)的菜单栏项目。 - 一个 **“Start HR session”**(启动心率会话)操作,会持续流式传输**实时 BPM** 直到你手动停止(使用标准的 BLE Heart Rate 配置文件 —— 请参阅下面的注意事项)。 - 一个 **“Launch at login”**(登录时启动)开关。 - 在 `research/PROTOCOL.md` 中提供了专为 Powerbeats Pro 2 制作的完整 **AACP 协议解码**(包括 PSM、握手协议、操作码、帧结构)—— 这是首个针对该设备公开发布的协议图。 - 一份记录了尝试突破 macOS 内核级 L2CAP 策略的文档,包括发生拒绝的具体反汇编位置。 ## 状态 | | | |---|---| | 电量(播放音乐时的实时状态) | ✅ 已发布 | | 心率(会话模式,BLE 0x180D) | ✅ 已发布 | | Powerbeats Pro 2 的 AACP 协议已解码 | ✅ 已记录文档 | | `IOBluetooth` 策略拦截已逆向工程 | ✅ 精确到 ARM64 指令级别 | | 心率(通过 AACP 始终开启) | ❌ 在 macOS 内核层被阻止 —— 请参阅 [JOURNEY.md](research/JOURNEY.md) | ## 界面展示 菜单栏: ``` ♥ 78 46% ``` 点击展开详情: ``` 🟢 Powerbeats Pro connected Heart Rate: 78 bpm Battery: Left 46% · Right 46% · Case 92% Start HR session… HR Mode ▶ Launch at login About BeatsBar… Quit ``` 电池状态会连续以流式传输显示,没有任何多余操作。`♥ 78` 仅在心率会话运行期间出现。 ## HR 的工作原理(以及附带的问题) Powerbeats Pro 2 提供了两种获取心率的途径: 1. **标准 BLE Heart Rate 配置文件**(GATT 服务 `0x180D`)。仅在耳塞处于“健身设备配对”模式时可用 —— 可通过**双击并长按 b 按钮**触发。在此模式下,耳塞会断开音频连接。BeatsBar 使用此路径实现“Start HR session”。该功能可用,但并非始终开启,且每次会话都需要进行手势操作。 2. **Apple AACP**,通过 Bluetooth Classic L2CAP,PSM `0x1001` 传输。这是 iOS 在播放音乐时用来读取心率的通道 —— 无需模式切换,也无需手势。**macOS 阻止第三方应用打开此 PSM。** 该拦截机制存在于 `IOBluetooth.framework` 内部;即使使用 `sudo` 也无济于事。我们已经对其进行了最底层的挖掘;详情见下文及 [`research/JOURNEY.md`](research/JOURNEY.md)。 ## AACP 协议(我们已记录的内容) | 层级 | 详情 | |---|---| | 物理层 | Bluetooth Classic (BR/EDR),与音频链路共享 | | L2CAP PSM | `0x1001`(在 Apple 自己的 SDK 头文件中名为 `kBluetoothL2CAPPSMAACP`) | | SDP 服务名称 | `AAP Server` | | 服务 UUID | `74ec2172-0bad-4d01-8f77-997b2be0722a` | | 帧魔术字节 | `04 00 04 00` | | 帧结构 | `04 00 04 00 ` | | 初始握手 | `00 00 04 00 01 00 02 00 00 00 00 00 00 00 00 00`(必须是第一个数据包) | 一旦通道打开并发送了握手信号: ``` # 订阅所有通知 04 00 04 00 0F 00 FF FF FE FF # 启用 HRM (控制操作码 0x09, 标识符 0x30, 值 0x01) 04 00 04 00 09 00 30 01 00 00 00 ``` 电量报告通过操作码 `0x0004` 传入,格式为 `[count] ([component] 01 [level] [status] 01)*` —— 这与 LibrePods 为 AirPods Pro 2 记录的格式相同。50 Hz 的原始 IMU/PPG 数据流的操作码是 `0x0017`。完整的操作码映射表:[`research/PROTOCOL.md`](research/PROTOCOL.md)。 ## macOS 的阻碍 对于任何第三方应用,`IOBluetoothDevice.openL2CAPChannelSync(_:withPSM: 0x1001, ...)` 都会返回 IOReturn `0xe00002bc`。我们对 `IOBluetooth.framework` 进行了反汇编,找到了产生此错误的具体指令对: ``` IOBluetooth`-[IOBluetoothDevice openL2CAPChannelAsync:withPSM:withConfiguration:delegate:] +136: mov w25, #0x2bc +140: movk w25, #0xe000, lsl #16 ; w25 = 0xe00002bc, the default error ``` `w25` 在函数顶部被加载为“默认错误”,并且只在成功的路径上被清除。对于 PSM `0x1001`,控制流永远不会到达清除错误的代码块 —— 请求在实际的 L2CAP CONN_REQ 通过网络发送出去之前就已经失败了。 我们尝试过: - **公共 API `openL2CAPChannelSync`** → `0xe00002bc`。 - **已弃用的 `openL2CAPChannel:findExisting:newChannel:`** → 走的是相同的内部路径 → 相同的错误。 - **私有 API `_initWithDevice:andClassicPeer:PSM:withServiceUUID:`** + `setupL2CAPChannelForDevice` → 在用户空间创建了一个真实的 `IOBluetoothL2CAPChannel` 对象,但从未触发内核端的 IOService open。 - **`IOBluetoothHCIControllerDisableL2CAPKernelDrivers(true)`** —— 这是一个私有函数,它通过 `IORegistryEntrySetCFProperty` 设置一个内核属性 `DeviceL2CAPOnlyUserClients`。即使以 `root` 身份运行也返回 `0xe0000007`:它需要 AMFI 独立于 unix 权限单独检查的授权 (entitlements)。 - **`BluetoothHCISetupUserClient`** —— 同样的授权门槛,同样的拒绝。 - **监听 PSM 0x1001 上的传入 L2CAP 连接**(注册为服务器)→ 耳塞从不主动发起连接;它们只通过 Apple 自己的流程向“主要”配对主机发起 AAP。 - **嗅探 Continuity 0x07 BLE 近距离广播**以寻找隐藏在加密的 16 字节尾部中的 HR 数据 → 确认那是一个轮换的隐私 MAC,而不是遥测数据。 绕过内核拦截的现实方法(没有一种仅限于用户空间): - **禁用 SIP + AMFI**(`csrutil disable`,`nvram boot-args="amfi_get_out_of_my_way=0x1"`),然后使用正确的授权 plist 对 helper 程序进行签名。 - **DriverKit / kext**,由 Apple 签名 —— 需要付费的开发者注册以及特定于 Bluetooth 的授权审批。 - **外部 USB Bluetooth 适配器**,通过 `_sendRawHCIRequest` 直接驱动无线电模块,手工构造 L2CAP CONN_REQ 数据包。 - **Linux + USB BT 直通** —— LibrePods 在 Linux 上使用相同的握手协议成功连接了相同的耳塞。 位于 [`interposer/aacp_unlock.m`](interposer/aacp_unlock.m) 的 interposer dylib 实现了上述所有用户空间尝试,作为一份记录在案的探索。它成功创建了通道对象,但未能突破内核层。 ## 构建与运行 ``` cd src swift build -c release .build/release/BeatsBar & ``` 该应用程序将安装到您的菜单栏中(没有 Dock 图标)。首次启动时会提示授予 Bluetooth 权限 —— 请点击允许。 系统要求: - macOS 13+ (Apple Silicon 或 Intel) - Powerbeats Pro 2 已与您的 Mac 配对并连接用于音频播放 - Xcode 命令行工具 ## 架构 ``` BeatsBar/ ├── src/ # Swift menu bar app + 0x180D HR session client ├── interposer/ # DYLD_INSERT_LIBRARIES dylib (Objective-C) ├── research/ # Protocol decoding scripts + writeups + opcode map ├── assets/ # Header image ├── docs/ # (reserved for future docs) └── README.md ``` 组件: - **`BeatsBar`** (Swift,`src/Sources/BeatsBar`) —— 基于 `NSStatusItem` 的菜单栏应用。轮询 `system_profiler` 获取电量和连接状态,针对 0x180D 路径运行按需的 `CBCentralManager` HR 会话,并包含一个用于研究的、执行 dylib 的“Kernel mode”存根后端。 - **`aacp_helper`** (Swift,`src/Sources/aacp_helper`) —— 在 Kernel 模式下注入 dylib 启动的小型 CLI 工具;一旦链路层成功打开,它将在 stdout 输出 JSON 格式的 HR 读数。 - **`libaacp_unlock`** (Objective-C,`interposer/`) —— DYLD interposer,混写了 (swizzles) `openL2CAPChannelSync`,并尝试了我们发现的所有用户空间途径。 - **`research/`** —— 用于解析 PacketLogger `.pklg` 捕获数据的 Python 工具、AACP 操作码映射表 (`PROTOCOL.md`) 以及完整的逆向工程时间线 (`JOURNEY.md`)。 ## 许可证 MIT —— 请参阅 `LICENSE`。
标签:AACP协议, ARM64, Beats, BLE, CVE监控, GATT, IOBluetooth, L2CAP, Powerbeats Pro 2, Wayback Machine, 云资产清单, 反汇编, 威胁情报, 开发者工具, 心率监测, 电量显示, 硬件黑客, 系统扩展, 苹果生态, 菜单栏应用, 蓝牙, 逆向工具, 逆向工程