联发科BootROM漏洞深度剖析:从手机变砖到漏洞利用全解析

本文详细记录了作者通过联发科BootROM漏洞修复变砖小米手机的完整过程,包括漏洞发现、逆向分析、内存地址定位和利用原理,深入解析了如何绕过安全认证实现未签名代码执行。

联发科BootROM漏洞深度剖析

一部变砖的小米手机让我在Github上发现了一个使用未文档化联发科BootROM漏洞的项目。该漏洞由Xyz发现,由Chaosmaster实现。这个初始漏洞已经存在相当一段时间了。既然我已经成功修复了手机,我决定记录下修复过程并解释该漏洞的工作原理。这个漏洞允许未签名代码执行,进而让我们能够从手机中读写任何数据。

对于专业人士:你可以直接跳到BootROM漏洞工作原理部分(剧透:它非常简单)。本指南将尝试引导初学者,以便他们能够为自己的手机添加支持。我想展示所有内容,但这会违反联发科的版权,所以我只会展示Boot ROM反编译的片段。

手机变砖与理解SP Flash Tool

我喜欢使用小米手机,因为它相对便宜,有简单的方法解锁bootloader,而且在泰国这里很容易买到。有了解锁的bootloader,我从未陷入无法恢复的启动循环,因为我通常可以进入fastboot模式并重新刷入原始ROM。我通常购买搭载高通SOC的手机,但这次我购买了搭载联发科SOC(MT6873,也称为Dimensity 800)的Redmi 10X Pro 5G。但事实证明:你可能会变砖而无法进入fastboot模式。

几年前,重新刷写联发科手机很容易:进入BROM模式(通常通过按住音量增大按钮并在手机关闭时插入USB),然后使用SP Flash Tool覆盖所有内容(包括boot/recovery分区)。它的工作方式是:我们进入BROM模式,SP Flash Tool将上传DA(下载代理)到手机,SP Flash Tool将与DA通信以执行操作(擦除闪存、格式化数据、写入数据等)。

但现在他们增加了更多安全性:当我尝试刷写手机时,它显示了一个身份验证对话框。事实证明,这不是普通的Mi Account对话框,而是需要成为授权Mi Account持有者(通常来自服务中心)。事实证明,仅仅刷写联发科手机可能会进入启动循环,而无法进入fastboot模式。引用XDA文章中的话:

为Redmi Note 8 Pro开发的开发人员发现,该设备容易因多种原因变砖。有些人在从恢复分区刷写恢复分区时手机变砖,而其他人发现在解锁的bootloader上通过fastboot安装官方ROM也会使设备变砖。小米需要一种更好的方法来解砖其设备,而不是使用授权Mi Account。

我找到了一个ROM改装者,他不得不与互联网上一个 shady 的人打交道,使用远程Team Viewer来修复他的手机。他对MTK BootROM安全性有一些解释。总结:BROM可以有SLA(串行链路授权)、DAA(下载代理授权)或两者都有。如果我们未经授权,SLA会阻止加载DA。而DA可以呈现另一种类型的身份验证。使用自定义DA,我们可以绕过DA安全性,假设我们可以绕过SLA以允许加载DA。

当我读到那些文章时,我决定放弃。我已经准备好放弃我的数据。

MTK绕过

幸运的是,在我手机变砖两天后,我发现了一个针对各种MTK设备的绕过方法被发布了。不幸的是:MT6873尚未支持。要支持一个设备,你只需要编辑一个文件(device.c),其中包含一些地址。其中一些地址可以从外部来源找到(例如从该SOC发布的Linux内核),但大多数地址没有访问BootROM本身是无法找到的。我尝试尽可能多地阅读关于BROM协议的文档。我找到的一些文档:

  • 联发科详情:SoC启动:有指向BROM文档的链接
  • Oxygen Forensic® Detective中对联发科设备的支持(解释BROM保护)

几天后又来了一个运气:Chaosmaster发布了一个通用payload来转储BootROM。我很幸运:通用payload在我的手机上第一次尝试就立即工作,我得到了我的Boot ROM转储。现在我们需要弄清楚要填写哪些地址。在这一点上,我没有其他ROM可以比较,所以我需要聪明地找出这些地址。我们需要找到以下内容:

  • send_usb_response
  • usbdl_put_dword
  • usbdl_put_data
  • usbdl_get_data
  • uart_reg0
  • uart_reg1
  • sla_passed
  • skip_auth_1
  • skip_auth_2

从使用这些地址的主文件中我们可以看到:

  • uart_reg0和uart_reg1是正常工作握手所需的。这些地址可以在公共Linux内核源中找到。
  • usbdl_put_dword和usbdl_put_data用于向我们的计算机发送数据
  • usbdl_get_data用于从计算机读取数据
  • sla_passed、skip_auth_1和skip_auth_2是我们需要覆盖的主要变量,以便我们可以绕过身份验证

我们可以开始反汇编从通用转储器获得的固件。我们需要将其加载到地址0x0。没有多少字符串可供交叉引用,所以我们需要发挥创意。

不知何故,generic_dump_payload可以找到usb_put_data的地址,以便将转储的字节发送到Python脚本。它怎么知道的?generic_dump_payload的源代码可在ChaosMaster的存储库中找到。但我没有更早找到那个信息,所以我只是反汇编了文件。这是一个小二进制文件,所以我们可以使用Binary Ninja轻松逆向工程它。事实证明,它进行了一些模式匹配来查找函数的序言:2d e9 f8 4f 80 46 8a 46。实际上,它搜索具有该序言的第二个函数。

generic_dump_payload中的模式查找器

现在我们找到了send_word函数,我们可以看到发送是如何工作的。事实证明,它通过一次发送一个字节来发送一个32位值。注意:我尝试继续使用Binary Ninja,但在原始二进制文件上查找内存地址的交叉引用并不容易,所以我切换到了Ghidra。在稍微清理代码之后,它看起来像这样:

generic_dump_payload找到的内容

现在我们只需要找到function_pointers的引用,我们就可以找到sendbyte的真实地址。通过查看相关函数,我能够找到以下地址:usbdl_put_dword、usbdl_put_data、usbdl_get_data。注意,漏洞利用可以稍微简化,通过用对usbdl_put_data的调用替换usbdl_put_dword,这样我们就少了一个需要担心的地址。

对我来说最难的部分是找到send_usb_response以防止超时。从主文件中,我知道它需要3个数字参数(不是指针),并且这必须在我们通过USB发送数据之前的某个地方调用。这大大缩小了范围,我可以找到正确的函数。

现在到全局变量:sla_passed、skip_auth_1和skip_auth_2。当我们查看Python中的主漏洞利用时,它首先做的事情之一是读取当前配置的状态。这是通过进行握手然后检索目标配置来完成的。

目标配置

在boot ROM中必须有一个大的"switch"语句来处理所有这些命令。我们可以找到握手字节(A0 0A 50 05)来查找握手例程的引用(实际上找到了两个,一个用于USB,一个用于UART)。从那里我们可以找到大switch语句的引用。

握手

你应该能够找到类似这样的内容:握手后开始处理命令

大switch应该清晰可见。

处理各种命令的switch

现在我们找到了switch,我们可以找到命令0xd8(获取目标配置)的处理程序。注意在python中,代码是这样的:

注意位掩码

通过查看位掩码,我们可以得出结论,构造配置值的函数的名称。例如:我们可以将设置安全启动位的函数命名为bit_is_secure_boot。知道这一点,我们可以检查每个bit_is_sla和bit_is_daa

我们可以从它设置的位来命名函数

对于SLA:我们需要找到调用bit_is_sla的交叉引用,我们可以看到总是咨询另一个变量。如果SLA未设置,或者SLA已经通过,我们被允许执行下一个操作。

查找sla_passed

现在我们需要找到另外两个变量来通过DAA。查看bit_is_daa,我们发现在这个函数的末尾,它调用一个检查我们是否已经通过它的例程。这些是我们要找的最后两个变量。

BootROM漏洞利用工作原理

漏洞利用结果非常简单。

  • 我们被允许上传数据到某个内存空间
  • USB控制传输的处理程序盲目索引一个函数指针表

基本上是这样的:handler_arrayvalue*13;

但实际上有一些问题:

  • 这个数组的值是未知的,但我们知道大多数设备将0x100a00作为其中一个元素
  • 我们可以暴力破解USB控制传输的值来调用payload
  • 我们可能还需要尝试不同的地址(因为并非所有设备都有0x100a00作为可用的元素)

还提供了另一个payload来只是重启设备。这将使找到正确的地址和控制值变得容易。

结束语

虽然当我的手机变砖时我非常沮丧,但解决这个问题的经历非常令人兴奋。感谢Xyz找到这个漏洞,Chaosmaster实现它、简化它,并回答我的问题和审阅这篇文章。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计