小米手环 8 Pro 自动上传数据到 Obsidian 的思路
内容提要
作者通过逆向工程和编程成功获取小米手环数据,使用mitmproxy抓包分析但无法获取有用信息,通过编写BLE客户端连接手环获取数据,使用Frida和Xposed框架监听和修改数据,探讨后台启动和数据传输问题并提出解决方案。
延伸解读
抓包为何行不通:加密与证书固定
作者尝试用 mitmproxy 抓取小米健康 App 的 HTTPS 请求,虽然通过系统级证书安装成功抓到了流量,但所有请求都经过加密,并带有 signature、hash、nonce 等安全校验,无法直接解析出有用数据。这说明小米健康在传输层做了较强的防护,单纯抓包难以获取步数、睡眠等明文信息,也解释了作者为何转向直接连接手环或逆向 App 内部逻辑。
BLE 直连的局限:连接独占与认证密钥
作者参考开源项目编写 BLE 客户端,试图直接连接手环获取数据,但遇到两个现实障碍:一是 BLE 同一时间只能连接一个设备,官方 App 优先级更高,会抢占连接;二是连接需要 auth_key,虽然可通过第三方网站获取,但作者出于安全考虑不愿使用。这导致 BLE 直连方案在手机日常使用场景下难以稳定运行,最终被放弃。
逆向关键:从数据库到反射获取私有字段
作者在 /data/data/com.mi.health/databases 下发现 fitness_summary 数据库,并溯源到 com.xiaomi.fit.fitness.persist.db.internal 等类,但直接 hook 更新函数无法拿到具体数值。最终通过异常打印调用栈,定位到 DailyBasicReport 和 DailyStepReport 等类,并利用反射访问 private 的 steps 字段,成功获取当天步数。这一过程说明逆向时结合调用栈和反射能有效突破 Kotlin 数据类的
Xposed 插件与 Socket 服务:后台自动化的取舍
作者最终编写 Xposed 插件,hook 小米健康的 KeepAliveHelper.startService 实现后台启动,并复用 CommonSummaryUpdater 获取报告数据。在数据传输上,先后考虑广播、HTTP 服务器,最终选择 Socket 并手搓 HTTP 协议,以便 Obsidian 的 JavaScript 环境通过 HTTP 请求获取每日健康数据。作者也指出该方案目前是半成品,未做明文传输保护,安全性有限。
Q&A
小米手环8 Pro为什么不能像手环7那样通过Zepp获取数据?
小米手环8已经不再支持Zepp,彻底将Zepp废弃(Deprecated),而小米手环7虽然表面上不支持,但可以通过修改QRCode和Zepp安装包的方式使用。
抓包小米健康App时遇到了什么困难?如何解决?
抓包时遇到SSLPinning问题,作者采用mitmproxy加系统级证书的方法,在Magisk中安装ConscryptTrustUserCerts模块将用户级证书挂载到系统级证书目录,成功抓取HTTPS请求,但发现所有请求都经过加密,包含signature、hash、nonce等安全机制,无法获取有用信息。
如何通过BLE客户端直接连接小米手环获取数据?
作者参考了wuhan005/mebeats项目,编写BLE客户端连接手环获取数据,这种方式不需要在手机上操作,Obsidian运行脚本即可自动获取。但需要auth_key,且BLE只能同时连接一个设备,官方App优先级更高,因此该方法未能持续使用。
逆向小米健康App时如何找到步数等健康数据?
作者在/data/data/com.mi.health/databases下发现fitness_summary数据库,通过搜索关键词交叉引用溯源到com.xiaomi.fit.fitness.persist.db.internal类,利用异常查看函数调用栈,最终找到com.xiaomi.fit.fitness.export.data.aggregation.DailyBasicReport类,并通过反射获取private的steps属性。
如何编写Xposed插件来监听小米健康App的数据传输?
作者使用Android Studio创建No Activity项目,配置Xposed依赖和manifest,在assets/xposed_init中指定入口类。通过hook com.xiaomi.fitness.keep_alive.KeepAliveHelper的startService方法实现自启动,然后获取CommonSummaryUpdater实例,调用getReportList方法获取数据,并利用kotlinx.serialization将数据序列化为JSON。
最终如何实现与Obsidian的交互来获取每日健康数据?
作者最终采用Socket实现了一个HTTP服务器,在后台线程中监听端口,处理GET请求,解析路径和参数,调用DailyReportFactory创建对应报告并返回JSON响应。由于Obsidian的Templater环境无法直接使用套接字,因此手搓了HTTP协议,通过HTTP请求获取每日健康数据。