深入解析联发科BootROM漏洞利用机制

本文详细记录了作者通过联发科BootROM漏洞成功修复变砖小米手机的完整过程,包括漏洞发现、BootROM提取、关键地址定位以及认证绕过机制的技术分析,揭示了未签名代码执行的实现原理。

深入解析联发科BootROM漏洞

一部变砖的小米手机让我在Github上发现了一个使用未公开联发科BootROM漏洞的项目。该漏洞由Xyz发现,并由Chaosmaster实现。初始漏洞已存在相当长一段时间。由于我成功修复了手机,本文记录了我的修复历程,并解释了漏洞的工作原理。该漏洞允许未签名代码执行,从而使我们能够读取/写入手机中的任何数据。

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

手机变砖与理解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修改者,他不得不与互联网上的一个可疑人员打交道,使用远程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 设计