最近推上iOS虚拟手机话题很火,很从我晒了自己动手修改实现的可运行的iOS虚拟手机。
基于tart的super-tart-vphone项目用起来要20G的空间,这着实有些难受。本文主要从iOS系统框架介绍说起,讲解vphone-cli工具一步步实现iOS虚拟手机制作的全过程。
目前vphone-cli工具还没有将文件补丁与VM的制作实现全自动化,旦笔者相信,在强大的社区力量的贡献下,要不了多久,iOS虚拟手机/iOS云手机这类自动化的工具会快速的完善起来。届时,想要玩macOS/iOS平台的逆向工程,只需要一台2999元的Mac Mini M4基础款就可以啦!
2024年底,Apple正式推出Private Cloud Compute(以下简称PCC),声称为云端AI隐私开辟新的方向。PCC的核心是一套运行在Apple Silicon服务器上的虚拟化系统,对外提供安全研究用的虚拟机实例。到2025年底,安全研究者在PCC固件的cloudOS 26版本中发现了一个令人震惊的组件: vphone600ap,即"iPhone Research Environment Virtual Machine"。

这意味着Apple在PCC固件内嵌入了完整的虚拟iPhone运行环境。无论这是Apple有意为安全研究者准备的工具,还是一次意外泄露(类似2021年iOS 15 beta中DEVELOPMENT/KASAN内核被包含长达4个月的事件),社区已经迅速行动,将这一发现转化为可实际运行的虚拟iPhone方案。
经过wh1te4ever、Lakr233等研究者的持续工作,目前已实现在macOS上完整启动iOS 26虚拟机,支持SSH远程访问、VNC图形界面,可以运行SpringBoard和系统应用。对于iOS逆向工程和安全研究来说,这是一个真正可以投入生产环境使用的虚拟化分析平台。


上图展示了虚拟iPhone的实际运行效果。通过VNC客户端连接后,可以看到完整的iOS 26用户界面,包括SpringBoard主屏幕、系统设置等原生应用。虚拟机内核版本为Darwin 25.1.0(xnu-12377.42.6),设备标识为iPhone99,11,硬件型号vresearch101ap。
本文将从Apple提供的Virtualization.framework出发,逐步拆解虚拟iPhone从创建到运行的完整技术实现。涉及的核心仓库包括:
Apple从macOS 11开始提供Virtualization.framework,用于在Apple Silicon上创建和管理轻量级虚拟机。公开API支持创建macOS和Linux虚拟机,提供CPU、内存、磁盘、网络、图形等外设的配置能力。框架内部使用Hypervisor.framework提供的硬件虚拟化支持,直接利用ARM架构的EL2特权级。
但公开API有一个明确的限制: 只支持macOS和Linux客户机操作系统。iOS从未出现在官方文档的支持列表中。
突破口在于Virtualization.framework内部的私有API。通过逆向分析框架二进制,研究者发现了_VZMacHardwareModelDescriptor这个未公开的类。该类的setPlatformVersion:方法接受一个无符号整数参数,不同的值对应不同的硬件平台:
创建PV=3硬件模型的核心代码如下:
VZMacHardwareModel *VPhoneCreateHardwareModel(void) {
_VZMacHardwareModelDescriptor *desc = [[_VZMacHardwareModelDescriptor alloc] init];
[desc setPlatformVersion:3];
[desc setBoardID:0x90];
[desc setISA:2];
VZMacHardwareModel *model = [VZMacHardwareModel _hardwareModelWithDescriptor:desc];
return model;
}
其中boardID:0x90对应vresearch101板卡标识,ISA:2指定ARM64指令集架构。这些参数与PCC固件中的vphone600ap配置完全匹配。
整个虚拟iPhone的创建过程依赖11个私有API,通过ObjC桥接层调用,汇总如下:
_VZMacHardwareModelDescriptor | VPhoneCreateHardwareModel() | |
-_setROMURL: | VPhoneSetBootLoaderROMURL() | |
-_setForceDFU: | VPhoneConfigureStartOptions() | |
_VZGDBDebugStubConfiguration | VPhoneSetGDBDebugStubDefault() | |
_VZPvPanicDeviceConfiguration | VPhoneSetPanicDevice() | |
-_setCoprocessors: | VPhoneSetCoprocessors() | |
-_setProductionModeEnabled: | VPhoneDisableProductionMode() | |
-_setDataValue:forNVRAMVariableNamed: | VPhoneSetNVRAMVariable() | |
_VZPL011SerialPortConfiguration | VPhoneCreatePL011SerialPort() | |
_VZUSBTouchScreenConfiguration | VPhoneConfigureMultiTouch() | |
_VZSEPCoprocessorConfiguration | VPhoneConfigureSEP() |
表2-1 虚拟iPhone私有API清单
这些API都位于Virtualization.framework内部,以下划线开头,不在公开头文件中暴露。由于ObjC的动态特性,可以通过NSClassFromString和performSelector在运行时访问。
使用私有API还不够,macOS在执行虚拟化操作前会检查进程的代码签名权限(Entitlements)。虚拟iPhone要求以下5项权限:
<dict>
<key>com.apple.security.virtualization</key>
<true/>
<key>com.apple.private.virtualization</key>
<true/>
<key>com.apple.private.virtualization.security-research</key>
<true/>
<key>com.apple.vm.networking</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
其中com.apple.private.virtualization授权访问私有虚拟化API,com.apple.private.virtualization.security-research是PV=3专属权限,缺少任何一项都会导致VM创建失败。
在正常情况下,私有Entitlements只有Apple签名的系统二进制才能使用。要让自编译的vphone-cli获得这些权限,必须禁用系统完整性保护(SIP)和Apple Mobile File Integrity(AMFI):
# 恢复模式下执行
csrutil disable
csrutil allow-research-guests enable
# 重启后在macOS中执行
sudo nvram boot-args="amfi_get_out_of_my_way=1 -v"
然后使用Ad-hoc签名将Entitlements附加到二进制:
codesign --force --sign - --entitlements vphone.entitlements .build/release/vphone-cli
虚拟iPhone要求macOS 15.0(Sequoia)或更新版本,运行在Apple Silicon设备上。系统配置分三步:
第一步,进入恢复模式。长按电源键直到屏幕显示"Loading boot options",在恢复模式的Terminal中执行:
csrutil disable
csrutil allow-research-guests enable
第二步,重启进入macOS后设置启动参数:
sudo nvram boot-args="amfi_get_out_of_my_way=1 -v"
第三步,再次重启使参数生效。
整个固件操作流程依赖libimobiledevice生态系统,需要从源码编译以下组件:
libplist -> plist解析
libimobiledevice -> iOS设备通信协议
libusbmuxd -> USB复用守护进程
libirecovery -> 恢复模式通信(需添加vresearch101设备定义)
idevicerestore -> 固件恢复工具
其中libirecovery需要添加虚拟设备的硬件标识才能正确识别vphone:
{ "iPhone99,11", "vresearch101ap", 0x90, 0xFE01, "iPhone 99,11" },
vphone-cli项目提供了一键编译脚本:
zsh Scripts/compile_all_libimobiledevice_deps.sh
固件补丁脚本使用Python3编写,依赖三个关键库:
pip3 install capstone keystone-engine pyimg4
vphone-cli是一个Swift Package Manager项目,使用ObjC桥接层调用私有API。编译和签名一步完成:
./build_and_sign.sh
该脚本执行三个操作:
# 1. Release模式编译
swift build -c release
# 2. 使用Entitlements签名
codesign --force --sign - --entitlements vphone.entitlements .build/release/vphone-cli
# 3. 验证签名
codesign -d --entitlements - .build/release/vphone-cli
验证输出应包含全部5项权限:
[Dict]
[Key] com.apple.private.virtualization
[Value]
[Bool] true
[Key] com.apple.private.virtualization.security-research
[Value]
[Bool] true
...
虚拟iPhone的固件并非来自单一来源,而是将iPhone OS和cloudOS PCC两份固件进行"杂交"。这是因为PCC固件包含vresearch101平台的引导链(iBSS/iBEC/LLB/内核等),而iPhone IPSW包含完整的iOS用户空间(Cryptex/SystemOS/AppOS)。
需要下载的固件:
iPhone OS: iPhone17,3_26.1_23B85_Restore.ipsw
cloudOS: PCC-CloudOS-26.1-23B85固件
iPhone固件可通过Apple CDN直接获取,cloudOS固件通过PCC安全研究工具下载。
在合并固件之前,需要先通过Apple提供的pccvre工具创建一个PCC研究虚拟机作为模板:
sudo /System/Library/SecurityResearch/usr/bin/pccvre
cd /System/Library/SecurityResearch/usr/bin/
./pccvre release list
./pccvre release download --release 35622
./pccvre instance create -N pcc-research -R 35622 --variant research
创建完成后,模板虚拟机位于:
~/Library/Application Support/com.apple.security-research.vrevm/VM-Library/pcc-research.vm
从中需要提取以下文件:
AuxiliaryStorage -> NVRAM辅助存储
Disk.img -> 磁盘镜像
SEPStorage -> Secure Enclave存储
config.plist -> 虚拟机配置
另外还需要从系统Virtualization.framework中复制ROM文件:
/System/Library/Frameworks/Virtualization.framework/Versions/A/Resources/AVPBooter.vresearch1.bin
/System/Library/Frameworks/Virtualization.framework/Versions/A/Resources/AVPSEPBooter.vresearch1.bin
prepare_firmware.sh脚本负责将两份固件合并为虚拟iPhone可用的混合固件。核心操作是将cloudOS的引导链组件覆盖到iPhone IPSW目录:
# 内核缓存(来自cloudOS)
cp${CLOUDOS_DIR}/kernelcache.* "$IPHONE_DIR"/
# 引导链、设备树等固件组件(来自cloudOS)
for sub in agx all_flash ane dfu pmp; do
cp${CLOUDOS_DIR}/Firmware/${sub}/* "$IPHONE_DIR/Firmware/${sub}"/
done
cp${CLOUDOS_DIR}/Firmware/*.im4p "$IPHONE_DIR/Firmware"/
固件合并后,脚本还会生成一个包含5种Build Identity的BuildManifest.plist。不同Identity使用不同的引导链和ramdisk组合:
表4-1 BuildManifest的5种Build Identity配置
这5种配置覆盖了固件恢复过程中所有可能的场景。idevicerestore会根据设备状态自动选择合适的Identity。
准备完成后,VM工作目录结构如下:
VM/
AVPBooter.vresearch1.bin -> ROM引导加载器
AVPSEPBooter.vresearch1.bin -> SEP引导加载器
AuxiliaryStorage/ -> NVRAM辅助存储
Disk.img -> 磁盘镜像
SEPStorage -> SEP非易失存储
config.plist -> VM配置
nvram.bin -> NVRAM存储
iPhone17,3_26.1_23B85_Restore/ -> 混合固件目录
固件合并只是第一步。由于vresearch1的ROM和引导链仍然执行签名验证,直接启动会因为签名不匹配而失败。patch_firmware.py脚本对6个启动组件进行共计41+处二进制修改,覆盖签名验证、Image4校验、trustcache检查等多个安全机制。
AVPBooter是最先执行的ROM代码,负责验证后续加载的所有固件组件的数字签名。其核心验证逻辑围绕DGST(DiGeST)标签展开。
补丁脚本采用动态分析策略定位验证函数,而非依赖固定偏移:
在IDA中可以清晰看到DGST验证的分支逻辑:
__int64 __fastcall sub_102400(__int64 a1, __int64 a2, int a3, __int64 a4)
// ...
if( (_DWORD)v8 != 'DGST' )
// ...
v20 = sub_1021EC(0, 'DGST', v82);
补丁将返回值从mov x0, x20(传递验证结果)替换为mov x0, #0(强制返回0,即验证通过):
补丁前: 0x102C20: mov x0, x20 (e00314aa)
补丁后: 0x102C20: mov x0, #0 (000080d2)
这个单字节级别的修改让AVPBooter接受任何后续固件,无论其签名是否有效。
iBSS(iBoot Single Stage)和iBEC(iBoot Epoch Change)是iOS引导链的第二和第三阶段。它们使用Image4格式的validate_property_callback函数验证固件组件的签名属性。
补丁脚本搜索以下指令模式来定位验证回调:
b.ne X ; 验证失败时跳转
mov x0, x22 ; 返回值赋值
... ; 8条指令内有cmp比较
movn w22, ... ; 加载-1到w22(表示失败)
补丁方式:
b.ne -> nop ; 消除验证失败跳转
mov x0, x22 -> mov x0, #0 ; 强制返回成功
以iBSS为例,补丁位于偏移0x1F7BE0:
0x1F7BE0: b.ne -> nop, mov x0,x22 -> mov x0,#0
同时,两个组件都注入了串口标签(如"Loaded iBSS"、"Loaded iBEC"),方便在启动过程中通过串口输出追踪执行进度。
iBEC还需要额外的boot参数补丁,将默认启动参数替换为包含调试标志的版本:
原始参数: (默认)
新参数: serial=3 -v debug=0x2014e %s
这个补丁涉及ARM64指令级别的地址重编码。由于新字符串可能比原字符串长,需要在二进制中找到空闲空间存放新字符串,然后修改ADRP+ADD指令对使其指向新地址。
ADRP+ADD是ARM64中访问PC相对地址的标准方式:
adrp x2, #page ; 加载目标页地址(4KB对齐)
add x2, x2, #pageoff ; 加上页内偏移
补丁脚本重新编码这两条指令:
defencode_adrp(rd, pc, target):
imm = ((target & ~0xFFF) - (pc & ~0xFFF)) >> 12
imm &= (1 << 21) - 1
return0x90000000 | ((imm & 3) << 29) | ((imm >> 2) << 5) | (rd & 0x1F)
defencode_add(rd, rn, imm12):
return0x91000000 | ((imm12 & 0xFFF) << 10) | ((rn & 0x1F) << 5) | (rd & 0x1F)
新字符串存放在0x1B2970偏移处,ADRP+ADD被重编码为指向该地址。
LLB(Low Level Bootloader)是引导链中安全检查最密集的组件。除了Image4回调绕过和boot参数补丁外,还需要6处固定偏移的补丁:
0x0002AFE8: b +0x2c ; 跳过签名检查分支
0x0002ACA0: nop ; 空操作替换签名验证调用
0x0002B03C: b -0x258 ; 重定向到签名检查成功路径
0x0002ECEC: nop ; 空操作替换验证函数
0x0002EEE8: b +0x24 ; 跳过验证失败处理
0x0001A64C: nop ; 绕过panic触发
这6处补丁分布在LLB的多个签名验证路径上,确保无论走到哪个分支都不会因签名问题中断启动。最后一处特别关键,它阻止了签名验证失败时触发的kernel panic。
TXM(Trusted Execution Monitor)负责维护系统的信任缓存(trustcache)。trustcache是一个CDHash列表,只有列表中的二进制才被允许执行。
补丁位于偏移0x2C1F8,将trustcache验证的返回值强制为0:
0x0002C1F8: mov x0, #0 ; trustcache验证绕过
这使得任何二进制都能通过trustcache检查,为后续安装SSH、VNC等第三方工具铺平道路。
内核补丁是修改量最大的部分,覆盖5个子系统,共25处修改。
APFS文件系统补丁(6处):
0x02476964: _apfs_vfsop_mount ; 跳过root snapshot检查
0x023CFDE4: _authapfs_seal_is_broken ; 跳过sealed volume验证
0x0242011C: _apfs_graft ; 允许graft操作(mov w0,#0)
0x02475044: _apfs_vfsop_mount ; 修改比较逻辑(cmp x0,x0)
0x02476C00: _apfs_mount_upgrade_checks ; 跳过升级检查
0x0248C800: _handle_fsioc_graft ; 允许graft ioctl
APFS补丁的核心目标是让内核接受被修改过的文件系统。iOS使用Signed System Volume(SSV)保护系统分区的完整性,任何文件修改都会导致seal验证失败。上述补丁绕过了这一机制。
MAC策略框架补丁(5对,共10处):
_hook_file_check_mmap: mov x0,#0; ret
_hook_mount_check_mount: mov x0,#0; ret
_hook_mount_check_remount: mov x0,#0; ret
_hook_mount_check_umount: mov x0,#0; ret
_hook_vnode_check_rename: mov x0,#0; ret
MAC(Mandatory Access Control)是macOS/iOS内核的强制访问控制框架。这5个hook函数分别控制文件映射、挂载、重挂载、卸载和重命名操作的权限检查。将它们全部替换为mov x0, #0; ret(返回0表示允许)等同于禁用了整个MAC策略。
调试器与启动约束补丁(4处):
0x012C8138: _PE_i_can_has_debugger ; 返回1,启用调试器
0x012C813C: ret
0x0163863C: _proc_check_launch_constraints ; 返回0,跳过启动约束
0x01638640: ret
_PE_i_can_has_debugger是iOS/macOS内核中著名的调试器开关函数。在正式发布的内核中,该函数返回0,禁止附加调试器。补丁将其改为返回1,等同于开发版内核的行为。
_proc_check_launch_constraints控制进程的启动约束(Launch Constraints),这是iOS 17引入的安全机制。绕过它允许未经授权的进程启动。
其他补丁(5处):
0x00F6D960: _bsd_init ; 跳过rootvp认证
0x00FFAB98: post-validation ; nop
0x016405AC: postValidation ; cmp w0, w0(总是相等)
0x016410BC: _check_dyld_policy_internal ; 返回1
0x016410C8: _check_dyld_policy_internal ; 返回1
_check_dyld_policy_internal控制dyld(动态链接器)的加载策略。补丁允许加载未签名的动态库。
整个补丁体系按功能分类:
表5-1 引导链补丁分类统计
vphone-cli的VPhoneVM类封装了虚拟机的完整配置。初始化过程配置11个子系统:
init(options: Options) throws {
// 1. 硬件模型(PV=3)
let hwModel =tryVPhoneHardware.createModel()
// 2. 平台配置
let platform =VZMacPlatformConfiguration()
platform.machineIdentifier =VZMacMachineIdentifier()
platform.auxiliaryStorage = auxStorage
platform.hardwareModel = hwModel
// 3. 启动加载器
let bootloader =VZMacOSBootLoader()
VPhoneSetBootLoaderROMURL(bootloader, options.romURL)
// 4. CPU与内存
config.cpuCount =max(options.cpuCount, minimumAllowedCPUCount)
config.memorySize =max(options.memorySize, minimumAllowedMemorySize)
// 5. 显示(iPhone屏幕规格)
let gfx =VZMacGraphicsDeviceConfiguration()
gfx.displays = [
VZMacGraphicsDisplayConfiguration(
widthInPixels: 1290,
heightInPixels: 2796,
pixelsPerInch: 460
)
]
// 6. 存储
let attachment =tryVZDiskImageStorageDeviceAttachment(url: options.diskURL)
config.storageDevices = [VZVirtioBlockDeviceConfiguration(attachment: attachment)]
// 7. 网络(NAT)
let net =VZVirtioNetworkDeviceConfiguration()
net.attachment =VZNATNetworkDeviceAttachment()
// 8. 串口(PL011 UART)
let serialPort =VPhoneCreatePL011SerialPort()
serialPort.attachment =VZFileHandleSerialPortAttachment(...)
// 9. 多点触控
VPhoneConfigureMultiTouch(config)
// 10. GDB调试
VPhoneSetGDBDebugStubDefault(config)
// 11. SEP协处理器
VPhoneConfigureSEP(config, sepStorageURL, sepRomURL)
try config.validate()
}
显示配置值得关注: 1290x2796像素、460 PPI,这正是iPhone 16 Pro的屏幕参数。虚拟机模拟的是一台真实iPhone的硬件规格。
虚拟iPhone需要触控输入才能操作界面。vphone-cli通过_VZUSBTouchScreenConfiguration配置USB触摸屏设备,然后将鼠标事件转换为触摸事件。
创建触点对象时有一个技术细节值得注意。直接调用_VZTouch的初始化方法会导致SIGBUS崩溃,原因是ObjC运行时在Swift动态框架中执行objc_copyStruct时出错。解决方案是使用KVC(Key-Value Coding)逐个设置属性:
id VPhoneCreateTouch(NSInteger index, NSInteger phase,
CGPoint location, NSInteger swipeAim,
NSTimeInterval timestamp) {
Class touchClass = NSClassFromString(@"_VZTouch");
id touch = [[touchClass alloc] init];
[touch setValue:@((unsignedchar)index) forKey:@"_index"];
[touch setValue:@(phase) forKey:@"_phase"];
[touch setValue:@(swipeAim) forKey:@"_swipeAim"];
[touch setValue:@(timestamp) forKey:@"_timestamp"];
[touch setValue:[NSValue valueWithPoint:location] forKey:@"_location"];
return touch;
}
触摸阶段(phase)对应UITouch的标准定义: 0=began, 1=moved, 3=ended。通过VNC连接时,鼠标点击和拖拽都会被转换为对应的触摸事件。
首次配置虚拟机需要进入DFU(Device Firmware Update)模式,以便通过irecovery向设备发送自定义固件:
./boot_dfu.sh
启动后vphone-cli输出:
[vphone] PV=3 hardware model: isSupported = true
[vphone] PTY: /dev/ttys001
[vphone] SEP coprocessor configured
[vphone] Configuration validated
[vphone] Starting DFU...
[vphone] VM started in DFU mode -- connect with irecovery
此时在macOS的系统信息中可以看到一个DFU模式的Apple设备:
Apple Mobile Device (DFU Mode):
序列号: SDOM:01 CPID:FE01 CPRV:00 CPFM:00 SCEP:01 BDID:90
ECID:55E4D88BB1F30E6E IBFL:24 SRTG:[iBoot-13822.81.10]
USB供应商ID: 0x05ac
USB产品ID: 0x1227
CPID:FE01和BDID:90确认这是一个vresearch101平台设备。CPFM:00表示工程样品模式,拥有最高的系统修改权限。
使用编译好的irecovery(已添加vresearch101设备定义)查询虚拟设备:
irecovery -q
输出:
CPID: 0xfe01
CPRV: 0x00
BDID: 0x90
ECID: 0x02dea93bbf44524c
CPFM: 0x00
SCEP: 0x01
IBFL: 0x24
SRTG: iBoot-13822.81.10
MODE: DFU
PRODUCT: iPhone99,11
MODEL: vresearch101ap
NAME: iPhone 99,11
设备标识为iPhone99,11,型号vresearch101ap,当前处于DFU模式。
在DFU模式下,使用idevicerestore向Apple TSS服务器请求固件签名(SHSH blob):
idevicerestore -e -y ./iPhone17,3_26.1_23B85_Restore -t
成功输出:
Found device in DFU mode
ECID: 206788706982711884
Identified device as vresearch101ap, iPhone99,11
IPSW Product Version: 26.1
IPSW Product Build: 23B85 Major: 23
Getting ApNonce in DFU mode...
Trying to fetch new SHSH blob
Received SHSH blobs
SHSH saved to 'shsh/206788706982711884-iPhone99,11-26.1.shsh'
SHSH blob包含Apple TSS服务器对该设备+固件组合的签名授权。后续构建ramdisk和签名固件组件都需要用到这个blob。
获取SHSH后,执行完整的固件恢复:
idevicerestore -e -y ./iPhone17,3_26.1_23B85_Restore
idevicerestore会将混合固件写入虚拟机的磁盘镜像。恢复完成后虚拟机会启动到kernel panic(因为系统还需要进一步修补),此时按Ctrl+C终止虚拟机。
固件恢复后,系统分区已经写入了iOS文件系统,但还需要通过ramdisk进行一系列修补才能正常启动。
build_ramdisk.py脚本构建一个包含SSH工具的签名ramdisk,过程分为8步:
步骤1: iBSS -> 提取已补丁的payload,用IM4M签名
步骤2: iBEC -> 修改boot参数为ramdisk模式(rd=md0)
步骤3: SPTM -> 直接签名
步骤4: DeviceTree -> 直接签名
步骤5: SEP -> 直接签名
步骤6: TXM -> 应用trustcache绕过补丁后签名
步骤7: Kernel -> 重新打包为rkrn格式并签名
步骤8: Ramdisk -> 构建254MB DMG,注入SSH工具,生成trustcache
步骤2中iBEC的boot参数被修改为ramdisk启动模式:
正常启动: serial=3 -v debug=0x2014e %s
Ramdisk: serial=3 rd=md0 debug=0x2014e -v wdt=-1 %s
rd=md0告诉内核从内存磁盘(md0)启动,wdt=-1禁用看门狗定时器。
步骤8最为复杂,包括:
构建完成后,通过ramdisk_send.sh将所有组件发送到DFU设备并启动:
./ramdisk_send.sh
引导序列分9步,每步通过irecovery发送一个签名固件组件:
[1/8] Loading iBSS... -> DFU进入Recovery
[2/8] Loading iBEC... -> Recovery模式就绪
[3/8] Loading SPTM... -> Secure Page Table Monitor
[4/8] Loading TXM... -> Trusted Execution Monitor
[5/8] Loading trustcache... -> 信任缓存
[6/8] Loading ramdisk... -> 根文件系统
[7/8] Loading device tree... -> 设备树
[8/8] Loading SEP... -> Secure Enclave固件
[*] Booting kernel... -> 启动内核
启动成功后,串口输出会显示ASCII苹果logo和SSH服务就绪信息:
llllllllllllllllllllllllllllllllllllllllllllllllll
llllllllllllllllllllllllllllllllllllllllllllllllll
lllllc:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:clllll
lllll,. .,lllll
lllll, '::::, .,::::. ,lllll
lllll, ,llll; .:llll' ,lllll
lllll, .''''''''''''. ,lllll
lllll, ,llllllllllll, ,lllll
lllll:'....................................':lllll
llllllllllllllllllllllllllllllllllllllllllllllllll
SSHRD_Script by Nathan (verygenericname)
Running server
通过iproxy将USB端口映射到本地:
iproxy 2222 22
然后SSH连接(密码alpine):
ssh root@127.0.0.1 -p2222
连接后确认内核版本:
localhost:~ root# uname -a
Darwin localhost 25.1.0 Darwin Kernel Version 25.1.0: Thu Oct 23 11:11:48 PDT 2025;
root:xnu-12377.42.6~55/RELEASE_ARM64_VRESEARCH1 iPhone99,11
接下来修补启动磁盘。首先处理APFS快照:
mount_apfs -o rw /dev/disk1s1 /mnt1
snaputil -l /mnt1
# 输出: com.apple.os.update-8AAB8DBA5C...
snaputil -n $(snaputil -l /mnt1) orig-fs /mnt1
umount /mnt1
snaputil -n将系统快照重命名为orig-fs,这是iOS越狱中的经典操作,允许内核在启动时挂载修改过的文件系统而非只读快照。
install_cfw.sh脚本通过SSH在ramdisk环境中执行7步系统修改,将vanilla iOS转变为可正常启动的定制固件(Custom Firmware, CFW)。
Cryptex是iOS 16引入的模块化系统组件容器,包含SystemOS(系统库和框架)和AppOS(应用层组件)。虚拟机恢复后这些组件缺失,需要手动安装。
[1/7] Installing Cryptex (SystemOS + AppOS)...
Mounting SystemOS...
Mounting AppOS...
Mounting device rootfs rw...
Copying Cryptexes to device (this takes ~3 minutes)...
Creating dyld symlinks...
[+] Cryptex installed
安装过程:
/System/Cryptexes/OS和/System/Cryptexes/Appseputil是管理SEP(Secure Enclave)存储的系统工具。Gigalocker是SEP的加密锁文件,通过UUID标识。补丁将动态UUID路径替换为固定路径:
[2/7] Patching seputil...
Found format string at 0x1B3F0: b'/%s.gl\x00'
[+] Patched at 0x1B3F1: %s -> AA
/%s.gl -> /AA.gl
Renaming gigalocker...
[+] seputil patched
原始代码使用/%s.gl格式字符串动态构造路径,补丁将%s替换为AA,使路径固定为/AA.gl。同时将磁盘上实际的.gl文件也重命名为AA.gl。
虚拟机使用半虚拟化GPU(AppleParavirtGPU),需要安装对应的Metal驱动:
[3/7] Installing AppleParavirtGPUMetalIOGPUFamily...
[+] GPU driver installed
该驱动是一个IOKit内核扩展包,通过tar解压到设备的文件系统中。
iosbinpack64是一套针对iOS的基础Unix工具集,包含bash、coreutils等必备命令:
[4/7] Installing iosbinpack64...
[+] iosbinpack64 installed
安装后,这些工具位于/iosbinpack64/目录下。由于trustcache已被绕过,这些未经Apple签名的二进制可以正常执行。
launchd_cache_loader负责验证和加载launchd的启动配置缓存。补丁绕过其验证逻辑,允许使用修改过的launchd.plist:
[5/7] Patching launchd_cache_loader...
Found anchor 'unsecure_cache' inside "launchd_unsecure_cache="
Found string ref at 0xB48
Patching: cbz x0, #0xbfc -> nop
[+] NOPped at 0xB58
[+] launchd_cache_loader patched
补丁脚本使用字符串锚点法定位目标代码: 搜索"unsecure_cache"字符串,通过ADRP+ADD指令回溯找到引用位置,然后将附近的条件分支(cbz)替换为nop。
mobileactivationd控制设备激活。补丁让-[DeviceType should_hactivate]方法始终返回YES,绕过激活流程:
[6/7] Patching mobileactivationd...
Found via symtab: va:0x1002F5F84 -> foff:0x2F5F84
Original: ldrb w0, [x0, #0x14]
[+] Patched at 0x2F5F84: mov x0, #1; ret
[+] mobileactivationd patched
补丁脚本使用三层回退策略定位目标方法:
最后一步将SSH(dropbear)、VNC(trollvnc)和bash注入到系统的LaunchDaemons中:
[7/7] Installing LaunchDaemons...
Patching launchd.plist...
[+] Injected bash
[+] Injected dropbear
[+] Injected trollvnc
[+] LaunchDaemons installed
注入方式是将3个daemon plist文件复制到/System/Library/LaunchDaemons/,然后修改launchd.plist将这些daemon添加到启动列表。
安装完成后,通过SSH进入ramdisk执行halt关机:
halt
虚拟机停止后,所有修改已持久化到磁盘镜像。
CFW安装完毕后,使用boot.sh启动虚拟机(不带--dfu标志):
./boot.sh
启动日志显示launchd加载修改后的配置并启动各项服务:
Using unsecure cache: /System/Library/xpc/launchd.plist
Trying to send bytes to launchd: 2563 16384
Sending validated cache to launchd
Cache sent to launchd successfully
(finish-restore) <Notice>: Doing boot task
(finish-demo-restore) <Notice>: Doing boot task
(sysstatuscheck) <Notice>: Doing boot task
(prng_seedctl) <Notice>: Doing boot task
(launchd_cache_loader) <Notice>: Doing boot task
(boot) <Notice>: Early boot complete. Continuing system boot.
<Notice>: Got first unlock unregistering for AKS events
bash-4.4#
进入bash后初始化环境变量:
export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:\
/iosbinpack64/usr/local/sbin:/iosbinpack64/usr/local/bin:\
/iosbinpack64/usr/sbin:/iosbinpack64/usr/bin:\
/iosbinpack64/sbin:/iosbinpack64/bin'
/iosbinpack64/bin/mkdir -p /var/dropbear
/iosbinpack64/bin/cp /iosbinpack64/etc/profile /var/profile
/iosbinpack64/bin/cp /iosbinpack64/etc/motd /var/motd
执行shutdown -h now关机,然后再次启动。此时系统已完全配置好,dropbear SSH服务和trollvnc VNC服务会自动启动。
通过iproxy建立USB端口转发:
iproxy 22222 22222 # SSH端口
iproxy 5901 5901 # VNC端口
SSH连接:
ssh root@127.0.0.1 -p22222
# 密码: alpine
VNC连接: 使用任意VNC客户端连接localhost:5901,即可看到完整的iOS 26图形界面。
SSH连接后确认系统信息:
localhost:~ root# uname -a
Darwin localhost 25.1.0 Darwin Kernel Version 25.1.0: Thu Oct 23 11:11:48 PDT 2025;
root:xnu-12377.42.6~55/RELEASE_ARM64_VRESEARCH1 iPhone99,11
内核版本xnu-12377.42.6,平台VRESEARCH1,设备型号iPhone99,11。这是一个运行iOS 26.1(23B85)的完整虚拟iPhone环境。
从零到一启动虚拟iPhone,整个流程可以概括为以下几个阶段:
阶段1: 环境准备
禁用SIP/AMFI, 编译libimobiledevice, 编译vphone-cli
阶段2: 固件准备
下载iPhone/cloudOS固件, 合并为混合固件, 创建PCC VM模板
阶段3: 引导链补丁
41+处二进制修改: AVPBooter/iBSS/iBEC/LLB/TXM/Kernel
阶段4: 虚拟机创建与固件恢复
DFU引导, SHSH获取, idevicerestore固件写入
阶段5: Ramdisk修补
构建SSH ramdisk, 引导启动, APFS快照处理
阶段6: CFW安装
7步系统修改: Cryptex/seputil/GPU/工具集/launchd/激活/daemon
阶段7: 正常启动
boot.sh启动, iproxy转发, SSH/VNC远程访问
虚拟iPhone对iOS安全研究有极高的实用价值: