【胖猴小玩闹】智能门锁与网关:云丁鹿客智能门锁BLE通信的分析(下)
2021-05-19 12:00:00 Author: www.4hou.com(查看原文) 阅读量:171 收藏

导语:上一篇文章中我们通过SWD接口提取出了门锁固件,并使用IDA顺利加载了固件,本篇将继续对固件进行分析,研究门锁如何处理手机通过BLE下发BleKey的通信数据。

1. 简介

上一篇文章中我们通过SWD接口提取出了门锁固件,并使用IDA顺利加载了固件,本篇将继续对固件进行分析,研究门锁如何处理手机通过BLE下发BleKey的通信数据。

书接上文,我们仿照果加门锁固件的处理方式,对鹿客门锁的固件进行解析之后,IDA 的导航条如下图所示

图片1.png

图1-1 IDA直接解析固件后的导航条

上图中可以看到,目前固件只有开始的一小部分被解析成代码了,其他绝大部分固件数据都是unexplored状态。浏览固件中的字符串,可以发现如下图所示的内容:

图片2.png

图1-2 固件中的部分字符串

结合被顺利解析的代码片段,我们可以推测目前此部分代码仅仅是bootloader,后续的主程序可能使用了FreeRTOS系统(一种开源的实时操作系统,https://www.freertos.org/)。

针对当前的情况,我们可以选择直接“莽”,即由bootloader开始分析,一直分析到BLE的处理流程,但是由于门锁固件使用了FreeRTOS操作系统,这个分析思路实现起来会更麻烦一点。这里可以选择一种更直接的研究方法:既然门锁电路板上已经提供了SWD引脚,这里我们就看看能不能“投机取巧”一下,直接通过SWD调试,快速定位到固件的关键位置。关于bootloader和FreeRTOS,后续会以一篇番外的形式来分享其分析方法。

2. SEGGER JLink的调试功能

在进行调试之前,先简单介绍一下如何使用SEGGER JLink(下文以JLink代称)的调试功能。上一篇文章中,我们在提取固件时使用了JLink的命令行工具,这个命令行工具也包含了诸如设置断点、暂停CPU核心、读取/写入寄存器或指定位置的内存、单步调试等动态调试所需要的指令,具体可以查阅SEGGER的Wiki(https://wiki.segger.com/J-Link_Commander)。可以选择openOCD配合JLink进行调试,但我们在本篇中暂不介绍openOCD,而是选择另一款调试工具。

在实际调试过程中,命令行工具通常需要搭配IDA使用,用起来非常繁琐,且信息展示不够直观。SEGGER提供了一个图形界面工具——Ozone,可以在一定程度上解决以上问题, 关于Ozone的介绍可以参考SEGGER的官方网站(https://www.segger.com/products/development-tools/ozone-j-link-debugger/),软件以及使用手册的下载页面也可以在这里找到。下载后的安装一路next就可以了,想必大家都很熟练(滑稽)。

安装完成后,可以通过“File->New->New Project Wizard”选项来创建新的项目,创建时需要选择待调试芯片的型号、调试接口类型、通信速率等信息。继续,点击“Debug->Start Debug Session->Attach to Running Program”连接到待调试设备,注意整个调试过程中需要保持电脑、调试器和设备的接通状态,如下图所示。

图片3.png

图2-1 连接到设备

连接到待调试设备后,Ozone可以像IDA一样展示多个subview,这样就可以同步观察很多信息了,下图是笔者某次调试的界面。

图片4.png

图2-2 Ozone调试界面

如上图所示,我们在调试时可以一次性看到寄存器的数据、多个内存区域的数据以及反汇编后的代码,下方的控制台区域可以执行一些指令或预先编写好的脚本,除此之外,左上角的断点设置区域,可以看到断点除了Location以外,还有Type和Extra两个属性, 通过阅读用户手册可以确定这两个属性是用于设置断点类型的,如执行断点,读写断点、TRACE断点等,如下图所示:

图片5.png

图2-3 Ozone中断点的属性

Ozone还提供了很多强大的功能,在后文中,我们用到的时候就会逐一介绍这些功能。

3. 通过SWD接口对门锁进行调试

学习了Ozone的基本使用方法,我们就来调试一下门锁固件。回顾第一篇鹿客门锁的分析文章,我们分析了鹿客门锁与手机app之间的通信数据,知道BLE通信有AES加密保护,联想到果加门锁的分析文章中,我们通过TEA加密使用的常量来定位门锁的通信处理代码,那么这里我们是不是也可以从AES加密入手呢?

3.1 固件中的AES加解密

翻阅门锁MCU的芯片手册可以看到,芯片提供了AES处理模块,该模块的内存映射如下图所示。

图片6.png

图3-1 EFM32中的内存映射

显然,我们假设鹿客门锁使用芯片的AES模块进行加解密操作,而不是自写AES算法,那么必然需要访问0x400E0000~0x400E0400这片区域中的内存地址,那么我们只要在设置适当的读写断点,然后等待手机与门锁进行通信时触发断点就可以了。

在断点设置区域右键,选择Set Data Breakpoint,会弹出如下图所示的窗口, 

图片7.png

图3-2 设置数据端点

上图中的设置,表示当CPU向0x400E00XX地址写入数据时触发断点。

断点设置完成之后,在手机上点击开锁,由于我们设置的数据断点是监控一片内存区域,所以开锁过程中会多次被触发,后可以看到如下图左侧的一小段代码,右侧是执行到0xED0C地址时的寄存器数据。

图片8.png

图3-3 写入待解密数据的断点

上图中,0x400E001C地址(R0 + 28)是AES_DATA寄存器,这一小段代码所处的函数向AES_DATA寄存器写数据,应该就是AES的处理函数(下文以AESFunc代称)。回溯调用栈,可以找到调用AESFunc的外层函数,以及AESFunc函数的起始地址,进而使用IDA的F5功能对AESFunc函数进行分析,如下图:

图片9.png

图3-4 AESFunc函数的伪代码

结合芯片手册,由伪代码很容易能判断出AESFunc各个参数的作用,在本系列第一篇文章中,我们已经知道了开锁时的解密密钥就是BleKey,而门锁BleKey的获取过程,是由服务器下发一组数据totalData至手机app,app没有进行任何处理,直接通过BLE通信转发给了门锁。那么,接下来看一看门锁是如何处理totalData的。

3.2 门锁获取BleKey的过程

首先我们需要看一下,totalData的内容是什么,如下图所示:

图片10.png

图3-5 totalData字段及其base64解码数据

可以看到totalData是一串二进制数据经过base64编码后的结果,红框之前的部分可以视作数据的header,包含消息头、数据包序号、校验等内容, header之后的body部分,即红、蓝、黑框中的数据,这三组数据的结构是相同的,如下图所示:

图片11.png

图3-6 totalData中payload用到的数据结构

红框中data_type为0x03的数据,其data_content=0x5FFFECAE,该部分与AES根密钥密文有关。totalData的body部分还有两组数据,其具体作用不再详细说明,说太多有些不妥。

接着,我们在AESFunc的入口下一个断点,可以看到BleKey的值如下图所示:

图片12.png

图3-7 内存中的BleKey

从图3-5和图3-7中看不到BleKey和totalData之间的联系,想必二者之间还是经过了某些解密或解码转换,我们需要继续寻找门锁对totalData的处理过程。保持AESFunc函数的断点,在调试过程中可以发现totalData也是经过 AESFunc函数进行解密的。此时,回溯调用栈即可找到如下图所示的关键代码。

图片13.png

图3-8 totalData数据的处理

上图中的AESEntry函数为AESFunc的封装,这部分就是由totalData生成BleKey的核心代码,该流程可以整理为下图。

图片14.png

图3-10 BleKey获取流程图

在这个流程中,如果没有根密钥就无法解密得到BleKey,通过调试可以找到根密钥在Flash中的存储地址是0x7E09C。

4. 总结

鹿客门锁的系列文章就先到这里,其他的功能逻辑分析就不再做过多讨论,感兴趣的读者可以自行探索。在关于鹿客的第一篇文章中,我们通过逆向手机app知道了门锁蓝牙功能的通信数据有AES加密保护;第二篇文章分享了如何使用SWD接口提取固件;本篇文章进一步通过对门锁固件的调试,来分析门锁获取BleKey的过程。在下一篇番外中,我们会介绍关于鹿客门锁的其他分析技巧,但不会再更多的讨论鹿客门锁的运行逻辑了,感兴趣的同学请多多关注我们的后续文章。最后,希望大家都能有所收获。

Light & Yimi Hu @ PwnMonkeyLabs

本文为 胖猴实验室 原创稿件,授权嘶吼独家发布,如若转载,请注明原文地址


文章来源: https://www.4hou.com/posts/n79W
如有侵权请联系:admin#unsafe.sh