固件补丁管线

fw prepare 到 fw patch 的完整固件加工流程、patcher 构建与固件配对表

固件补丁管线

vphone-cli 的固件补丁管线(FirmwarePatcher)负责把原版 iPhone + cloudOS(PCC)两份 IPSW 加工成能在 Virtualization.framework 研究 VM 上启动的混合固件。整条管线分两大步:fw prepare(备料)与 fw patch_<variant>(打补丁)。

第一步:fw prepare

make fw_prepare

fw prepare 完成固件的下载、解包与合并:

  1. 下载 IPSW:分别获取 iPhone 与 cloudOS 两份 IPSW,支持断点续传与本地缓存(缓存命中可离线重跑)。
  2. 解包unzip 解进缓存目录后克隆到工作目录,并清理陈旧的 *Restore* 目录。
  3. cloudOS 合并进 iPhone 树:cloudOS 的 kernelcache、Firmware/ 子目录(agx/all_flash/ane/dfu/pmp)与散置 im4p 覆盖进 iPhone 树;*.dmg 与 trustcache 保留 iPhone 版。
  4. 生成 hybrid BuildManifest:合并两份固件的身份信息,产出混合 BuildManifest.plistRestore.plist,供 DFU restore 使用——VM 在 DFU 下自认 cloudOS research 设备,而文件系统来自 iPhone 侧。

第二步:fw patch_<variant>

make fw_patch_dev    # 以 dev 变体为例;其余见「固件变体全解」

补丁阶段对 VM 目录下最新的 *Restore*/ 目录原地修改启动链组件:

组件类别 路径位置 被打补丁的文件
dfu *Restore*/Firmware/dfu/ iBSS、iBEC
all_flash *Restore*/Firmware/all_flash/ LLB、DeviceTree
txm *Restore*/Firmware/ TXM
kernelcache *Restore*/ 内核缓存

每个组件会被透明地解包(IM4P)→ 按变体串联补丁器 → 按原容器结构重打包写回。补丁点全部经 Capstone 反汇编动态定位,不硬编码偏移;每个补丁都会记录进 VM bundle 内的 patch_report.json,可用于审计与回归比对。

patcher 构建:make patcher_build

fw_patch* 系列 target 实际调用的是一个 debug、未签名的 patcher 二进制

make patcher_build    # 产出 .build/debug/vphone-cli

为什么单独存在:固件补丁是纯用户态文件操作,不需要虚拟化相关的私有 entitlements,因此不需要签名(也就不触发 amfi 检查);debug 构建比 release 快得多,改补丁代码时迭代成本低。相对的,make build 产出的 release 签名二进制是留给真正跑虚拟化的路径(make boot 等)的——不要拿 swift build 裸产物去启动 VM。

固件配对表:单一数据源

iPhone IPSW 与 cloudOS IPSW 的配对关系集中维护在仓库的:

config/firmware_catalog.json
  • 新增或更新配对只改这个 JSON,不改任何代码fw prepare 默认取其中的 defaultPairing 作为固件源。
  • 该文件会随发布 App 一起打包(Contents/Resources/config/),GUI 与 CLI 读到的是同一份。

Manager 的 Firmware 面板

如果你使用 vphone-manager GUI,侧栏的 Firmware 面板提供了图形化的镜像管理:

  • 浏览配对表中的固件条目
  • 直接下载对应 IPSW 镜像(走与 fw prepare 相同的缓存)
  • 查看本地已缓存 / 已解包的固件状态

面板下载的镜像与命令行管线完全互通,可以混用。

典型工作流

make patcher_build     # 1. 构建未签名 patcher(补丁代码改动后重跑)
make fw_prepare        # 2. 下载 + 合并固件(有缓存则秒过)
make fw_patch_dev      # 3. 按 dev 变体打补丁

注意事项:

  • fw patch原地修改,重复跑同一变体是安全的(有干净备份与幂等设计),但跨变体重打前建议确认 *Restore* 目录状态。
  • kernelcache 在首次打补丁前会保存一次性 .orig 备份,供后续 cfw kernel-patch 从干净源开始,避免二次补丁污染。
  • 想单独重打某个组件,可用 standalone patch target:make dt_patch / gpu_patch / sensor_patch / sim_patch

深入阅读

  • 各启动链补丁器的实现细节:仓库 docs/bootchain-patchers.md
  • CFW 安装阶段(补丁之后、首启之前):仓库 docs/cfw-installers.md