☰
open_oura安卓App逆向完全指南:Oura BLE常量、认证操作与Realm密钥提取全流程
2026/11/5 5:23:14 网站建设 项目流程

open_oura 是一个纯 Rust 实现的 Oura Ring 开源工具集,本项目通过逆向官方安卓 App,完整还原了 Oura BLE 协议的常量定义、App 级认证操作(nonce 挑战/加密应答),并给出在 Root 手机上提取 Realm 数据库密钥的全流程方法。跟随这篇指南,你将掌握从反编译 APK 到成功提取 16 字节 auth_key 的每一步。

为什么要逆向 Oura 安卓App?

Oura 戒指的电池、历史事件等核心数据都受App 级认证保护:连接后必须通过一次密钥挑战才能读取数据。官方安卓 App 是唯一"知道"这把 16 字节密钥的地方——它存储在本地的 Realm 数据库(DbRingConfiguration.auth_key)中。

逆向的目标非常明确:

  1. 找出 App 里的BLE GATT 常量(服务/特征 UUID)
  2. 还原认证操作的请求/响应字节格式
  3. 弄清密钥如何生成与加密
  4. 在 Root 手机上提取 Realm 中的密钥,供 open_oura 的 Rust 客户端使用

全部成果沉淀在 docs/android-app-reversing.md,配合 docs/horizon-ring3-protocol-cheatsheet.md 可对照实际抓包验证。

逆向环境准备:反编译工具链

项目使用以下工具组合完成 APK 反编译(详见 docs/android-app-reversing.md 的 Tools 一节):

工具用途
apkeep从 APKPure 下载com.ouraring.oura的 XAPK 包(版本 7.15.0)
apktool解包资源与 manifest
jadx反编译 dex 为可读 Java 源码

如果要从零开始,先克隆仓库:

git clone https://gitcode.com/gh_mirrors/op/open_oura

反编译输出的目录(reverse/、captures/)都被 gitignore,只在本机保留——这是逆向项目的标准安全习惯。

从App中提取到的Oura BLE常量

jadx 反编译后,com/ouraring/ourakit/internal/Constants类直接暴露了全部 GATT 定义。这些常量是 Ring 3/4/5 三代通用,也是 open_oura 客户端能跨代工作的基础:

常量UUID / 值说明
戒指服务98ED0001-A541-11E4-B6A0-0002A5D5C51BGATT Service
读/通知特征98ED0003-A541-11E4-B6A0-0002A5D5C51B响应与通知通道
写特征98ED0002-A541-11E4-B6A0-0002A5D5C51B协议请求通道
充电器服务8BC5888F-C577-4F5D-857F-377354093F13充电盒专用
厂商 ID0x02b2广播厂商数据前缀

📌 协议帧格式为tag | length | payload,扩展操作统一使用外层 tag0x2f,第一个 payload 字节作为扩展操作码。

认证操作全解析:三步完成BLE握手

App 在com/ouraring/ourakit/operations下有明确的官方操作类,逆向后得到三步认证流程:

第一步:GetAuthNonce(请求随机数)

  • 请求字节:2f 01 2b(tag0x2f,扩展 tag0x2b)
  • 响应:外层 tag0x2f+ 扩展 tag0x2c,nonce 从响应索引[3, 18)拷贝,固定 15 字节

第二步:Authenticate(加密应答)

  • 请求字节:2f 11 2d+ 16 字节加密后的 nonce
  • 响应:扩展 tag0x2e,认证结果在响应第 3 字节

第三步:SetAuthKey(首次配对写入密钥)

  • 请求字节:24 10+ 16 字节密钥
  • 响应 tag0x25,第 2 字节为结果:0x00成功;0x05表示出厂测试缺失(可安全忽略)

⚠️ 注意区分:SetAuthKey只在戒指出厂重置后首次配对时使用;已配对的戒指不能重新写入密钥,必须复用原有的 auth_key——这正是需要提取密钥的原因。

密钥生成与AES加密原理

逆向还还原了两个关键算法细节:

密钥生成(RingOperations.i()[B):生成随机UUID→ 写入 16 字节小端ByteBuffer(先写 most-significant 64 位,再写 least-significant 64 位)。非生产构建则返回静态测试密钥。

nonce 加密:戒指与充电器认证路径均使用AES/ECB/PKCS5Padding:

  • 输入:15 字节 nonce
  • 处理:PKCS7 补齐到 16 字节,单次 AES-128 加密
  • 输出:16 字节密文 → 这就是"15 字节 nonce 为什么变成 16 字节"的答案

open_oura 在 crates/oura-protocol/src/auth.rs 用 Rust 精确复刻了这套加密,并带有已验证的已知答案测试向量(known-answer test),保证与 App 行为逐字节一致。

Root手机提取Realm密钥:完整流程

密钥存储位置(Realm 模型字段):

  • 戒指:DbRingConfiguration.authKey(序列化名auth_key)
  • 充电器:DbAccessoryConfiguration.authKey

方法一:Python 辅助脚本(推荐起步)

项目提供 tools/android_oura_key_extract.py,在 Root 手机(Magisk)上执行:

adb devices -l adb shell 'pm list users' adb shell 'pm list packages | grep oura' python3 tools/android_oura_key_extract.py --serial 50380B2617647259

脚本的工作方式:

  1. 遍历所有 Android 用户(Oura 可能装在/data/user/10等次要用户下,而非/data/data)
  2. 拉取 App 日志与assa-store.realm到captures/android/(0600权限,绝不打印密钥)
  3. 以auth_key、serial_number、DbRingConfiguration为锚点,在 Realm 文件附近窗口内扫描高熵 16 字节候选(Shannon 熵 ≥ 3.4)
  4. 唯一候选 → 直接写出密钥文件;多个候选 → 写入候选清单待 BLE 验证

方法二:Realm JS 精确读取(最可靠)

tools/extract_oura_realm_key.js 用realm@20包以只读模式打开 Realm 文件,按serial_number过滤DbRingConfiguration行,取in_active_use === true的活跃行,校验auth_key长度为 16 字节后写出:

npm install realm@20 node tools/extract_oura_realm_key.js assa-store.realm <序列号> oura-android-auth.key

🔑 实测案例(2026-07-02,Pixel 8):工厂重置戒指 → 官方安卓 App 重新配对 → 从assa-store.realm成功读出活跃 Ring 5 行(serial_number、mac_address、android_ble_identifier、16 字节auth_key),密钥写入oura-android-auth.key。

验证提取的密钥

把密钥交给 open_oura 的 Rust CLI 验证:

cargo run -p oura-cli -- --key-file captures/android/oura-android-auth.key info

Frida与APK补丁:走过的弯路

项目也尝试过更"激进"的路子,结论记录在案(见 docs/android-app-reversing.md):

  • Frida 运行时补丁:tools/frida/oura_bond_bypass.js 可 hookRxBleRingBondConnector.isBonded/connect绕过绑定检查,但 Frida 17.15.3 在该 App 上触发 nativeSIGBUS崩溃,目前不可行
  • 静态 APK 替换:apktool 重打包或只替换classes5/6.dex均因资源 ID/初始化失败崩溃
  • 最终结论:已配对戒指必须复用 App 生成的密钥(新生成密钥无法匹配戒指侧已安装的密钥);从 Realm 直接提取才是最优路线,而非 APK 替换

Ring 5 实机验证:与逆向结果完全吻合

2026-06-21 对本地 Ring 5 的实测(docs/ring-5-observations.md):

  • 请求2f012b→ 响应2f102c 490a55be3b8169e3f24aa279f1e55a
  • 解析出 15 字节 nonce490a55be3b8169e3f24aa279f1e55a

与反编译的 Android App 逻辑、Ringverse 的 Ring 4 笔记三方一致——证明逆向出的协议细节可直接用于实机通信。

相关文件速查

资料路径
逆向总文档docs/android-app-reversing.md
协议命令速查表docs/horizon-ring3-protocol-cheatsheet.md
Ring 5 实测记录docs/ring-5-observations.md
AES 认证实现crates/oura-protocol/src/auth.rs
Root 提取脚本tools/android_oura_key_extract.py
Realm 密钥读取tools/extract_oura_realm_key.js
Frida 绑定绕过tools/frida/oura_bond_bypass.js
Rust 客户端用法crates/README.md

总结:逆向得到的完整链路

反编译APK → BLE常量 + 三步认证协议 → 密钥存储于Realm ↓ Root手机拉取 assa-store.realm → 提取16字节 auth_key ↓ open_oura Rust CLI (--key-file) → 本地免云端读取戒指数据

整个流程的核心收获:Oura 的 App 级认证只是"15 字节 nonce 挑战 + AES-128/ECB 应答",复杂度全在密钥管理上——密钥由官方 App 本地生成并锁在 Realm 数据库里。掌握这条链路后,你就可以用 open_oura 在本地完整同步、存储并分析戒指数据,无需 Oura 云端。

💡安全提示:密钥文件权限请保持0600,切勿提交到任何代码仓库;破坏性命令(如factory-reset)在 open_oura 中均需显式--yes确认。

【免费下载链接】open_oura

A Rust toolkit for the Oura Ring (Gen 3/4/5): reverse-engineered BLE protocol, event decoders, and reimplemented>项目地址:https://gitcode.com/gh_mirrors/op/open_oura

点击查看免费下载
上一篇:完整环境配置清单:ZenTorch、ZenDNN、PyTorch 与 vLLM 四件套版本兼容表(Phi-4-reasoning-plus-w4a16-llmcompressor 专用)
下一篇:embeddinggemma-2-nvfp4 5分钟快速上手:如何在 Apple Silicon 上生成第一个文本向量嵌入

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询