一次小米手环BLE通信协议的逆向之旅
0x0 前言
纯逆向新手,接触逆向两个月左右。
目前拥有一台小米手环4带有NFC功能的设备,在内置智能语音助手小爱同学的基础上能够实现语音指令与设备互动的功能。出于对其实现原理的好奇心以及希望进一步扩展其功能的目的, 我决定进行逆向研究。目前关于Miband系列的研究主要集中在Miband3阶段, 对于Miband4的新功能而言, 我尚处于最初的探索阶段
0x1 逆向前准备
首先,在使用智能手表上的语音助手之前,请确保你的智能手机与之实时连接,并使...持续处于后台状态。值得注意的是,在这种情况下,默认情况下智能手表并不会自带完整的语音识别功能。推测其可能是将来自身体的声音传感器收集的数据传输至智能手机端,并由该设备执行一定的数据处理流程(如自然语言处理),随后将结果返回至智能手表。
而在安卓中,想要实现BLE(低功耗蓝牙)通讯,必须要调用
_复制代码_ _隐藏代码_ boolean android.bluetooth.BluetoothGatt.writeCharacteristic(BluetoothGattCharacteristic characteristic)
具体API可以参考Google的
我们就从这里开始入手。
0x2 开始逆向
通过调用Jadx库来访问小米运动APP的资源,并获取并分析其源代码内容。注意到存在大量代码混杂的情况;然而无需过分担心这一点。
通过我们的代码分析工具对'writeCharacteristic'进行定位,最终成功提取了相关数据.

此处省略代码查找过程,最终我们找到了实际发送字节流的函数。

我们继续向上追踪引用,在多数情况下可能无需复杂的动态分析就能立刻识别出其数据包架构。

Jadx反编译失败了...Emm....不管了,直接Hook吧。
我们可以使用自定义钩子发送数据包的函数来了解该数据包的具体内容。当然也可以直接使用安卓系统提供的API来避免遗漏。在这里选择后者。

已经实现了这些包的结构都很明显;其中大部分是字符串和一些整数,并未采用任何加密技术;只需通过对比分析即可明确其内容。接下来我们将重点分析小爱同学的通讯协议以及小米手环认证算法。
0x3 小爱同学的通讯协议
为了获取小爱同学的交互包, 我们需要开发一个能够捕获蓝牙设备上字节流数据的应用程序。在Android系统中, 这种数据捕获功能通常采用的是回调机制, 具体实现时采用的是回调机制, 因此我们需要开发一个能够钩子地访问并处理这些回调函数的应用程序.
_复制代码_ _隐藏代码_com.xiaomi.hm.health.bt.O00000oO.O00000Oo.onCharacteristicChanged(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic bluetoothGattCharacteristic)

这样我们也能抓到从手环发到APP的包了:

因为我具备了正面开发的经验,在此情况下基于以往经验推断可知,在最初的几个软件包中主要涉及到了状态交换操作。这些包仅涉及到了状态交换操作:包括启动录音操作、切换用户界面等基础功能。而后续对声音数据进行解密才是整个系统的核心功能。
通过细致地分析这些声音数据包的结构组成后发现其中第一个字节编码标识了数据包类型第二个字节则编码了数据包的序列号这可能是一种为了避免数据包在传输过程中发生顺序颠倒(尽管BLE标准中尚未明确这一点)的技术手段接下来应包含的声音数据块初步推测可能为PCM格式但经过进一步分析发现并非如此随后应包含的声音信号可能存在一层额外的编码处理直接获取调用堆栈信息似乎存在困难因此转而采用静态分析的方法来研究APP的行为模式更为合适
通过搜索一些关键词,我找到一些有意思的ENUM。
需要注意的是,在深入分析onCharacteristicChanged函数时,并没有实际意义。因为通常情况下,默认情况下应用通过Intent来进行数据传递,并非直接调用了加密解密功能。
需要注意的是,在深入分析onCharacteristicChanged函数时,并没有实际意义。因为通常情况下,默认情况下应用通过Intent来进行数据传递,并非直接调用了加密解密功能。


我们只要向上查找这个枚举的引用,就找到了解析语音数据包的代码。

嗯,看来是找对了。

该解密函数用于处理敏感信息。可以看出该程序正在遍历一组数据。首先将获取的数据保存至本地存储。随后立即调用了一个辅助功能模块进行后续处理。我们深入分析这个流程以了解其运行机制。

这里显然调用了decode函数,并且根据字符串信息可以确定最终格式为pcm和16k。在解密前的数据类型应为opus类型。

研究人员发现某项目采用了某so库。然而该库采用的是opuss项目的解密机制,并且其源码已公开。因此我们可以尝试使用官方提供的公共库编写一个演示文本来验证其功能。



成功了!这样我们就完成了从声音数据的捕获到声音数据的解密。
0x4 小米手环认证算法
相关应用及其功能模块在未经身份验证的状态下无法运行,在此情况下必须经过身份验证流程。
在互联网上也有关于这类问题的相关文章,在此不妨一读。对于这类问题而言,静态与动态结合的分析方法已经足够。需要注意的是,在该验证包中一个关键参数似乎发生了变化,请与你所查阅的文章进行对比阅读。其核心在于AES加密算法中的数据块与密钥之间的关系研究。

0x5 心得与后记
评估该APP非常简单。整个流程持续了一个下午,并未涉及复杂的加密机制。软件本身并未采取任何防护措施,但也收获颇丰。比如:
从软件调用的API考虑,向上回溯查找
关键词查找
动态静态结合分析
学习一些典型的软件设计模式(作为软件工程的基础学科),基于正向开发思路构建APP(从而能够更快、更高效地进行相关工作)。
其实在这种情况下,还有一种更为简便的方式——那就是通过钩子机制来调用那个记录日志的功能。经过一番巧妙的操作后发现,小米运动的日志系统确实非常详尽。
再贴一个和github老哥亲切交谈的图,貌似小米手环要走向国际化了呢。

