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 工程:
/home/hicode002/qcomuefi/boot_images/boot_images/edk2/Build/QcomTest/DEBUG_GCC49/AARCH64/QcomPkg/QcomTestPkg/VbRwStateApp/VbRwStateApp/DEBUG/AutoGen.cUEFI 应用入口流程
start() (0x1000) — 入口点
│ start(ImageHandle, SystemTable)
│ ├── sub_1080() → 初始化 UEFI 运行时/启动服务表
│ ├── sub_12A8() → 核心攻击逻辑
│ └── sub_1244() → 注册 ExitBootServices 事件回调- sub_1080 — 初始化阶段
依次获取并验证 UEFI 核心表:
| 函数 | 作用 | 保存到 |
|---|---|---|
| sub_2348 | 获取 Runtime Services Table (gRT) | qword_80B8 |
| sub_23A8 | 获取 Boot Services Table (gBS) 和 ImageHandle | qword_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 可用 | - |
- sub_12A8 -> sub_12CC — 核心攻击逻辑
这是整个利用的核心,操作 VerifiedBoot 协议:
│ 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 锁定状态
- 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_14F0 | 0x14F0 | DebugPrint — 格式化调试输出(DebugLib.c) |
| sub_1CF4 | 0x1CF4 | ASSERT 断言处理器,带调用栈保护 canary(qword_80B0) |
| sub_25F0 | 0x25F0 | Print — 宽字符串格式化输出到 UEFI console |
| sub_304C | 0x304C | UnicodeSPrint/AsciiSPrint — 核心格式化打印引擎(PrintLibInternal.c) |
| sub_4F4C | 0x4F4C | ReportStatusCode — 向 UEFI 报告状态码 |
| sub_2064 | 0x2064 | CopyMem — 内存拷贝 |
| sub_5524 | 0x5524 | AsciiStrnCpyS — 安全字符串拷贝 |
所有函数都实现了 栈保护 canary(检查 qword_80B0),这是 EDK2 DEBUG 构建的标准安全机制。
攻击原理总结
这个利用利用了以下安全链的断裂:
- 工程 ABL 开放 fastboot boot(零售版禁止),绕过了第一道防线
- 删除 pvmfw + vbmeta 关闭了 AVB 的链式验证,使设备不再校验镜像签名
- VbRwStateApp 直接调用 Qualcomm 私有的 VerifiedBoot UEFI 协议,将设备的锁定状态字节改为"已解锁"状态,使 Bootloader 变为永久解锁
这个攻击的关键在于:一旦 AVB 验证被关闭(GPT 中移除了 vbmeta),VerifiedBoot 协议的写操作就不再受到保护,UEFI 应用可以直接修改设备的锁定状态。修改后设备会认为 Bootloader 已正常解锁,从而允许启动任意自定义镜像。