首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从 Apple T2 安全到普通 MCU 启动过程

从 Apple T2 安全到普通 MCU 启动过程

作者头像
云深无际
发布2026-03-30 17:41:03
发布2026-03-30 17:41:03
1480
举报
文章被收录于专栏:云深之无迹云深之无迹

前几天电脑修好以后,我找了专门的 Apple 文档还研究了 DFU 这个东西:

其实还有一个维护的 wiki,那我就不爱看了
其实还有一个维护的 wiki,那我就不爱看了

其实还有一个维护的 wiki,那我就不爱看了

苹果毕竟设备产品这么多,安全上面要下大功夫的;一方面是隐私安全,另外一方面是不想把配件市场给更大商家;在 Intel 时代,在不得已的情况下,外挂了一颗 T2.

是要保护的呀
是要保护的呀

是要保护的呀

然后现代搞了 SOC,更是把这些东西都做在了一起。

哪有怎样,再牛逼也得 SPI
哪有怎样,再牛逼也得 SPI

哪有怎样,再牛逼也得 SPI

这是 doc 里面复杂的架构
这是 doc 里面复杂的架构

这是 doc 里面复杂的架构

然后, Apple 的安全不是“某个密码很复杂”,而是:每一层只信任上一层验证过的东西,这就是典型的 chain of trust(信任链)

这份文档最核心的思想,是信任必须有根,而且这个根必须尽可能不可篡改

这个“根”在 Apple 体系里主要体现为:Boot ROM,制造时固化,不可更改,是最底层硬件信任根;Secure Enclave(安全隔区),独立安全子系统,负责密钥、生物识别、部分高敏感安全逻辑;AES / PKA 等专用硬件引擎,实现密钥不可见的加解密与公钥操作;UID/GID 等硬件绑定密钥材料,把数据和“这台设备”绑定起来;签名验证与启动链,只有受信任的软件才能进入下一阶段执行。

这个是 M4 的主板,我也没有看到雷电的接口不一样
这个是 M4 的主板,我也没有看到雷电的接口不一样

这个是 M4 的主板,我也没有看到雷电的接口不一样

其实是这样的,虽然苹果有两个口,但是是 USB4+霹雳的:

大概是这样
大概是这样

大概是这样

看看 DFU

按照文档的意思,DFU 是底层 iBOOT 下的产物,这段引导是提前写入的,也就是说,除非真真正正的硬件错误,否则只要进入 DFU 就可以重新启动引导。

但是还有一个引导设计,在重新开机后:

还是会把安全的解锁信息带过来
还是会把安全的解锁信息带过来

还是会把安全的解锁信息带过来

在这里有这个描述
在这里有这个描述

在这里有这个描述

另外,还可以进入更多的安全模式:

大开眼界
大开眼界

大开眼界

先看看普通嵌入式的启动过程

一般来说做嵌入式的是要深刻理解这个过程的,但是这个要理解需要学很多计算机组成原理的课程,而且现在很多人也这个文章(但是一眼 AI,我感觉对面复制的老哥可能眼神都涣散了)

苹果安全这些我是没有本事研究,但是我们可以先看看普通的,然后做一些感性的理解也不错。

嵌入式系统的启动过程(Boot Process)其实是所有计算系统最基础的运行机制;无论是 MCU、SoC、手机、路由器、FPGA SoC,还是 PC,本质结构都类似,只是复杂程度不同。

从系统工程角度看,启动流程可以概括为一句话:

从不可修改的最小可信代码开始,一层一层加载更复杂的软件。

所有系统启动都遵循同一个原则:ROM → Bootloader → OS → Application

也就是:

代码语言:javascript
复制
不可修改代码
      ↓
初始化硬件
      ↓
加载更复杂的软件
      ↓
运行系统

原因很简单,上电时:RAM 是空的,CPU 没有程序,Flash 还没被读取;所以必须有一段 CPU 知道在哪里的代码;这就是:Boot ROM。

苹果这个太复杂了,我的看不清
苹果这个太复杂了,我的看不清

苹果这个太复杂了,我的看不清

先看看最简单的启动系统(MCU)

最简单情况,如STM32,启动过程:

代码语言:javascript
复制
Power on
   │
   ▼
Reset
   │
   ▼
PC ← Reset Vector
   │
   ▼
执行 Flash 中代码

CPU 上电后,程序计数器 PC 会被设置为:0x00000000或者某个固定地址;这个地址叫:Reset Vector,这里存放程序入口地址。(因为 CPU 只会忠实的运行 PC 指向的指令)

例如 ARM Cortex-M:

代码语言:javascript
复制
0x00000000   初始SP
0x00000004   Reset Handler

启动过程:

代码语言:javascript
复制
CPU reset
   │
读取 SP
   │
读取 PC
   │
跳转 Reset_Handler

Reset Handler 是 C 程序之前的初始化代码:

代码语言:javascript
复制
Reset_Handler:
    初始化堆栈
    初始化 .data
    清零 .bss
    初始化时钟
    调用 main()

流程:

代码语言:javascript
复制
Reset
   │
startup.s
   │
system_init()
   │
main()

这就是 MCU 启动。

小结一下

开机以后,第一步是重置,所有寄存器保证在可控状态;接着是ARM Cortex-M 处理器复位后,硬件会自动从地址 0x00000000 获取 MSP (主堆栈指针) 初始值以建立内存栈区,随后从 0x00000004 读取 复位向量 并存入 PC(其最低位必须为 1 以进入 Thumb 状态),从而引导 CPU 跳转至 Reset_Handler 开始执行初始化代码及进入主程序。

Reset Handler 是汇编语言,但也是程序,它首先完成 C 运行环境的准备工作,包括通过 初始化堆栈 确保内存空间可用、将 .data 段从 Flash 拷贝到 RAM 以及将 .bss清零;随后配置系统时钟以确保硬件频率正常,最后通过跳转指令调用 main() 函数,实现从底层汇编到上层应用程序的平滑过渡。

另外需要注意,在 Reset_Handler 中,通常会先调用一个名为 SystemInit() 的 C 函数(由芯片厂商提供),它的主要工作就是配置系统时钟(设置 PLL、HSE/HSI、AHB/APB 总线分频等)。只有时钟稳定后,CPU 才能以更快的速度执行后续的 .data 拷贝和 main() 函数。(我们不要小看这个时钟系统,另外 MCU 本来就是数学电路需要时钟)

SoC 启动流程

SoC 比 MCU 复杂很多,因为:OS 很大,存储复杂,有 DRAM。

典型 SoC 启动:

代码语言:javascript
复制
Power on
   │
   ▼
Boot ROM
   │
   ▼
Stage1 Bootloader
   │
   ▼
Stage2 Bootloader
   │
   ▼
OS Kernel
   │
   ▼
Userspace

为什么 Bootloader 要多级

因为Boot ROM 代码必须极小,如:32 KB;所以它只能做:初始化最小硬件,加载 bootloader,而Linux kernel > 10MB,Boot ROM 不可能直接加载。。

Bootloader 的分层

典型 Bootloader:

代码语言:javascript
复制
Stage0  Boot ROM
Stage1  SPL
Stage2  U-Boot
Stage3  Kernel

Stage0 Boot ROM

在芯片内部:ROM code;来初始化 CPU,初始化 SRAM,读取 Boot device,加载 Stage1

Boot device 可能是:

代码语言:javascript
复制
NAND
NOR
eMMC
SD
USB
UART

Stage1 Bootloader(SPL)

SPL,Secondary Program Loader,来初始化 DRAM,然后加载 Stage2

那为什么要单独 SPL?

因为:DRAM 初始化非常复杂,如 DDR 有PLL,timing,calibration;但Boot ROM 不会做这些。

Stage2 Bootloader(U-Boot)

U-Boot 是最常见 bootloader;用来初始化外设,加载 kernel,加载 device tree,加载 initramfs;然后:jump to kernel。

碎碎念

安卓时代喜欢刷机,而且现在也能经常听见要什么解 BL 锁,其实就是这个地方的问题;一个新的 ROM,需要最底层开始一级一级的引导。

再说回STM32 启动流程:

代码语言:javascript
复制
Reset
   │
Boot mode pins
   │
   ├─ Flash
   ├─ System ROM
   └─ SRAM

如果选择:Flash;执行:0x08000000;如果选择:System ROM;进入:ST Bootloader;支持:USART,USB,CAN,I2C。

这里需要骂一下 ADI 的启动
这里需要骂一下 ADI 的启动

这里需要骂一下 ADI 的启动

bootloader 需要我自己写!操。

启动过程中最重要的三件事

启动系统的三个核心问题:

CPU 从哪里取第一条指令,Boot ROM

如何加载更大程序?Bootloader

如何保证安全?Secure Boot(知道大家不爱看,没写)

嵌入式启动的完整结构

最终结构可以总结为:

代码语言:javascript
复制
Power
   │
Reset
   │
Boot ROM
   │
Bootloader Stage1
   │
Bootloader Stage2
   │
Kernel
   │
Init
   │
Applications

步入正题

DFU(Device Firmware Update)模式是 Apple 设备安全架构中一个非常关键但经常被误解的组件。它不是“绕过安全”的后门,而是受信启动链的一部分,用于恢复系统或重新安装固件

如果理解 Apple 的安全模型,DFU 其实非常有代表性,因为它涉及:Boot ROM,Secure Boot chain签名验证恢复模式USB 设备协议

DFU 在 Apple 启动体系中的位置

Apple 设备启动大致分为几个阶段:

代码语言:javascript
复制
硬件上电
   │
   ▼
Boot ROM(不可修改)
   │
   ▼
LLB / iBoot
   │
   ▼
Kernel
   │
   ▼
iOS / iPadOS / macOS

DFU 模式存在于 Boot ROM 阶段,换句话说:

DFU 是 Boot ROM 内置的 USB 固件更新协议。

因为 Boot ROM 在芯片生产时就写死在硅片里,所以:无法被软件更新,无法被系统篡改,永远存在;这就是 DFU 的安全基础。

Boot ROM 为什么要内置 DFU

如果设备启动失败,例如:系统损坏,iBoot 损坏,更新中断,NAND 损坏,用户强制恢复设备必须有一种最低级别恢复机制,否则设备就会变成砖。

所以 Apple 设计:

代码语言:javascript
复制
Boot ROM
  ├── 正常启动路径
  └── DFU 恢复路径

如果正常启动失败,Boot ROM 可以:直接进入 DFU 模式,通过 USB 接收新的固件镜像。

DFU 模式的技术原理

DFU 模式本质是一个 USB DFU 协议设备,当 iPhone/iPad 进入 DFU 时;电脑看到的设备不是 iPhone,而是:

代码语言:javascript
复制
Apple Mobile Device (DFU Mode)

USB Vendor ID:

代码语言:javascript
复制
0x05AC

Product ID(不同设备不同)。

DFU 模式时设备运行的软件

此时设备只运行Boot ROM;没有:iBoot,kernel,iOS,drivers,文件系统,这个设备几乎是“裸芯片”。

DFU 传输流程

电脑端(Finder / iTunes / idevicerestore):

代码语言:javascript
复制
发送固件
      │
      ▼
Boot ROM 接收
      │
      ▼
验证签名
      │
      ▼
写入 NAND
      │
      ▼
重启

关键步骤是:签名验证,否则 DFU 就会成为 jailbreak 永久后门(开心死啦)。

Apple Secure Boot 与 DFU

Apple 的 secure boot 是:

代码语言:javascript
复制
Boot ROM
  ↓ verify
LLB
  ↓ verify
iBoot
  ↓ verify
Kernel

每一步都会验证签名。

DFU 也是同样,DFU 接收固件后:

代码语言:javascript
复制
Boot ROM
   ↓
验证 Apple 签名
   ↓
允许执行

如果固件没有 Apple 签名:Boot ROM → 拒绝;这就是为什么:不能随便刷自定义系统(因为软件签名不对,底层硬件是拒绝的)

SHSH 与 DFU

很多人听过SHSH blobs,这其实也和 DFU 密切相关;因为Apple 不仅要求:固件必须 Apple 签名;还要求:固件必须针对这台设备签名。

服务器流程:

代码语言:javascript
复制
电脑
  │
  ▼
Apple TSS server
  │
  ▼
生成 SHSH
  │
  ▼
设备验证

这就是为什么:旧版本 iOS 很难刷回去,因为 Apple 停止签名。(这个 jb 封闭啊)

DFU vs Recovery Mode

很多人混淆这两个,但是区别非常重要。

模式

运行代码

USB 显示

能力

Recovery

iBoot

iTunes + cable

普通恢复

DFU

Boot ROM

黑屏

最底层恢复

Boot ROM 代码无法更新,所以如果 Boot ROM 有漏洞:那漏洞 = 永久漏洞(我在说正确的废话)

这就是著名的:checkm8(Boot ROM exploit。)

影响:A5 → A11;攻击流程:USB → DFU → Boot ROM exploit,利用 DFU USB stack 的漏洞,然后可以控制 Boot ROM

checkm8 漏洞利用流程首先需要将设备强制进入 DFU 模式,在 BootROM 处于等待 USB 接收固件的阶段,利用其 USB 控制传输回调函数中的堆溢出或释放后使用(UaF)漏洞实施劫持;随后通过注入 Shellcode 直接在内存中绕过官方签名验证,从而获取 Root 最高权限并实现任意镜像的加载与越狱。

那为什么 Apple 仍然允许 DFU?

因为 DFU 解决一个关键问题:设备可恢复性;如果没有 DFU:设备更新失败就彻底砖;Apple 的设计原则是:DFU 必须存在,但 DFU 不允许绕过签名。

所以:Boot ROM 固定,必须验证签名,USB 接口最小化

如果把 Apple 安全体系画成结构:

代码语言:javascript
复制
┌────────────────────┐
│ iOS / Apps         │
├────────────────────┤
│ Kernel             │
├────────────────────┤
│ iBoot              │
├────────────────────┤
│ LLB                │
├────────────────────┤
│ Boot ROM           │
├────────────────────┤
│ DFU mode           │
└────────────────────┘

DFU 的作用是当上面全部损坏时仍然可以恢复系统。

(我本来还有一段猜测 Apple 如何设计 DFU 的,但是觉得无关紧要了)

后记

最近几年固件安全好少,大佬们不知道哪里去了;另外研究这些也不是全无意义,当你在设计产品时不可避免的要和启动这个“不起眼的”事情打交道,深入理解过程才能写出好代码。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 看看 DFU
  • 先看看普通嵌入式的启动过程
  • 先看看最简单的启动系统(MCU)
    • 小结一下
  • SoC 启动流程
  • 为什么 Bootloader 要多级
  • Bootloader 的分层
  • Stage0 Boot ROM
  • Stage1 Bootloader(SPL)
  • Stage2 Bootloader(U-Boot)
    • 碎碎念
  • 启动过程中最重要的三件事
    • 嵌入式启动的完整结构
  • 步入正题
  • DFU 在 Apple 启动体系中的位置
  • Boot ROM 为什么要内置 DFU
  • DFU 模式的技术原理
  • DFU 模式时设备运行的软件
  • DFU 传输流程
  • Apple Secure Boot 与 DFU
  • SHSH 与 DFU
  • DFU vs Recovery Mode
  • 那为什么 Apple 仍然允许 DFU?
  • 后记
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档