查看: 44|回复: 0

[转载图文] 一次小米手环BLE通信协议的逆向之旅

[复制链接]

18

主题

23

帖子

1

精华

靶场管理员

Rank: 12Rank: 12Rank: 12

学币
356
荣耀
0
rank
200
违规
0
发表于 2020-5-19 22:48:57 | 显示全部楼层 |阅读模式

0x0 前言
        纯逆向新手,接触逆向两个月左右。
        手头有一个小米手环4NFC版本,内置小爱同学,能够语音对话,进而控制智能家居,做一些操作如设置闹钟等。因对其实现原理好奇,并且想拓展其功能,遂逆向。百度只有Miband3之前的研究,到了Miband4的新功能,我应该还是第一个。
0x1 逆向前准备
        首先,要想使用小米手环中的语音助手,手环必须和手机保持连接,并且小米运动APP要保持后台运行。很显然,小米手环并没有内置语音识别的功能,猜测其应该是将声音传感器的数据发送给手机,然后手机进行语音识别,自然语义处理之后再发送给手环。
        而在安卓中,想要实现BLE(低功耗蓝牙)通讯,必须要调用
boolean android.bluetooth.BluetoothGatt.writeCharacteristic(BluetoothGattCharacteristic characteristic)[/code]
        具体API可以参考Google的
        我们就从这里开始入手。
0x2 开始逆向
        我们使用Jadx打开小米运动APP,查看其源代码,发现大部分代码混淆得有点厉害,不过这不是问题。
        我们直接使用代码搜索功能搜索“writeCharacteristic”,发现了我们想要的结果。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        此处省略代码查找过程,最终我们找到了实际发送字节流的函数。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        我们继续向上查找引用,或许可以直接通过静态分析就知道它的数据包结构呢?结果...

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        Jadx反编译失败了...Emm....不管了,直接Hook吧。
        我们可以通过Hook发送数据包的函数,获取它到底发送了啥。当然也可以直接Hook安卓API,防止遗漏。这里我们这里选择了后者。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        成功了!这些包的结构都很明显,大部分都是字符串和一些整数,且没有加密,通过多次对比和猜测就能知道,就不深入讲了。接下来我们重点分析小爱同学的通讯协议和小米手环认证算法。
0x3 小爱同学的通讯协议
        为了抓到小爱同学的交互包,我们还需要Hook蓝牙的读取字节流的函数。在安卓里面,这个过程是通过Callback实现的,那我们需要Hook那个Callback函数。稍微一查就找到了:
com.xiaomi.hm.health.bt.O00000oO.O00000Oo.onCharacteristicChanged(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic bluetoothGattCharacteristic)

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        这样我们也能抓到从手环发到APP的包了:

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        因为我正向开发的经验还比较多,这里直接猜测就知道,前几个包仅涉及到一些状态的交换,如开始录音,切换UI等。后面的声音数据的解密才是重点。
        我观察这些声音数据包,发现第一个字节代表数据包类型,第二个字节代表数据包序号,应该是防止乱序之类的(不知道BLE有没有乱序这一说)。接下来应该是声音数据,初步猜测是PCM,事实证明不是,还有一层编码。打印调用堆栈似乎是不可行的,我这里继续静态分析APP。
        通过搜索一些关键词,我找到一些有意思的ENUM。
        注意,这里向下追溯onCharacteristicChanged函数是没用的,因为大多数APP都是用Intent间接传递参数的,并不是直接调用解密函数。
        

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        我们只要向上查找这个枚举的引用,就找到了解析语音数据包的代码。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        嗯,看来是找对了。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        这里是解密函数,可以看到他在遍历一个数组,先将元素写到一个文件中,接着又调用了另一个函数,我们跟进去看看。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        这里果然调用了一个decode函数,并且通过字符串我们知道最后的格式应该是pcm,16k。解密之前应该是opus。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        发现他调用了一个so,不过opus的解密代码是开源的,我们直接用开源库写一个demo试试。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
        成功了!这样我们就完成了从声音数据的捕获到声音数据的解密。
0x4 小米手环认证算法
        小爱同学等相关功能在未认证的情况下是不能使用的,所以有一个认证过程。
        这个网上也有相关的文章,静态动态结合分析就行了,不过提醒一点,那个验证包的一个参数貌似变了,跟我网上搜索的文章讲的不一样。主要就是AES算法的data和key。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
0x5 心得与后记
        分析这个APP很简单,整个过程花费了一个下午,也没啥复杂的加密流程,软件本身也没保护,但还是学到很多,比如:
  • 从软件调用的API考虑,向上回溯查找
  • 关键词查找
  • 动态静态结合分析
  • 掌握一些软件设计模式(软件工程这门学问),APP正向开发思路,能更快更好的猜想。
    其实,还有一个更简单的方法,那就是Hook那个打印日志的函数,等我一波骚操作后才发现,小米运动的日志是真详细(逃)。
    再贴一个和github老哥亲切交谈的图,貌似小米手环要走向国际化了呢。

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅
  

一次小米手环BLE通信协议的逆向之旅

一次小米手环BLE通信协议的逆向之旅

  


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
嘿嘿
快速回复 返回顶部 返回列表