系统总体架构
系统总体架构
vphone-cli 是基于 Apple Virtualization.framework(PV=3 私有 entitlement)的虚拟 iPhone 研究工具:在 macOS 宿主机上完成固件准备 → 启动链补丁 → DFU restore → CFW 安装 → 启动运行 → 运行时控制的完整闭环。本文是理解全局的地图——先看四个进程域如何拼成系统,再分清「构建期」与「运行期」两条主线,最后拆解三个让这套系统得以产品化的工程决策。
全景架构:四个进程域
系统由四个进程域组成:宿主机上的三个前端、宿主机上的特权与辅助进程、Guest 域内的虚拟 iPhone,以及驱动自动化的外部控制客户端。宿主与 guest 之间只经 vsock 通信(1337 控制通道 + 2222/1338/1339 三条数据通道),外部世界与宿主之间只有 vphone.sock 一个入口——极简的边界是后文所有设计决策的起点。
图上三条最重要的连线:manager/agent → 无头 CLI 子进程(VM 永远跑在独立进程里)、CLI ⇄ vphoned 的 vsock:1337(宿主对 guest 的全部运行时控制)、客户端 → vphone.sock(外部世界的唯一入口)。
域一:宿主前端——三个入口,一组库
| 前端 | 形态 | 定位 |
|---|---|---|
| vphone-cli | 宿主应用(签名 + 私有 entitlements) | CLI + 菜单栏 UI;boot 后直接持有 VZVirtualMachine,提供窗口、输入、录屏与 HostControl 服务 |
| vphone-manager | SwiftUI 桌面 GUI(无私有 entitlements) | 多 VM 集中管理;VM 运行交给 spawn 的无头 CLI 子进程,创建管线在进程内驱动 |
| vphone-agent | 无头用户级 daemon | 集群节点侧:以 Bearer token 认证的 HTTP API 暴露本机 VM 库与生命周期操作 |
三个前端不是三套实现,而是同一组 SwiftPM 库的三个入口:
| 共享库 | 职责 |
|---|---|
| VPhoneCore | VM bundle / manifest / ~/.vphone 库、restore 与 host-mount 原语、子进程工具 |
| VPhoneCreate | vm create 端到端编排(VPhoneCreateOrchestrator,结构化事件与协作式取消) |
| FirmwarePatcher | 全部固件补丁与 CFW 安装器(fw prepare / fw patch / cfw install 的引擎) |
| VPhoneManagerCore | Manager 与 agent 共享的纯逻辑层(不依赖 SwiftUI):VM 生命周期、库发现、远程节点客户端 |
| VPhoneNetworking | 网络配置与流量遥测客户端 |
| VPhoneLogging | 统一日志库 |
| VPhoneHostControlTransport | HostControl 客户端传输抽象——本地 unix socket 与远程 agent HTTP 代理同一套接口 |
收益直白:CLI 上验证过的建机与控制语义,GUI 与集群直接继承,行为不会分叉;逻辑沉在库层,单测与回归天然覆盖三个前端。
域二:特权与辅助进程
com.vphone.helper(root LaunchDaemon) —— cfw install 与 vm create 需要在 VM 关机状态下把 Disk.img 挂到宿主机写文件、并翻转 APFS boot snapshot,这些是 root 操作。helper 经一次性的 make helper_install 安装,之后全程免密:
- XPC 只接受签名 identifier 为
com.vphone.cli/com.vphone.manager的连接; - 动词面严格受限(挂载 / 卸载 / 属主收尾 / 重跑 cfw install 共五个动词),没有任意命令执行;
- 设备必须匹配
/dev/diskNsM且不属于启动盘,挂载点必须落在白名单根内; - 没装 helper 时可
sudo直跑等价的 root 路径(研究机兜底)。
pymobiledevice3_bridge.py(DFU restore 桥) —— 全管线唯一保留的 Python 子进程,只做一件事:封装 pymobiledevice3 完成 DFU 下的 SHSH 抓取与固件刷入。其余阶段全部是 Swift in-process。
network-proxy(Go sidecar) —— VM 的网络出口:guest 的 NAT 流量经它透明代理到上游(SOCKS5 / HTTP),同时产出流量遥测,供宿主观测 guest 的网络行为。
域三:Guest 域——虚拟 iPhone 与 vphoned
VM 本体是 Virtualization.framework 以 PV=3 私有硬件模型启动的虚拟 iPhone——这也解释了宿主为何必须放宽 SIP/AMFI:只有带私有 entitlement 的签名二进制才被允许这样使用 Hypervisor。guest 内的常驻执行端是 vphoned:
- ObjC LaunchDaemon,伪装成 Apple 系统 daemon 常驻(launchd
KeepAlive保活); - 监听 vsock:1337,按 14 个命令族处理宿主请求:输入注入(HID / 触摸)、文件传输、应用与 IPA 安装、账户 profile、keychain、剪贴板、系统设置、位置模拟、自更新等;
- 另持三条独立数据通道:2222 SSH 桥(inetd 模式拉起 dropbear,guest 内零 TCP sshd 暴露)、1338 虚拟相机帧中转、1339 端口转发 relay;
- 支持免重启热更新:握手比对二进制 SHA-256 → 宿主推送新版 → launchd 重启生效,是固件级改动之外的主要迭代通道。
域四:外部控制客户端
外部世界对 VM 的一切操作收敛到一个入口:<bundle>/vphone.sock(AF_UNIX、0600、校验对端 UID)。无论你是 automation/ 的 AI E2E 框架、MCP 工具链,还是一行 nc -U 脚本,看到的都是同一个「一行 JSON 进 / 一行 JSON + 内联截图出」协议——与菜单栏 UI 的人工操作共用完全相同的 VPhoneGuestControl 通道。
主线一:构建期——把一台 VM 做出来
理解本仓库最高效的方式,是区分构建期(把一台 VM 做出来)与运行期(把 VM 用起来)。构建期由 vphone-cli vm create 驱动(make rebuild_dev 与 Manager 创建向导都是同一引擎的入口),按固定顺序走完六个阶段:
| 阶段 | 做什么 | 关键承担者 |
|---|---|---|
| 1. fw prepare | 下载并解包 iPhone 与 cloudOS 两份 IPSW,cloudOS 启动链合并进 iPhone 固件树,生成 hybrid BuildManifest | FirmwarePatcher · Prepare |
| 2. fw patch | 按变体对 dfu(iBSS/iBEC)、all_flash(LLB/DeviceTree)、txm、kernelcache 原地打补丁 | FirmwarePipeline + 各组件 patcher |
| 3. DFU restore | VM 以 DFU 模式启动,抓取 SHSH,把混合固件刷入后关机;系统落在 Disk.img 与 SEPStorage |
pymobiledevice3_bridge.py 子进程 |
| 4. cfw install | 关机状态下经 helper 把 Disk.img 挂到宿主,变体安装器写入 CFW 文件(vphoned、dylib、配置等) |
CFWHostMounter + com.vphone.helper |
| 5. snapshot 翻转 | 改名具名 root snapshot,让下次引导挂载被修改过的 live 卷(与阶段 4 同属一道工序) | ApfsSnapRename(root 上下文) |
| 6. first boot | 首启注入初始化命令后关机;再次启动并分析启动结果,判定成败、落盘固件信息 | boot analysis |
要点:
- 编排器是库不是脚本:
VPhoneCreateOrchestrator是独立的VPhoneCreatelibrary target,CLI 直接驱动,vphone-manager 在进程内驱动同一引擎(消费结构化事件、支持取消);需要 VM 实例与 root 权限的阶段仍由签名的 vphone-cli 二进制承担,六个阶段中只有 DFU restore 依赖 Python 子进程。 - 变体决定补丁强度:
less/regular/dev/jb/exp五档安全绕过逐级递增(less最大程度保留 iOS 缓解措施,exp是jb超集并含反 VM 检测研究补丁),详见「固件变体全解」。 - 每个补丁都有账可查:写回时生成
PatchRecord(offset、前后字节、前后反汇编),汇总进 VM bundle 的patch_report.json,可审计、可回归比对。
实操向导见「创建你的第一台虚拟机」;补丁细节见「固件补丁管线」。
主线二:运行期——把 VM 用起来
vm launch 之后,人工点击与 AI 自动化走完全相同的控制链:
三个值得注意的设计:
- 每步操作回传内联截图。默认每条命令执行后附带一张压缩截图(
"screen":false可关,"delay"控制截图前等待的毫秒数)。对自动化这等于「操作即可见」——点完立刻拿到视觉反馈,不需要额外的截图轮询。 - 人工与自动化同一条通道。菜单栏按钮与
nc -U发出的 JSON 走同一个VPhoneGuestControl;GUI 能做的自动化都能做,行为不会分叉。 - 能力协商与热更新。握手时 vphoned 上报能力列表(caps),宿主按能力决定输入路径与菜单可用性;
make vphoned构建后经vphoned_update推送,guest 侧改动免重启生效。
安全边界同样收敛:socket 0600 且校验对端 UID,命令走显式 allowlist,guest 内零 TCP 监听(SSH 与端口转发全走 vsock,guest 内 App 扫端口不可见)。
产品化与工程化:三个「为什么」
架构图上「为什么这么连」比「连了什么」更值得读。以下三个决策分别回答了「怎么把研究工具做成产品」「怎么让补丁工程可靠」「怎么让固件数据可持续维护」。
为什么 Manager 和 Agent 都不直接持有 VZVirtualMachine?
两者共用同一个模型:spawn 签名的 vphone-cli boot --no-graphics 无头子进程跑 VM,自己只经 HostControl socket 控制。
- 特权面收敛:PV=3 私有 entitlement 只存在于
vphone-cli一个签名二进制里;Manager 与 agent 不碰 Virtualization.framework、不带私有 entitlements,因此能以常规签名分发安装(agent 甚至可以 Developer ID 分发),不必为整个 GUI 打开特权后门。 - 崩溃隔离:VM 跑在独立子进程里,GUI 崩溃、退出、升级都不波及运行中的 VM——Manager 退出可选「Keep Them Running」让 VM 存活;agent 重启后经 lsof 重新发现托管 VM,子进程无感存活。
- 生命周期同源:Manager 与 agent 共同链接
VPhoneManagerCore的VMSupervisor(preflight 预检、SIGINT→grace→SIGKILL 停机信号升级、lsof 运行态发现),一套语义两端复用,不会漂移出两套行为。 - 能力不打折:无头 boot 只裁掉窗口,HostControl 照常监听——截图、触摸注入、录屏、挂起恢复全部可用。
- 本地 / 远程同构:控制面统一是 HostControl,本地走 unix socket、远程走 agent 的 HTTP 代理,Manager 用同一套视图与命令封装无缝切换。
为什么 patcher 是 Swift 库而不是 Python 脚本?
固件补丁早期多由 Python 脚本承担;如今 FirmwarePatcher 是 SwiftPM library target,管线主体全程 in-process。
- 类型安全:Swift 6 strict concurrency 下,
PatchRecord/PatchResult/PatchReport把「每个补丁必须记录 offset 与前后状态」固化成类型,而不是散落在脚本的 print 里。 - 二进制基础设施可复用:Capstone 反汇编负责补丁点定位(按 mnemonic / 操作数 / 控制流的语义匹配,禁止硬编码偏移与预汇编字节),Keystone 负责替换指令现编(
asm(...)/NOP/MOV_W0_0),全部补丁器共享同一套地基。 - 统一错误处理:
PatcherError(patchSiteNotFound/multipleMatchesFound/patchVerificationFailed等)把「锚点要么唯一命中、要么响亮失败」变成硬约束——绝不静默跳过或打错位置继续跑。 - 无跨语言边界:CLI 与 Manager 直接调用同一引擎(
vm create的结构化进度事件即由库层回调产出);全管线 Python 只剩 restore 桥这一个纯第三方库封装。
为什么固件配对由单一 JSON 驱动?
iPhone IPSW 与 cloudOS IPSW 的配对关系全部收敛在 config/firmware_catalog.json:
- 配对是数据不是逻辑:新增或更新固件配对只改这个 JSON,零代码改动、零重新构建;
fw prepare默认取其中defaultPairing作为固件源。 - 单一数据源,三端一致:该文件随发布 App 打包进
Contents/Resources/config/,CLI、Manager 的 Firmware 面板、agent 读到的是同一份——不存在「GUI 能下载的镜像 CLI 找不到」这类漂移。 - 容错回退:catalog 缺失时回退内置字面量,旧 bundle 不会因此直接坏掉。
深入阅读
| 想深入 | 阅读 |
|---|---|
| 建机全流程实操 | 「创建你的第一台虚拟机」 |
| 补丁管线与变体 | 「固件补丁管线」「固件变体全解」 |
| 运行时控制与命令族速查 | 「VM 运行时:窗口、输入与控制面」 |
| guest 守护进程 | 「guest 守护进程 vphoned」 |
| GUI 与集群 | 「vphone-manager 多 VM 管理 GUI」「集群管理与 vphone-agent」 |
| 网络代理与遥测 | 「网络与代理」 |
| 自动化与 E2E | 「自动化」 |
| 逐模块开发文档 | 仓库 docs/ 目录(总入口 docs/architecture.md) |