
AppleのPCCファームウェアに含まれるVPHONE600APコンポーネントを用いて仮想iPhoneを構築するガイド。ファームウェアのパッチ適用、ブートチェーンの改変、カーネルデバッグを含み、iOSセキュリティ研究のためのものです。
2024年末頃、AppleはPrivate Cloud Computeを導入し始め、クラウドベースのAIプライバシーに新たな地平を開くと主張しました。そして、2025年末頃、興味深いニュースが現れました:AppleはcloudOS 26以降で、PCCファームウェアにvphone600ap関連のコンポーネントを新たに追加したのです。

出典: https://x.com/matteyeux/status/2006339694783848660/photo/1
「iPhone Research Environment Virtual Machine」?
これは、Appleが将来他のセキュリティ研究者向けに仮想iPhone環境を構築・配布する計画的な動きだったのでしょうか、それとも単なるミスだったのでしょうか?2021年にiOS 15.0ベータから15.1 beta3のOTAでDEVELOPMENT/KASANビルドカーネルが発見されたことを考えると、ミスの可能性は否定できません。当時、そのカーネルは約4か月間(2021年6月から10月頃)含まれていました。
そして、今年の1月頃、これらのvphone600ap関連コンポーネントを利用して仮想iPhoneを起動しているツイートが投稿されました。

出典: https://x.com/_inside/status/2008951845725548783

私が見た限り、ほとんどすべてが本当にエレガントに動作していました。以前見たQEMUAppleSilicon(Inferno)プロジェクトと比較して、はるかに機敏でスムーズに動作します。さらに、Metalアクセラレーションもサポートしているように見えました。結局、それに完全に魅了され、1月31日にすぐに取り組み、自分自身の仮想iPhoneを構築し始めました。

参照されているプロジェクトはsecurity-pccです。これは/System/Library/SecurityResearch/usr/bin/vrevmバイナリのソースコードに対応しています。興味深い点は、Virtualization.frameworkが提供するプライベートメソッドを使用していることです。PCC研究で使用される仮想マシンでは、ハードウェアモデルの初期化プロセス中にISAとPlatformVersionが明示的に指定されていることがわかります。

ブートROMには、AVPBooter.vresearch1.binが使用されます(/System/Library/Frameworks/Virtualization.framework/Resources/AVPBooter.vresearch1.bin)

また、SEPROM (avpsepbooter)にはAVPSEPBooter.vresearch1.binが使用され、これはAuxiliaryStorageと同様に機能するSEPStorageファイルを個別にロードします。 (/System/Library/Frameworks/Virtualization.framework/Versions/A/Resources/AVPSEPBooter.vresearch1.bin)
もう一つの興味深い点は、解像度を設定するコードを見ると、1290x2796に設定されていることです。これはiPhone 14 Pro Max、15 Plus、15 Pro Max、16 Plusのデバイスに対応しています。

この情報だけで、仮想iPhoneを起動するためにsuper-tartを修正するには十分すぎるはずです。以下のように修正を行いました。
/Sources/tart/VM.swift```swift ... class VM: NSObject, VZVirtualMachineDelegate, ObservableObject { ... // vzHardwareModel derives the VZMacHardwareModel config specific to the "platform type" // of the VM (currently only vresearch101 supported) static private func vzHardwareModel_VRESEARCH101() throws -> VZMacHardwareModel { var hw_model: VZMacHardwareModel
guard let hw_descriptor = _VZMacHardwareModelDescriptor() else { fatalError("Failed to create hardware descriptor") } hw_descriptor.setPlatformVersion(3) // .appleInternal4 = 3 hw_descriptor.setBoardID(0x90) hw_descriptor.setISA(2) hw_model = VZMacHardwareModel._hardwareModel(withDescriptor: hw_descriptor)
guard hw_model.isSupported else { fatalError("VM hardware config not supported (model.isSupported = false)") }
return hw_model }
static func craftConfiguration( diskURL: URL, nvramURL: URL, romURL: URL, sepromURL: URL? = nil, vmConfig: VMConfig, network: Network = NetworkShared(), additionalStorageDevices: [VZStorageDeviceConfiguration], directorySharingDevices: [VZDirectorySharingDeviceConfiguration], serialPorts: [VZSerialPortConfiguration], suspendable: Bool = false, nested: Bool = false, audio: Bool = true, clipboard: Bool = true, sync: VZDiskImageSynchronizationMode = .full, caching: VZDiskImageCachingMode? = nil ) throws -> VZVirtualMachineConfiguration { let configuration: VZVirtualMachineConfiguration = .init()
// Boot loader let bootloader = try vmConfig.platform.bootLoader(nvramURL: nvramURL) Dynamic(bootloader)._setROMURL(romURL) configuration.bootLoader = bootloader
// SEP ROM let homeURL = FileManager.default.homeDirectoryForCurrentUser var sepstoragePath = homeURL.appendingPathComponent(".tart/vms/vphone/SEPStorage").path let sepstorageURL = URL(fileURLWithPath: sepstoragePath) let sep_config = Dynamic._VZSEPCoprocessorConfiguration(storageURL: sepstorageURL) if let sepromURL { // default AVPSEPBooter.vresearch1.bin from VZ framework sep_config.romBinaryURL = sepromURL } sep_config.debugStub = Dynamic._VZGDBDebugStubConfiguration(port: 8001) configuration._setCoprocessors([sep_config.asObject])
// Some vresearch101 config let pconf = VZMacPlatformConfiguration() pconf.hardwareModel = try vzHardwareModel_VRESEARCH101()
let serial = Dynamic._VZMacSerialNumber.initWithString("AAAAAA1337") let identifier = Dynamic.VZMacMachineIdentifier._machineIdentifierWithECID(0x1111111111111111, serialNumber: serial.asObject) pconf.machineIdentifier = identifier.asObject as! VZMacMachineIdentifier
pconf._setProductionModeEnabled(true) var auxiliaryStoragePath = homeURL.appendingPathComponent(".tart/vms/vphone/nvram.bin").path let auxiliaryStorageURL = URL(fileURLWithPath: auxiliaryStoragePath) pconf.auxiliaryStorage = VZMacAuxiliaryStorage(url: auxiliaryStorageURL)
if #available(macOS 14, *) { let keyboard = VZUSBKeyboardConfiguration() configuration.keyboards = [keyboard] }
if #available(macOS 14, *) { let touch = _VZUSBTouchScreenConfiguration() configuration._setMultiTouchDevices([touch]) } ... configuration.platform = pconf
// Display let graphics_config = VZMacGraphicsDeviceConfiguration() let displays_config = VZMacGraphicsDisplayConfiguration( widthInPixels: 1179, heightInPixels: 2556, pixelsPerInch: 460 ) graphics_config.displays.append(displays_config) configuration.graphicsDevices = [graphics_config] ...
# ファームウェアの改変
参照プロジェクトは[vma2pwn](https://github.com/nick-botticelli/vma2pwn)です。特にバージョン12.0.1では、ブートチェーンのほぼ全体を改変したMac仮想マシンを起動します。
最初に[prepare.sh](https://github.com/nick-botticelli/vma2pwn/blob/main/prepare.sh)スクリプトを見てみましょう。これはブートローダーやカーネルなどのファームウェアコンポーネントをIM4P形式からRAW形式に抽出し、特定のハードコードされたアドレスに対して命令/データのパッチを適用します。RestoreRamdiskはファームウェア復元時に使用されるルートファイルシステムであり、AVPBooterは仮想マシンで使用されるBootROMです。
要約すると、ファームウェアに含まれる個々のファイルを抽出し、カスタムファームウェアの復元を許可するための整合性チェックをパッチするか、またはブート関連のログを表示しやすくするためにboot-argsパラメータを変更します。