0. 启动过程
0x00 BootROM (Primary Boot Loader)
众所周知,一台电脑最小启动时需要 CPU (中央处理器)、Memory (内存)、PM (电源管理) 三个部分,显然外存中的任何操作系统是不包含在内的。我们在上电启动后,首先加载的是 BootROM,这是由芯片厂商提供的代码,被固化在 CPU 内部的某个只读存储器中 (当然也可以是外部),出厂时被烧写后就无法修改。
当上电加载 BootROM 后。Boot Code 开始运行。BootROM 的作用一般有:
A. 初始化芯片内部的 ISRAM (Intelligent SRAM,也就是 Cache) 和 eMMC (也可以是其他存储器) 硬件
B. 从 eMMC 中加载 PreLoader 并释放到 ISRAM 中运行
C. 当找不到 PreLoader 或外部传入某种信号时,开始以预定义的某种标准 (例如 USB、UART) 进行数据传输
D. 运行厂商定制的其他代码
因为 BootROM 是被固化在 CPU 内部的只读存储器的,因此一旦 BootROM 代码出现漏洞,就将是影响所有该 CPU 的 "硬件漏洞",无法通过后续系统更新修补。一些比较知名的 BootROM 漏洞有影响苹果 A4 的 Limera1n (绿雨) 和影响苹果 A11 及以下所有芯片的 checkm8 漏洞、影响非常广的联发科的 amonet、kamakiri 漏洞、被广泛用于 Nintendo Switch 破解的 Tegra X1 的硬件漏洞。一旦 BootROM 出现漏洞,通过一些方法从外部注入一个 payload 来执行一些代码就变为了可能,例如用来加载自制引导。
0x01 PreLoader (Secondary Boot Loader)
当 BootROM 运行完毕,就会把控制权交由 PreLoader。PreLoader 存储在 eMMC 中的 EMMC_BOOT 区块中,可以在后期被任意擦写,但如果 PreLoader 不适用当前平台,可能导致设备变砖。
因为在 BootROM 阶段只初始化了 SRAM,DRAM 需要在 PreLoader 阶段进行初始化,因此 PreLoader 依旧是在 SRAM 中执行的。但是从 PreLoader 阶段开始,便开始执行外部存储器中的东西。PreLoader 的作用一般有:
A. 初始化 DRAM,初始化底层基本环境
B. 释放 LK 到 DRAM 中
C. 如果实现了 ARM Trusted Firmware,则会开始加载 TEE,否则直接加载 LK
直到这里我们才开始加载 DRAM 和 eMMC 中的内容,PreLoader 也承担着操作整个 eMMC 的重任,当系统出现问题时,我们可以通过 PreLoader 提供的 USB 端口或者 UART 串口来重新烧录 eMMC 中的内容。联发科的 PreLoader VCOM 端口、高通的 9008 端口都是由 PreLoader 提供的。
0x02 TEE 和 RPMB (可信执行环境)
TEE 分区包含了 ATF 和 TEE OS。从加载的顺序来看,TEE OS 的优先级和权限极高,高过 Kernel,与之后的 Android 部分是并行运行的,它分出两个 World: Secure World 和 Non-Secure World 态,一些对安全、版权保护要求较高的操作将会被放入 Secure World 中运行,Secure World 可以访问自身和 Non-Secure World,Non-Secure World 则无法访问 Secure World。
而 RPMB (Replay Protected Memory Block) 是位于 eMMC (其他存储设备同理) 中的一个隐藏区块,用于存放机密数据 (例如序列号、密钥、保修状态)。开机时,PreLoader 会写入 RPMB 鉴权密钥,之后由 TEE OS 提供的相关接口来访问,密钥的生成和使用过程是完全在本地设备中运行的,因此无法在其他设备中产生相同的结果。当设备在解锁 Bootloader、AVB 或者关闭某种安全策略后,RPMB 可能会被锁定而无法访问,获取不到 RPMB 中的密钥的情况下,指纹支付等功能可能会失效。
RPMB 按理来说是不能被任何修改的,但是因为部分漏洞,设备的 RPMB 可能可以被写入、擦除,但是无法被修改,如果厂商额外修改了安全策略,对 RPMB 安全策略进行加固,那么可能也无法通过一般的方法来访问和修改。
TEE OS 有很多类型,也有不少厂商有自己的 TEE OS,当然也有开源的,不同厂商对安全相关的实现并不一样。
0x03 ABL (Android Boot Loader)
当 PreLoader 阶段完毕后,则会开始加载 ABL。ABL 在不同平台上的叫法不同,一般来说,高通平台上叫 abl、aboot,NXP、晶晨的平台上叫做 u-boot,MTK 平台就直接叫 LK 了。但实际上它们内部都运行着 LK (Little Kernel),顾名思义,这是一个微型的操作系统。
ABL 的主要作用是验证和加载 boot.img,常说的解 BL 锁也正是解除这个部分的验证,解除验证后,我们就可以加载补丁过的 boot.img,来运行其他操作系统了。
ABL 不仅是用来加载 boot.img 的,它提供不同的引导选项 (例如组合键,Test Point,或者 misc 分区),用于 Normal boot、加载 recovery,或者是进入 fastboot (fastboot 也存在于 ABL 中,但对使用动态分区的 Android 10+ 来说,fastbootd 并不在这里)。一般来说,启动的优先级是 boot -> recovery -> 其他厂商定义的模式 -> fastboot。
当 ABL 加载完成后,就会开始启动 Linux Kernel 了,在 ABL 阶段产生的一些参数 (例如 androidboot.*
) 会被传递到 Kernel 中,最后进入系统的 prop 配置文件。但在此之前,如果设备实现了 AVB (Android Verified Boot),设备还会进行 AVB 阶段的验证。
0x04 AVB (Android Verified Boot)
AVB 是在 Android 8.0 推出的,作为可选开源模块在源码中提供,Google 建议将其与 Project Treble 和 A/B 分区布局一起使用。
AVB 提供了对只读分区的保护、防止版本回滚的功能。如果你发现你的设备在修改系统分区后重新刷入该分区,结果设备完全无法启动,而是直接进入 fastboot,那么这就是 AVB 的效果。
关于 AVB,Google 官方有很详细的 文档。
在启用 AVB 的设备中,vbmeta 分区负责存储受保护镜像的 vbmeta struct 结构体和 AVB Key,AVB Key 是一对非对称密钥,私钥用来签名,公钥用来验证。vbmeta struct 结构体的定义如下:
而当系统 OTA 后,会触发对 AVB 中 rollback_index 的增加,当要求启动一个 rollback_index ≥ 当前值的系统才能正确启动。下图是 AVB 的启动流程,由 Google 提供:
0x05 Linux Kernel
通过 AVB 验证后,才会开始启动 Linux Kernel,也就是 boot.img 中的 Kernel。也有平台和系统 (例如 Rockchip) 会将这部分拆分开来。
同样在 Android 8.0 正式加入对 Project Treble 与 A/B 的支持后,Google 加入了 System-as-root 的支持,将原先的在 ramdisk.img 中的根文件系统合并到了 system.img 中,因此我们解包 system.img 后并不能直接看到 system 目录下的文件,而是先看到 root。
启动 Linux 内核后,内核会以用户态依次执行 init -> ueventd -> ··· -> zygote -> system_server。但在这之前,还有一道安全策略: dm-verity。
0x06 DM-Verity
不同于 Android 8.0 加入的 AVB,DM-Verity 早在 Android 4.4 就出现了。DM 的意思是 Linux 中的 Device Mapper,这是一种从逻辑设备到物理设备的映射框架机制,而 DM-Verity 则提供了对块设备的完整性检查,包括阻止挂载和写入保护的分区。
在 userdebug 系统中,DM-Verity 可以通过命令 adb disable-verity
来关闭,关闭后则可以挂载 /system、/vendor 等分区
0x07 Android System
历经 8 个步骤,终于到了启动 Android 的时候了,在 Linux Kernel 加载各种服务和 Android framework 之后,Android 系统就启动完成了,进入默认的 Launcher。
1. 安全策略
整个启动过程中,安全密钥的传递是按顺序的,即信任链从 BootROM 阶段的密钥会一层一层接力传递下去,一直到系统启动后依旧在发挥作用。因此常说的解 Bootloader 锁、解 AVB 锁、禁用 DM-Verity,都是禁用这整个过程中的某一个阶段来实现使用自定义操作系统的,如果你修改了某个部分的签名、密钥信息,即使可以成功加载下一个部分,但终究无法通过上个阶段、BootROM 阶段的验证。
在普通用户来说,我们能接触到最底层的可编辑部分就是 boot.img 部分,假如厂商开源了 Kernel 源码,我们还可以修改 Kernel,而再往下的 ABL (LK)、TEE、PreLoader 的闭源部分则不是那么好编辑的了。
有些厂商开放了解锁 BootLoader 的通道,这其实就是禁用了 ABL 阶段对 boot.img 的验证,解锁后我们得以使用第三方 boot.img 和内核。但厂商如果不公开这个通道,在出现比 ABL 更底层的 PreLoader 或者 BootROM 漏洞之前,我们理论上是不可能使用第三方操作系统的 (如果厂商加入了更多的验证,那么依旧是不能启动第三方操作系统的)。
2. 附录
高通 Qualcomm 平台启动过程参考图:
联发科 MediaTek 平台启动过程参考图:
瑞芯微 Rockchip 平台启动过程参考图: