Skip to content

SM8750 Ennea IMG

有技术的神人我见得多了。

攻击负载结构

攻击负载是一个 boot.img,经 magiskboot.so 解压后得到约 5000 KB 的 kernel。这个 kernel 并非普通 Linux 内核,而是一个 EDK II UEFI 固件,其中包含一个 UEFI 应用 LinuxLoader。

从编译路径可知,对应的 PE32 body 实际上是一个名为 VbRwStateApp(Verified Boot Read/Write State Application)的 UEFI 应用,编译自 Qualcomm 的 EDK2 工程:

text
/home/hicode002/qcomuefi/boot_images/boot_images/edk2/Build/QcomTest/DEBUG_GCC49/AARCH64/QcomPkg/QcomTestPkg/VbRwStateApp/VbRwStateApp/DEBUG/AutoGen.c

UEFI 应用入口流程

start() (0x1000) — 入口点

text
│ start(ImageHandle, SystemTable)
│   ├── sub_1080()  → 初始化 UEFI 运行时/启动服务表
│   ├── sub_12A8()  → 核心攻击逻辑
│   └── sub_1244()  → 注册 ExitBootServices 事件回调
  1. sub_1080 — 初始化阶段

依次获取并验证 UEFI 核心表:

函数作用保存到
sub_2348获取 Runtime Services Table (gRT)qword_80B8
sub_23A8获取 Boot Services Table (gBS) 和 ImageHandleqword_80C0, qword_80C8, off_80D0
sub_26E0(空操作,返回 0)-
sub_28B4获取 HOB List (Hand-Off Block)qword_80D8
sub_2AA8通过 gBS->CreateEvent 创建事件dword_80E4, qword_80E8
sub_2D94验证 ARM Architectural Timer 可用-
  1. sub_12A8 -> sub_12CC — 核心攻击逻辑

这是整个利用的核心,操作 VerifiedBoot 协议:

text
│ sub_12CC():
│   1. gBS->LocateProtocol(&VerifiedBoot_GUID, NULL, &Interface)
│      // GUID: {8E5EFF91-21B6-47D3-AF2B-C15A01E020EC}

│   2. Interface->VBRwDeviceState(READ_CONFIG, Buffer, 3344)
│      // 读取设备当前的 AVB 配置状态

│   3. Buffer[13] = 1   ← 修改配置字段
│      Buffer[14] = 1   ← 修改配置字段

│   4. Interface->VBRwDeviceState(WRITE_CONFIG, Buffer, 3344)
│      // 将修改后的 AVB 配置写回设备

│   5. Print "VbRwStateApp: VBRwDeviceState(WRITE_CONFIG) success."

关键发现:

  • VerifiedBoot 协议 GUID: {8E5EFF91-21B6-47D3-AF2B-C15A01E020EC}(Qualcomm 私有协议)
  • 从设备读取 3344 字节的 AVB 配置数据
  • 修改 偏移 13 和 14 处的两个字节,将它们设为 1
  • 将修改后的配置写回,从而改变设备的 Verified Boot 锁定状态
  1. sub_1244 — 收尾

通过 gBS->CreateEventEx 注册 ExitBootServices 事件,确保在退出 UEFI 启动服务前完成清理。

完整的解锁攻击流程

│ ┌─────────────────────────────────────────────────┐ │ │ 第一步:刷入工程 ABL │ │ │ • 零售版 ABL 禁用了 fastboot boot 和 flash │ │ │ • 工程 ABL 开放这些命令 │ │ │ • 通过 EDL 模式或漏洞刷入 │ │ └───────────────────┬─────────────────────────────┘ │ ▼ │ ┌─────────────────────────────────────────────────┐ │ │ 第二步:刷入修改的 GPT 分区表 │ │ │ • 删除 pvmfw 分区(Protected VM Firmware) │ │ │ • 删除 vbmeta 分区(AVB 验证元数据) │ │ │ → 彻底关闭 Android Verified Boot 的链式验证 │ │ └───────────────────┬─────────────────────────────┘ │ ▼ │ ┌─────────────────────────────────────────────────┐ │ │ 第三步:fastboot boot 攻击负载 boot.img │ │ │ ┌──────────────────────────────────────────┐ │ │ │ │ boot.img │ │ │ │ │ └── kernel (EDK II UEFI 固件) │ │ │ │ │ ├── 显示驱动(FrameBuffer) │ │ │ │ │ ├── USB/串口驱动 │ │ │ │ │ ├── LinuxLoader.efi │ │ │ │ │ │ └── PE32 body = VbRwStateApp │ │ │ │ │ └── 其他 DXE 驱动 │ │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ │ VbRwStateApp 执行: │ │ │ → LocateProtocol(VerifiedBoot) │ │ │ → VBRwDeviceState(READ) 读取 AVB 状态 │ │ │ → 修改配置字节 [13]=1, [14]=1 │ │ │ → VBRwDeviceState(WRITE) 写入解锁状态 │ │ │ → 设备 Bootloader 永久解锁 │ │ └─────────────────────────────────────────────────┘

关键辅助函数

函数地址作用
sub_14F00x14F0DebugPrint — 格式化调试输出(DebugLib.c)
sub_1CF40x1CF4ASSERT 断言处理器,带调用栈保护 canary(qword_80B0)
sub_25F00x25F0Print — 宽字符串格式化输出到 UEFI console
sub_304C0x304CUnicodeSPrint/AsciiSPrint — 核心格式化打印引擎(PrintLibInternal.c)
sub_4F4C0x4F4CReportStatusCode — 向 UEFI 报告状态码
sub_20640x2064CopyMem — 内存拷贝
sub_55240x5524AsciiStrnCpyS — 安全字符串拷贝

所有函数都实现了 栈保护 canary(检查 qword_80B0),这是 EDK2 DEBUG 构建的标准安全机制。

攻击原理总结

这个利用利用了以下安全链的断裂:

  1. 工程 ABL 开放 fastboot boot(零售版禁止),绕过了第一道防线
  2. 删除 pvmfw + vbmeta 关闭了 AVB 的链式验证,使设备不再校验镜像签名
  3. VbRwStateApp 直接调用 Qualcomm 私有的 VerifiedBoot UEFI 协议,将设备的锁定状态字节改为"已解锁"状态,使 Bootloader 变为永久解锁

这个攻击的关键在于:一旦 AVB 验证被关闭(GPT 中移除了 vbmeta),VerifiedBoot 协议的写操作就不再受到保护,UEFI 应用可以直接修改设备的锁定状态。修改后设备会认为 Bootloader 已正常解锁,从而允许启动任意自定义镜像。