[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-74741":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":14,"forks30d":14,"starsTrendScore":16,"compositeScore":18,"rankGlobal":8,"rankLanguage":8,"license":8,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":8,"pushedAt":8,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":14,"starSnapshotCount":14,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},74741,"super-tart-vphone-writeup","wh1te4ever\u002Fsuper-tart-vphone-writeup","wh1te4ever",null,"Swift",1117,165,16,5,0,1,3,13,19.66,false,"main",[],"2026-06-12 02:03:27","# Building virtual iPhone using VPHONE600AP component of recently released PCC firmware\n\n# Special Thanks \u002F Acknowledgements\n\n- [dlevi309](https:\u002F\u002Fgithub.com\u002Fdlevi309) (Provided ideas for touch interaction on virtual iPhone)\n- [khanhduytran0](https:\u002F\u002Fgithub.com\u002Fkhanhduytran0), [34306](https:\u002F\u002Fgithub.com\u002F34306), [asdfugil](https:\u002F\u002Fgithub.com\u002Fasdfugil), [verygenericname](https:\u002F\u002Fgithub.com\u002Fverygenericname) (Provided other ideas for building virtual iPhone, including Cryptex, Device Activation, Ramdisk booting, etc.)\n- [ma4the](https:\u002F\u002Fgithub.com\u002Fma4the), [Mard](https:\u002F\u002Fgithub.com\u002FMardcelo), [SwallowS](https:\u002F\u002Fgithub.com\u002Fswollows) (Testing if works well on other environment)\n\n# Motivation\n\nAround late 2024, Apple began introducing [Private Cloud Compute](https:\u002F\u002Fsecurity.apple.com\u002Fblog\u002Fprivate-cloud-compute\u002F), claiming to open new horizon for cloud-based AI privacy. Then, around late 2025, some interesting news appeared: Apple had newly added vphone600ap-related components to PCC firmware, starting with cloudOS 26.\n\n![Source: [https:\u002F\u002Fx.com\u002Fmatteyeux\u002Fstatus\u002F2006339694783848660\u002Fphoto\u002F1](https:\u002F\u002Fx.com\u002Fmatteyeux\u002Fstatus\u002F2006339694783848660\u002Fphoto\u002F1)](contents\u002Fimage.png)\n\nSource: [https:\u002F\u002Fx.com\u002Fmatteyeux\u002Fstatus\u002F2006339694783848660\u002Fphoto\u002F1](https:\u002F\u002Fx.com\u002Fmatteyeux\u002Fstatus\u002F2006339694783848660\u002Fphoto\u002F1)\n\n**\"iPhone Research Environment Virtual Machine”?**\n\nIs this a planned move by Apple to build and distribute a virtual iPhone environment for other security researchers in the future, or was it simply a mistake? Given that DEVELOPMENT\u002FKASAN build kernel was once discovered in the iOS 15.0 beta to 15.1 beta3 OTAs back in 2021, the possibility of a slip-up cannot be ruled out. At that time, the kernel remained included for about 4 months, roughly from June to October 2021.\n\nThen, around January of this year, a tweet was posted showing a virtual iPhone booting up utilizing these vphone600ap-related components.\n\n![Source: [https:\u002F\u002Fx.com\u002F_inside\u002Fstatus\u002F2008951845725548783](https:\u002F\u002Fx.com\u002F_inside\u002Fstatus\u002F2008951845725548783)](contents\u002FScreenshot_2026-02-24_at_7.37.31_PM.png)\n\nSource: [https:\u002F\u002Fx.com\u002F_inside\u002Fstatus\u002F2008951845725548783](https:\u002F\u002Fx.com\u002F_inside\u002Fstatus\u002F2008951845725548783)\n\n![Screenshot 2026-02-24 at 7.39.03 PM.png](contents\u002FScreenshot_2026-02-24_at_7.39.03_PM.png)\n\nFrom what I saw, almost everything worked truly elegantly. Compared to the [QEMUAppleSilicon(Inferno) project](https:\u002F\u002Fgithub.com\u002FChefKissInc\u002FInferno) I had seen previously, it runs much snappier and smoother. Furthermore, it even appeared to support Metal acceleration. Ultimately, completely captivated by it, I dove right in and started building my own virtual iPhone on January 31st.\n\n![Screenshot 2026-02-24 at 7.46.41 PM.png](contents\u002FScreenshot_2026-02-24_at_7.46.41_PM.png)\n\n# **Modifying super-tart to boot virtual iPhone**\n\nThe referenced project is [security-pcc](https:\u002F\u002Fgithub.com\u002Fapple\u002Fsecurity-pcc). It corresponds to the source code of the \u002FSystem\u002FLibrary\u002FSecurityResearch\u002Fusr\u002Fbin\u002Fvrevm binary. An interesting point is that it uses private methods provided by Virtualization.framework. In the virtual machine used for PCC research, you can see that the ISA and PlatformVersion are explicitly specified during the hardware model initialization process.\n\n![Screenshot 2026-02-24 at 8.27.01 PM.png](contents\u002FScreenshot_2026-02-24_at_8.27.01_PM.png)\n\nFor the bootrom, AVPBooter.vresearch1.bin is used (\u002FSystem\u002FLibrary\u002FFrameworks\u002FVirtualization.framework\u002FResources\u002FAVPBooter.vresearch1.bin)\n\n![Screenshot 2026-02-24 at 8.32.08 PM.png](contents\u002FScreenshot_2026-02-24_at_8.32.08_PM.png)\n\nand for the SEPROM (avpsepbooter), AVPSEPBooter.vresearch1.bin is used, which separately loads a SEPStorage file that functions similarly to [AuxiliaryStorage](https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fvirtualization\u002Fvzmacplatformconfiguration\u002Fauxiliarystorage).\n(\u002FSystem\u002FLibrary\u002FFrameworks\u002FVirtualization.framework\u002FVersions\u002FA\u002FResources\u002FAVPSEPBooter.vresearch1.bin)\n\nAnother interesting point is that if you look at the code for setting the resolution, it is set to 1290x2796, which corresponds to the iPhone 14 Pro Max, 15 Plus, 15 Pro Max, and 16 Plus devices.\n\n![Screenshot 2026-02-24 at 8.34.11 PM.png](contents\u002FScreenshot_2026-02-24_at_8.34.11_PM.png)\n\nWith just this information, it should be more than enough to modify [super-tart](https:\u002F\u002Fgithub.com\u002FJJTech0130\u002Fsuper-tart) to boot the virtual iPhone. I made the modifications as shown below.\n\n- \u002FSources\u002Ftart\u002FVM.swift\n\n```swift\n...\nclass VM: NSObject, VZVirtualMachineDelegate, ObservableObject {\n...\n  \u002F\u002F vzHardwareModel derives the VZMacHardwareModel config specific to the \"platform type\"\n  \u002F\u002F of the VM (currently only vresearch101 supported)\n  static private func vzHardwareModel_VRESEARCH101() throws -> VZMacHardwareModel {\n    var hw_model: VZMacHardwareModel\n\n    guard let hw_descriptor = _VZMacHardwareModelDescriptor() else {\n      fatalError(\"Failed to create hardware descriptor\")\n    }\n    hw_descriptor.setPlatformVersion(3) \u002F\u002F .appleInternal4 = 3\n    hw_descriptor.setBoardID(0x90)\n    hw_descriptor.setISA(2)\n    hw_model = VZMacHardwareModel._hardwareModel(withDescriptor: hw_descriptor)\n\n    guard hw_model.isSupported else {\n        fatalError(\"VM hardware config not supported (model.isSupported = false)\")\n    }\n\n    return hw_model\n  }\n\n  static func craftConfiguration(\n    diskURL: URL,\n    nvramURL: URL,\n    romURL: URL,\n    sepromURL: URL? = nil,\n    vmConfig: VMConfig,\n    network: Network = NetworkShared(),\n    additionalStorageDevices: [VZStorageDeviceConfiguration],\n    directorySharingDevices: [VZDirectorySharingDeviceConfiguration],\n    serialPorts: [VZSerialPortConfiguration],\n    suspendable: Bool = false,\n    nested: Bool = false,\n    audio: Bool = true,\n    clipboard: Bool = true,\n    sync: VZDiskImageSynchronizationMode = .full,\n    caching: VZDiskImageCachingMode? = nil\n  ) throws -> VZVirtualMachineConfiguration {\n    let configuration: VZVirtualMachineConfiguration = .init()\n\n    \u002F\u002F Boot loader\n    let bootloader = try vmConfig.platform.bootLoader(nvramURL: nvramURL)\n    Dynamic(bootloader)._setROMURL(romURL)\n    configuration.bootLoader = bootloader\n\n    \u002F\u002F SEP ROM\n    let homeURL = FileManager.default.homeDirectoryForCurrentUser\n    var sepstoragePath = homeURL.appendingPathComponent(\".tart\u002Fvms\u002Fvphone\u002FSEPStorage\").path\n    let sepstorageURL = URL(fileURLWithPath: sepstoragePath)\n    let sep_config = Dynamic._VZSEPCoprocessorConfiguration(storageURL: sepstorageURL)\n    if let sepromURL { \u002F\u002F default AVPSEPBooter.vresearch1.bin from VZ framework\n        sep_config.romBinaryURL = sepromURL\n    }\n    sep_config.debugStub = Dynamic._VZGDBDebugStubConfiguration(port: 8001)\n    configuration._setCoprocessors([sep_config.asObject])\n    \n    \u002F\u002F Some vresearch101 config\n    let pconf = VZMacPlatformConfiguration()\n    pconf.hardwareModel = try vzHardwareModel_VRESEARCH101()\n\n    let serial = Dynamic._VZMacSerialNumber.initWithString(\"AAAAAA1337\")\n    let identifier = Dynamic.VZMacMachineIdentifier._machineIdentifierWithECID(0x1111111111111111, serialNumber: serial.asObject)\n    pconf.machineIdentifier = identifier.asObject as! VZMacMachineIdentifier\n\n    pconf._setProductionModeEnabled(true)\n    var auxiliaryStoragePath = homeURL.appendingPathComponent(\".tart\u002Fvms\u002Fvphone\u002Fnvram.bin\").path\n    let auxiliaryStorageURL = URL(fileURLWithPath: auxiliaryStoragePath)\n    pconf.auxiliaryStorage = VZMacAuxiliaryStorage(url: auxiliaryStorageURL)\n\n    if #available(macOS 14, *) {\n      let keyboard = VZUSBKeyboardConfiguration()\n      configuration.keyboards = [keyboard]\n    }\n\n    if #available(macOS 14, *) {\n      let touch = _VZUSBTouchScreenConfiguration()\n      configuration._setMultiTouchDevices([touch])\n    }\n    ...\n    configuration.platform = pconf\n\n    \u002F\u002F Display\n    let graphics_config = VZMacGraphicsDeviceConfiguration()\n    let displays_config = VZMacGraphicsDisplayConfiguration(\n        widthInPixels: 1179,\n        heightInPixels: 2556,\n        pixelsPerInch: 460\n    )\n    graphics_config.displays.append(displays_config)\n    configuration.graphicsDevices = [graphics_config]\n ...   \n```\n\n# Modifying the Firmware\n\nThe referenced project is [vma2pwn](https:\u002F\u002Fgithub.com\u002Fnick-botticelli\u002Fvma2pwn). Specifically for version 12.0.1, it boots a Mac virtual machine with almost the entire bootchain modified.\n\nLet's look at the [prepare.sh](https:\u002F\u002Fgithub.com\u002Fnick-botticelli\u002Fvma2pwn\u002Fblob\u002Fmain\u002Fprepare.sh) script first. It extracts firmware components, such as the bootloader and kernel compressed in IM4P format, into RAW format and patches instructions\u002Fdata at specific hardcoded addresses. RestoreRamdisk is the root filesystem used when restoring the firmware, and AVPBooter is the BootROM used in the virtual machine.\n\nTo summarize, it extracts the individual files included in the firmware and patches integrity checks to allow the restoration of custom firmware, or modifies the boot-args parameters to make it easier to view boot-related logs.\n\nFinally, [vma2pwn.sh](https:\u002F\u002Fgithub.com\u002Fnick-botticelli\u002Fvma2pwn\u002Fblob\u002Fmain\u002Fvma2pwn.sh) is responsible for restoring the custom firmware. It does this by entering DFU mode beforehand. Here, the virtual machine uses something called super-tart. This is a version of the existing tart virtual machine with added features like a custom bootrom, serial output, DFU mode, and GDB debugging. (Note that SIP\u002FAMFI must be disabled for this to work.)\n\nI have used it quite usefully recently while I [studying XNU kernel 1-day vulnerabilities (CVE-2021-30937, CVE-2021-30955)](https:\u002F\u002Fgithub.com\u002Fwh1te4ever\u002Fxnu_1day_practice). It is fantastic because it supports live kernel debugging.\n\n## Building Custom Firmware\n\nI mixed the components of cloudOS 26.1 (23B85) and iOS 26.1 (iPhone17,3; 23B85), uh,,, but... I can't remember the exact details. To be precise, I had to properly mix the iPhone 16 and vphone-related components to create the custom firmware, but I've forgotten exactly which ones I ended up mixing. From what I recall:\n\n- BuildManifest.plist:\nI modified the dictionary elements under the Manifest key. I configured it so that during the restore process, the SystemVolume, SystemVolumeCanonicalMetadata, OS, StaticTrustCache, RestoreTrustCache, and RestoreRamDisk from iPhone 16(iOS 26.1) model would be used. The rest were set up to use vphone-related files from PCC firmware.\n- Restore.plist:\nI believe I added properties related to DeviceMap or SupportedProductTypes, or changed the SystemRestoreImageFileSystems element.\n\nThe files below are the final result of my mix.\n\n[Restore.plist](contents\u002FRestore.plist)\n\n[BuildManifest.plist](contents\u002FBuildManifest.plist)\n\n- get_fw.py (Partial)\n\n```python\n...\n\n# 3. Import things from cloudOS\n# kernelcache\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002Fkernelcache.* iPhone17,3_26.1_23B85_Restore\")\n# agx, all_flash, ane, dfu, pmp...\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002FFirmware\u002Fagx\u002F* iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fagx\")\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002FFirmware\u002Fall_flash\u002F* iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\")\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002FFirmware\u002Fane\u002F* iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fane\")\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002FFirmware\u002Fdfu\u002F* iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\")\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002FFirmware\u002Fpmp\u002F* iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fpmp\")\n# sptm, txm, etc...\nos.system(\"cp 399b664dd623358c3de118ffc114e42dcd51c9309e751d43bc949b98f4e31349_extracted\u002FFirmware\u002F*.im4p iPhone17,3_26.1_23B85_Restore\u002FFirmware\")\n\n# 4. TODO: parse what things needed from BuildManifest.plist, Restore.plist in cloudOS 26.1\n# It will be really complicated, so import things from already parse completed\nos.system(\"sudo cp custom_26.1\u002FBuildManifest.plist iPhone17,3_26.1_23B85_Restore\")\nos.system(\"sudo cp custom_26.1\u002FRestore.plist iPhone17,3_26.1_23B85_Restore\")\n\nos.system(\"echo 'Done, grabbed all needed components for restoring'\")\n```\n\n## Patch AVPBooter.vresearch1.bin\n\nI referenced [that post](https:\u002F\u002Fgist.github.com\u002Fsteven-michaud\u002Ffda019a4ae2df3a9295409053a53a65c#iboot-stage-0-avpbootervmapple2binorg). You must patch `image4_validate_property_callback` in order to load  custom bootloader afterward. Simply use \"Text-search (slow!)\" feature in IDA Pro to search for \"0x4447\", and patch the epilogue of the corresponding function to always return 0.\n\n![image.png](contents\u002Fimage%201.png)\n\n## Modifying and Building libirecovery\n\nBefore restoring the firmware, a few modifications were necessary to support the vresearch101ap model. Once built, firmware restoration becomes possible using the [idevicerestore](https:\u002F\u002Fgithub.com\u002Flibimobiledevice\u002Fidevicerestore) tool.\n\n[https:\u002F\u002Fgithub.com\u002Fwh1te4ever\u002Flibirecovery](https:\u002F\u002Fgithub.com\u002Fwh1te4ever\u002Flibirecovery)\n\n![Screenshot 2026-02-24 at 9.52.14 PM.png](contents\u002FScreenshot_2026-02-24_at_9.52.14_PM.png)\n\n## **Patching Firmware Components**\n\nSimilar to AVPBooter, the bootloaders used for restoration, iBSS and iBEC, were patched to bypass signature verification. I also enabled serial log output so that if there are any booting issues, the cause can be identified immediately.\n\nAs you will see later, bypassing [SSV (Signed System Volume) verification](https:\u002F\u002Fsupport.apple.com\u002Ffr-lu\u002Fguide\u002Fsecurity\u002Fsecd698747c9\u002Fweb) is required to load an arbitrary Cryptex. This is performed in the LLB, which is loaded when booting in normal mode rather than DFU mode, and verification is also sometimes performed in the kernel.\n\nAdditionally, I patched the TXM so that even if a binary\u002Flibrary is not registered in the Trustcache, it is recognized as if it were.\n\n- patch_fw.py (Partial content, Part 1)\n\n```python\n# Patch iBSS\n# patch image4_validate_property_callback\npatch(0x9D10, 0xd503201f)   #nop\npatch(0x9D14, 0xd2800000)   #mov x0, #0\n\n# Patch iBEC\n# patch image4_validate_property_callback\npatch(0x9D10, 0xd503201f)   #nop\npatch(0x9D14, 0xd2800000)   #mov x0, #0\n# patch boot-args with \"serial=3 -v debug=0x2014e %s\"\npatch(0x122d4, 0xd0000082)  #adrp x2, #0x12000\npatch(0x122d8, 0x9101c042)  #add x2, x2, #0x70\npatch(0x24070, \"serial=3 -v debug=0x2014e %s\")\n\n# Patch LLB\n# patch image4_validate_property_callback\npatch(0xA0D8, 0xd503201f)   #nop\npatch(0xA0DC, 0xd2800000)   #mov x0, #0\n# patch boot-args with \"serial=3 -v debug=0x2014e %s\"\npatch(0x12888, 0xD0000082)  #adrp x2, #0x12000\npatch(0x1288C, 0x91264042)  #add x2, x2, #0x990\npatch(0x24990, \"serial=3 -v debug=0x2014e %s\")\n# make possible load edited rootfs (needed to command snaputil -n later)\npatch(0x2BFE8, 0x1400000b)\npatch(0x2bca0, 0xd503201f)\npatch(0x2C03C, 0x17ffff6a)\npatch(0x2fcec, 0xd503201f)\npatch(0x2FEE8, 0x14000009)\n# some unknown patch, bypass panic\npatch(0x1AEE4, 0xd503201f)  #nop\n\n# 6. Grab & Patch TXM\n# Patch TXM for make running binary which is not registered in trustcache\n# TXM [Error]: CodeSignature: selector: 24 | 0xA8 | 0x30 | 1\n# Some trace: FFFFFFF01702B018->sub_FFFFFFF0170306E4->sub_FFFFFFF01703059C->sub_FFFFFFF01703037C->sub_FFFFFFF017030164->sub_FFFFFFF01702EC70 (base: 0xFFFFFFF017004000)\npatch(0x2c1f8, 0xd2800000)      #FFFFFFF0170301F8\npatch(0x2bef4, 0xd2800000)      #FFFFFFF01702FEF4\npatch(0x2c060, 0xd2800000)      #FFFFFFF017030060\n\n# 7. Grab & patch kernelcache\n# ========= Bypass SSV =========\n# _apfs_vfsop_mount: Prevent panic \"Failed to find the root snapshot. Rooting from the live fs ...\"\npatch(0x2476964, 0xd503201f)  #FFFFFE000947A964\n# _authapfs_seal_is_broken: Prevent panic \"root volume seal is broken ...\"\npatch(0x23cfde4, 0xd503201f) #FFFFFE00093D3DE4 \n# _bsd_init: Prevent panic \"rootvp not authenticated after mounting ...\"\npatch(0xf6d960, 0xd503201f)    #FFFFFE0007F71960\n...\n```\n\nAfter converting to the RAW format and patching it, you need to convert it back to IM4P.\nIn the case of the kernel or TXM, a PAYP structure exists, so it was necessary to preserve that structure.\nBelow is the code that converts IM4P → RAW → IM4P using [pyimg4](https:\u002F\u002Fpypi.org\u002Fproject\u002Fpyimg4\u002F), [img4tool](https:\u002F\u002Fgithub.com\u002Ftihmstar\u002Fimg4tool), [img4](https:\u002F\u002Fgithub.com\u002Fxerub\u002Fimg4lib) tool.\n\n- patch_fw.py (Partial content, Part 2)\n\n```python\n...\n\n# Patch iBSS\nif not os.path.exists(\"iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p.bak\"):\n    os.system(\"cp iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p.bak\")\nos.system(\"tools\u002Fimg4 -i iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p.bak -o iBSS.vresearch101.RELEASE\")\n... # patch things from raw\nos.system(\"tools\u002Fimg4tool -c iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p -t ibss iBSS.vresearch101.RELEASE\")\n\n# Patch iBEC\nif not os.path.exists(\"iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p.bak\"):\n    os.system(\"cp iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p.bak\")\nos.system(\"tools\u002Fimg4 -i iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p.bak -o iBEC.vresearch101.RELEASE\")\n... # patch things from raw\nos.system(\"tools\u002Fimg4tool -c iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p -t ibec iBEC.vresearch101.RELEASE\")\n\n# Patch LLB\nif not os.path.exists(\"iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002FLLB.vresearch101.RESEARCH_RELEASE.im4p.bak\"):\n    os.system(\"cp iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002FLLB.vresearch101.RESEARCH_RELEASE.im4p iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002FLLB.vresearch101.RESEARCH_RELEASE.im4p.bak\")\nos.system(\"tools\u002Fimg4 -i iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002FLLB.vresearch101.RESEARCH_RELEASE.im4p.bak -o LLB.vresearch101.RESEARCH_RELEASE\")\n... # patch things from raw\nos.system(\"tools\u002Fimg4tool -c iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002FLLB.vresearch101.RESEARCH_RELEASE.im4p -t illb LLB.vresearch101.RESEARCH_RELEASE\")\n\n# 6. Grab & Patch TXM\nif not os.path.exists(\"iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.research.im4p.bak\"):\n    os.system(\"cp iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.research.im4p iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.research.im4p.bak\")\nos.system(\"pyimg4 im4p extract -i iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.research.im4p.bak -o txm.raw\")\n... # patch things from raw\n#create im4p\nos.system(\"pyimg4 im4p create -i txm.raw -o txm.im4p -f trxm --lzfse\")\n# preserve payp structure\ntxm_im4p_data = Path('iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.research.im4p.bak').read_bytes()\npayp_offset = txm_im4p_data.rfind(b'PAYP')\nif payp_offset == -1:\n    print(\"Couldn't find payp structure !!!\")\n    sys.exit()\n\nwith open('txm.im4p', 'ab') as f:\n    f.write(txm_im4p_data[(payp_offset-10):])\n\npayp_sz = len(txm_im4p_data[(payp_offset-10):])\nprint(f\"payp sz: {payp_sz}\")\n\ntxm_im4p_data = bytearray(open('txm.im4p', 'rb').read())\ntxm_im4p_data[2:5] = (int.from_bytes(txm_im4p_data[2:5], 'big') + payp_sz).to_bytes(3, 'big')\nopen('txm.im4p', 'wb').write(txm_im4p_data)\nos.system(\"mv txm.im4p iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.research.im4p\")\n\n# 7. Grab & patch kernelcache\nif not os.path.exists(\"iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak\"):\n    os.system(\"cp iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600 iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak\")\nos.system(\"pyimg4 im4p extract -i iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak -o kcache.raw\")\n... # patch things from raw\n#create im4p\nos.system(\"pyimg4 im4p create -i kcache.raw -o krnl.im4p -f krnl --lzfse\")\n\n# preserve payp structure\nkernel_im4p_data = Path('iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak').read_bytes()\npayp_offset = kernel_im4p_data.rfind(b'PAYP')\nif payp_offset == -1:\n    print(\"Couldn't find payp structure !!!\")\n    sys.exit()\n\nwith open('krnl.im4p', 'ab') as f:\n    f.write(kernel_im4p_data[(payp_offset-10):])\n\npayp_sz = len(kernel_im4p_data[(payp_offset-10):])\nprint(f\"payp sz: {payp_sz}\")\n\nkernel_im4p_data = bytearray(open('krnl.im4p', 'rb').read())\nkernel_im4p_data[2:5] = (int.from_bytes(kernel_im4p_data[2:5], 'big') + payp_sz).to_bytes(3, 'big')\nopen('krnl.im4p', 'wb').write(kernel_im4p_data)\n\nos.system(\"mv krnl.im4p iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600\")\n...\n\n```\n\n# Restoring Firmware\n\nOnce everything is ready, let's put the virtual machine into DFU mode and try restoring it.\n\nBelow is a screenshot of the panic that occurs if the SEP is not configured properly. If you set it up correctly, it should pass this point without any issues.\n\n![image.png](contents\u002Fimage%202.png)\n\nAfter the restore is complete, it reboots automatically.\nHowever, a panic occurs in the launchd process because the \u002Fusr\u002Flib\u002FlibSystem.B.dylib library is missing. This library is located within the dyld_shared_cache on the Cryptex partition, and for some reason, the Cryptex partition could not be restored. As a temporary workaround, you must create an [SSH Ramdisk](https:\u002F\u002Fgithub.com\u002Fverygenericname\u002FSSHRD_Script) to modify the root file system and inject the necessary files. That is exactly why the patch related to SSV verification was needed.\n\n![Screenshot 2026-02-24 at 10.24.33 PM.png](contents\u002FScreenshot_2026-02-24_at_10.24.33_PM.png)\n\n![image.png](contents\u002Fimage%203.png)\n\n# Fixing Boot Issue by Booting with SSH Ramdisk\n\nI am going to try fixing the boot failure issue by utilizing the ramdisk used in https:\u002F\u002Fgithub.com\u002Fverygenericname\u002FSSHRD_Script.\n\nTo upload and load components like the bootloader or kernel using the [irecovery](https:\u002F\u002Fgithub.com\u002Flibimobiledevice\u002Flibirecovery) tool in DFU mode, an IMG4 image is needed, which requires an IM4M file. Therefore, I first fetched shsh file using idevicerestore tool, and then converted it into an IM4M file.\n\n```bash\nidevicerestore -e -y .\u002FiPhone17,3_26.1_23B85_Restore -t\n\nmv shsh\u002F[ECID]-iPhone99,11-26.1.shsh shsh\u002F[ECID]-iPhone99,11-26.1.shsh.gz\n\ngunzip shsh\u002F[ECID]-iPhone99,11-26.1.shsh.gz\n\n...\n\npyimg4 im4m  extract -i shsh\u002F[ECID]-iPhone99,11-26.1.shsh -o vphone.im4m\n```\n\nThen, using that IM4M file, I generated several IMG4 files for each of the firmware components used, such as iBSS, iBEC, and the devicetree.\n\n```python\n# 1. Grab & Patch iBSS \nif not os.path.exists(\"iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p.bak\"):\n    os.system(\"cp iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p.bak\")\nos.system(\"tools\u002Fimg4 -i iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBSS.vresearch101.RELEASE.im4p.bak -o iBSS.vresearch101.RELEASE\")\n... # patch things from raw\nos.system(\"tools\u002Fimg4tool -c iBSS.vresearch101.RELEASE.im4p -t ibss iBSS.vresearch101.RELEASE\")\nos.system(\"tools\u002Fimg4 -i iBSS.vresearch101.RELEASE.im4p -o .\u002FRamdisk\u002FiBSS.vresearch101.RELEASE.img4 -M .\u002Fvphone.im4m\")\n\n# 2. Grab & Patch iBEC\nif not os.path.exists(\"iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p.bak\"):\n    os.system(\"cp iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p.bak\")\nos.system(\"tools\u002Fimg4 -i iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fdfu\u002FiBEC.vresearch101.RELEASE.im4p -o iBEC.vresearch101.RELEASE\")\n... # patch things from raw\nos.system(\"tools\u002Fimg4tool -c iBEC.vresearch101.RELEASE.im4p -t ibec iBEC.vresearch101.RELEASE\")\nos.system(\"tools\u002Fimg4 -i iBEC.vresearch101.RELEASE.im4p -o Ramdisk\u002FiBEC.vresearch101.RELEASE.img4 -M vphone.im4m\")\n\n# 3. Grab SPTM\nos.system(\"tools\u002Fimg4 -i iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fsptm.vresearch1.release.im4p -o Ramdisk\u002Fsptm.vresearch1.release.img4 -M vphone.im4m -T sptm\")\n\n# 4. Grab devicetree\nos.system(\"tools\u002Fimg4 -i iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002FDeviceTree.vphone600ap.im4p -o Ramdisk\u002FDeviceTree.vphone600ap.img4 -M vphone.im4m -T rdtr\")\n\n# 5. Grab sep\nos.system(\"tools\u002Fimg4 -i iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Fall_flash\u002Fsep-firmware.vresearch101.RELEASE.im4p -o Ramdisk\u002Fsep-firmware.vresearch101.RELEASE.img4 -M vphone.im4m -T rsep\")\n\n# 6. Grab & Patch TXM\nif not os.path.exists(\"iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.release.im4p.bak\"):\n    os.system(\"cp iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.release.im4p iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.release.im4p.bak\")\nos.system(\"pyimg4 im4p extract -i iPhone17\\\\,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.release.im4p.bak -o txm.raw\")\n... # patch things from raw\n#create im4p\nos.system(\"pyimg4 im4p create -i txm.raw -o txm.im4p -f trxm --lzfse\")\n# preserve payp structure\ntxm_im4p_data = Path('iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002Ftxm.iphoneos.release.im4p.bak').read_bytes()\npayp_offset = txm_im4p_data.rfind(b'PAYP')\nif payp_offset == -1:\n    print(\"Couldn't find payp structure !!!\")\n    sys.exit()\n\nwith open('txm.im4p', 'ab') as f:\n    f.write(txm_im4p_data[(payp_offset-10):])\n\npayp_sz = len(txm_im4p_data[(payp_offset-10):])\nprint(f\"payp sz: {payp_sz}\")\n\ntxm_im4p_data = bytearray(open('txm.im4p', 'rb').read())\ntxm_im4p_data[2:5] = (int.from_bytes(txm_im4p_data[2:5], 'big') + payp_sz).to_bytes(3, 'big')\nopen('txm.im4p', 'wb').write(txm_im4p_data)\n\n# sign\nos.system(\"pyimg4 img4 create -p txm.im4p -o Ramdisk\u002Ftxm.img4 -m vphone.im4m\")\n\n# 7. Grab & patch kernelcache\nif not os.path.exists(\"iPhone17\\\\,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak\"):\n    os.system(\"cp iPhone17\\\\,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600 iPhone17\\\\,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak\")\nos.system(\"pyimg4 im4p extract -i iPhone17\\\\,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak -o kcache.raw\")\n... # patch things from raw\n\n#create im4p\nos.system(\"pyimg4 im4p create -i kcache.raw -o krnl.im4p -f rkrn --lzfse\")\n\n# preserve payp structure\nkernel_im4p_data = Path('iPhone17,3_26.1_23B85_Restore\u002Fkernelcache.research.vphone600.bak').read_bytes()\npayp_offset = kernel_im4p_data.rfind(b'PAYP')\nif payp_offset == -1:\n    print(\"Couldn't find payp structure !!!\")\n    sys.exit()\n\nwith open('krnl.im4p', 'ab') as f:\n    f.write(kernel_im4p_data[(payp_offset-10):])\n\npayp_sz = len(kernel_im4p_data[(payp_offset-10):])\nprint(f\"payp sz: {payp_sz}\")\n\nkernel_im4p_data = bytearray(open('krnl.im4p', 'rb').read())\nkernel_im4p_data[2:5] = (int.from_bytes(kernel_im4p_data[2:5], 'big') + payp_sz).to_bytes(3, 'big')\nopen('krnl.im4p', 'wb').write(kernel_im4p_data)\n\n# sign\nos.system(\"pyimg4 img4 create -p krnl.im4p -o Ramdisk\u002Fkrnl.img4 -m vphone.im4m\")\n\n# 8. Grab ramdisk & build custom ramdisk\nos.system(\"pyimg4 im4p extract -i iPhone17,3_26.1_23B85_Restore\u002F043-53775-129.dmg -o ramdisk.dmg\")\nos.system(\"mkdir SSHRD\")\nos.system(\"sudo hdiutil attach -mountpoint SSHRD ramdisk.dmg -owners off\")\nos.system(\"sudo hdiutil create -size 254m -imagekey diskimage-class=CRawDiskImage -format UDZO -fs APFS -layout NONE -srcfolder SSHRD -copyuid root ramdisk1.dmg\")\nos.system(\"sudo hdiutil detach -force SSHRD\")\nos.system(\"sudo hdiutil attach -mountpoint SSHRD ramdisk1.dmg -owners off\")\n\n... #remove unneccessary files for expand space\n\n#resign all things preserving ents\ntarget_path= [\n    \"SSHRD\u002Fusr\u002Flocal\u002Fbin\u002F*\", \"SSHRD\u002Fusr\u002Flocal\u002Flib\u002F*\",\n    \"SSHRD\u002Fusr\u002Fbin\u002F*\", \"SSHRD\u002Fbin\u002F*\",\n    \"SSHRD\u002Fusr\u002Flib\u002F*\", \"SSHRD\u002Fsbin\u002F*\", \"SSHRD\u002Fusr\u002Fsbin\u002F*\", \"SSHRD\u002Fusr\u002Flibexec\u002F*\"\n]\nfor pattern in target_path:\n    for path in glob.glob(pattern):\n        if os.path.isfile(path) and not os.path.islink(path):\n            if \"Mach-O\" in subprocess.getoutput(f\"file \\\"{path}\\\"\"):\n                os.system(f\"tools\u002Fldid_macosx_arm64 -S -M -Cadhoc \\\"{path}\\\"\")\n\n#8-2. Grab & build custom ramdisk's trustcache while building custom ramdisk\nos.system(\"pyimg4 im4p extract -i iPhone17,3_26.1_23B85_Restore\u002FFirmware\u002F043-53775-129.dmg.trustcache -o trustcache.raw\")\nos.system(\"tools\u002Ftrustcache_macos_arm64 create sshrd.tc SSHRD\")\nos.system(\"pyimg4 im4p create -i sshrd.tc -o trustcache.im4p -f rtsc\")\n# sign\nos.system(\"pyimg4 img4 create -p trustcache.im4p -o Ramdisk\u002Ftrustcache.img4 -m vphone.im4m\")\n#8-2. end\n\nos.system(\"sudo hdiutil detach -force SSHRD\")\nos.system(\"sudo hdiutil resize -sectors min ramdisk1.dmg\")\n# sign\nos.system(\"pyimg4 im4p create -i ramdisk1.dmg -o ramdisk1.dmg.im4p -f rdsk\")\nos.system(\"pyimg4 img4 create -p ramdisk1.dmg.im4p -o Ramdisk\u002Framdisk.img4 -m vphone.im4m\")\n```\n\nOnce all the IMG4 images are created, let's load them one by one and boot with the Ramdisk.\n\n- boot_rd.sh\n\n```bash\n#!\u002Fbin\u002Fzsh\nirecovery -f Ramdisk\u002FiBSS.vresearch101.RELEASE.img4\nirecovery -f Ramdisk\u002FiBEC.vresearch101.RELEASE.img4\nirecovery -c go\n\nsleep 1;\nirecovery -f Ramdisk\u002Fsptm.vresearch1.release.img4\nirecovery -c firmware\n\nirecovery -f Ramdisk\u002Ftxm.img4\nirecovery -c firmware\n\nirecovery -f Ramdisk\u002Ftrustcache.img4\nirecovery -c firmware\nirecovery -f Ramdisk\u002Framdisk.img4\nirecovery -c ramdisk\nirecovery -f Ramdisk\u002FDeviceTree.vphone600ap.img4\nirecovery -c devicetree\nirecovery -f Ramdisk\u002Fsep-firmware.vresearch101.RELEASE.img4\nirecovery -c firmware\nirecovery -f Ramdisk\u002Fkrnl.img4\nirecovery -c bootx\n\n```\n\nThen, you will see the Creeper face from Minecraft in the third window from the left, as shown below.\nIf you check the USB menu in the System Information app and see \"iPhone Research...\",\nyou can now access the virtual iPhone shell using [iproxy](https:\u002F\u002Fgithub.com\u002Flibimobiledevice\u002Flibusbmuxd\u002Fblob\u002Fmaster\u002Ftools\u002Fiproxy.c) tool. (`iproxy 2222 22 &`)\n\n![image.png](contents\u002Fimage%204.png)\n\nTo modify the root file system, rename the snapshot.\n\n```python\nssh root@127.0.0.1 -p2222\n#pw: alpine\n\nmount_apfs -o rw \u002Fdev\u002Fdisk1s1 \u002Fmnt1\n\nsnaputil -l \u002Fmnt1\n# (then will output will be printed with hash, result may be differ)\ncom.apple.os.update-8AAB8DBA5C8F1F756928411675F4A892087B04559CFB084B9E400E661ABAD119\n\nsnaputil -n \u003Ccom.apple.os.update-hash> orig-fs \u002Fmnt1\n\numount \u002Fmnt1\n\nexit\n```\n\nDecrypt the AEA file using the [ipsw](https:\u002F\u002Fgithub.com\u002Fblacktop\u002Fipsw) tool to create a dmg file, mount it, and then transfer the files from the Cryptex partition to the virtual machine.\nAlong with the file transfer, specific patches were required. For convenience, I added three specific processes to start on boot: bash, dropbear, and [trollvnc](https:\u002F\u002Fgithub.com\u002FOwnGoalStudio\u002FTrollVNC).\n\nseputil had an issue where it couldn't properly find the gigalocker file, so I patched it to always look for AA.gl. Furthermore, I patched launchd_cache_loader to ensure that the modified \u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist loads correctly.\n\n```python\n...\n ========= INSTALL CRYPTEX(SystemOS, AppOS) =========\n# Grab and Decrypt Cryptex(SystemOS) AEA\nkey = subprocess.check_output(\"ipsw fw aea --key iPhone17,3_26.1_23B85_Restore\u002F043-54303-126.dmg.aea\", shell=True, text=True).strip()\nprint(f\"key: {key}\")\nos.system(f\"aea decrypt -i iPhone17,3_26.1_23B85_Restore\u002F043-54303-126.dmg.aea -o CryptexSystemOS.dmg -key-value '{key}'\")\n\n# Grab Cryptex(AppOS)\nos.system(f\"cp iPhone17,3_26.1_23B85_Restore\u002F043-54062-129.dmg CryptexAppOS.dmg\")\n\n# Mount CryptexSystemOS\nos.system(\"mkdir CryptexSystemOS\")\nos.system(\"sudo hdiutil attach -mountpoint CryptexSystemOS CryptexSystemOS.dmg -owners off\")\n\n# Mount CryptexAppOS\nos.system(\"mkdir CryptexAppOS\")\nos.system(\"sudo hdiutil attach -mountpoint CryptexAppOS CryptexAppOS.dmg -owners off\")\n\n# Prepare\nremote_cmd(\"\u002Fsbin\u002Fmount_apfs -o rw \u002Fdev\u002Fdisk1s1 \u002Fmnt1\")\n\nremote_cmd(\"\u002Fbin\u002Frm -rf \u002Fmnt1\u002FSystem\u002FCryptexes\u002FApp\")\nremote_cmd(\"\u002Fbin\u002Frm -rf \u002Fmnt1\u002FSystem\u002FCryptexes\u002FOS\")\n\nremote_cmd(\"\u002Fbin\u002Fmkdir -p \u002Fmnt1\u002FSystem\u002FCryptexes\u002FApp\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0755 \u002Fmnt1\u002FSystem\u002FCryptexes\u002FApp\")\nremote_cmd(\"\u002Fbin\u002Fmkdir -p \u002Fmnt1\u002FSystem\u002FCryptexes\u002FOS\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0755 \u002Fmnt1\u002FSystem\u002FCryptexes\u002FOS\")\n\n# send Cryptex files to device\nprint(\"Copying cryptexs to vphone! Will take about 3 mintues...\")\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 CryptexSystemOS\u002F. 'root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FCryptexes\u002FOS'\")\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 CryptexAppOS\u002F. 'root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FCryptexes\u002FApp'\")\n\n# Thanks nathan for idea\n# \u002FSystem\u002FLibrary\u002FCaches\u002Fcom.apple.dyld -> \u002FSystem\u002FCryptexes\u002FOS\u002FSystem\u002FLibrary\u002FCaches\u002Fcom.apple.dyld\u002F\nremote_cmd(\"\u002Fbin\u002Fln -sf ..\u002F..\u002F..\u002FSystem\u002FCryptexes\u002FOS\u002FSystem\u002FLibrary\u002FCaches\u002Fcom.apple.dyld \u002Fmnt1\u002FSystem\u002FLibrary\u002FCaches\u002Fcom.apple.dyld\")\n# \u002FSystem\u002FDriverKit\u002FSystem\u002FLibrary\u002Fdyld -> \u002FSystem\u002FCryptexes\u002FOS\u002FSystem\u002FDriverKit\u002FSystem\u002FLibrary\u002Fdyld\nremote_cmd(\"\u002Fbin\u002Fln -sf ..\u002F..\u002F..\u002F..\u002FSystem\u002FCryptexes\u002FOS\u002FSystem\u002FDriverKit\u002FSystem\u002FLibrary\u002Fdyld \u002Fmnt1\u002FSystem\u002FDriverKit\u002FSystem\u002FLibrary\u002Fdyld\")\n\n# ========= PATCH SEPUTIL =========\n# remove if already exist\nos.system(\"rm custom_26.1\u002Fseputil 2>\u002Fdev\u002Fnull\")\nos.system(\"rm custom_26.1\u002Fseputil.bak 2>\u002Fdev\u002Fnull\")\n# backup seputil before patch\nfile_path = \"\u002Fmnt1\u002Fusr\u002Flibexec\u002Fseputil.bak\"\nif not check_remote_file_exists(file_path): \n     print(f\"Created backup {file_path}\")\n     remote_cmd(\"\u002Fbin\u002Fcp \u002Fmnt1\u002Fusr\u002Flibexec\u002Fseputil \u002Fmnt1\u002Fusr\u002Flibexec\u002Fseputil.bak\")\n# grab seputil\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull -P 2222 root@127.0.0.1:\u002Fmnt1\u002Fusr\u002Flibexec\u002Fseputil.bak .\u002Fcustom_26.1\")\nos.system(\"mv custom_26.1\u002Fseputil.bak custom_26.1\u002Fseputil\")\n# patch seputil; prevent error \"seputil: Gigalocker file (\u002Fmnt7\u002FXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.gl) doesn't exist: No such file or directory\"\nfp = open(\"custom_26.1\u002Fseputil\", \"r+b\")\npatch(0x1B3F1, \"AA\")\nfp.close()\n# sign\nos.system(\"tools\u002Fldid_macosx_arm64 -S -M -Ksigncert.p12 -Icom.apple.seputil custom_26.1\u002Fseputil\")\n# send to apply\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 custom_26.1\u002Fseputil 'root@127.0.0.1:\u002Fmnt1\u002Fusr\u002Flibexec\u002Fseputil'\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0755 \u002Fmnt1\u002Fusr\u002Flibexec\u002Fseputil\")\n# clean\nos.system(\"rm custom_26.1\u002Fseputil 2>\u002Fdev\u002Fnull\")\n\n# Change gigalocker filename to AA.gl\nremote_cmd(\"\u002Fsbin\u002Fmount_apfs -o rw \u002Fdev\u002Fdisk1s3 \u002Fmnt3\")\nremote_cmd(\"\u002Fbin\u002Fmv \u002Fmnt3\u002F*.gl \u002Fmnt3\u002FAA.gl\")\n\n... # ========= INSTALL AppleParavirtGPUMetalIOGPUFamily =========\n\n# ========= INSTALL iosbinpack64 =========\n# Send to rootfs\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 jb\u002Fiosbinpack64.tar 'root@127.0.0.1:\u002Fmnt1'\")\n# Unpack \nremote_cmd(\"\u002Fusr\u002Fbin\u002Ftar --preserve-permissions --no-overwrite-dir -xvf \u002Fmnt1\u002Fiosbinpack64.tar  -C \u002Fmnt1\")\nremote_cmd(\"\u002Fbin\u002Frm \u002Fmnt1\u002Fiosbinpack64.tar\")\n# Setup initial dropbear after normal boot\n'''\n\u002Fiosbinpack64\u002Fbin\u002Fmkdir -p \u002Fvar\u002Fdropbear\n\u002Fiosbinpack64\u002Fbin\u002Fcp \u002Fiosbinpack64\u002Fetc\u002Fprofile \u002Fvar\u002Fprofile\n\u002Fiosbinpack64\u002Fbin\u002Fcp \u002Fiosbinpack64\u002Fetc\u002Fmotd \u002Fvar\u002Fmotd\n'''\n\n# ========= PATCH launchd_cache_loader (patch required if modifying \u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist) =========\n# remove if already exist\nos.system(\"rm custom_26.1\u002Flaunchd_cache_loader 2>\u002Fdev\u002Fnull\")\nos.system(\"rm custom_26.1\u002Flaunchd_cache_loader.bak 2>\u002Fdev\u002Fnull\")\n# backup launchd_cache_loader before patch\nfile_path = \"\u002Fmnt1\u002Fusr\u002Flibexec\u002Flaunchd_cache_loader.bak\"\nif not check_remote_file_exists(file_path): \n     print(f\"Created backup {file_path}\")\n     remote_cmd(\"\u002Fbin\u002Fcp \u002Fmnt1\u002Fusr\u002Flibexec\u002Flaunchd_cache_loader \u002Fmnt1\u002Fusr\u002Flibexec\u002Flaunchd_cache_loader.bak\")\n# grab launchd_cache_loader\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull -P 2222 root@127.0.0.1:\u002Fmnt1\u002Fusr\u002Flibexec\u002Flaunchd_cache_loader.bak .\u002Fcustom_26.1\")\nos.system(\"mv custom_26.1\u002Flaunchd_cache_loader.bak custom_26.1\u002Flaunchd_cache_loader\")\n# patch to apply launchd_unsecure_cache=1\nfp = open(\"custom_26.1\u002Flaunchd_cache_loader\", \"r+b\")\npatch(0xB58, 0xd503201f)\nfp.close()\n# sign\nos.system(\"tools\u002Fldid_macosx_arm64 -S -M -Ksigncert.p12 -Icom.apple.launchd_cache_loader custom_26.1\u002Flaunchd_cache_loader\")\n# send to apply\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 custom_26.1\u002Flaunchd_cache_loader 'root@127.0.0.1:\u002Fmnt1\u002Fusr\u002Flibexec\u002Flaunchd_cache_loader'\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0755 \u002Fmnt1\u002Fusr\u002Flibexec\u002Flaunchd_cache_loader\")\n# clean\nos.system(\"rm custom_26.1\u002Flaunchd_cache_loader 2>\u002Fdev\u002Fnull\")\n\n# ========= MAKE RUN bash, dropbear, trollvnc automatically when boot =========\n# Send plist to \u002FSystem\u002FLibrary\u002FLaunchDaemons\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 jb\u002FLaunchDaemons\u002Fbash.plist 'root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FLibrary\u002FLaunchDaemons'\")\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 jb\u002FLaunchDaemons\u002Fdropbear.plist 'root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FLibrary\u002FLaunchDaemons'\")\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 jb\u002FLaunchDaemons\u002Ftrollvnc.plist 'root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FLibrary\u002FLaunchDaemons'\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0644 \u002Fmnt1\u002FSystem\u002FLibrary\u002FLaunchDaemons\u002Fbash.plist\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0644 \u002Fmnt1\u002FSystem\u002FLibrary\u002FLaunchDaemons\u002Fdropbear.plist\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0644 \u002Fmnt1\u002FSystem\u002FLibrary\u002FLaunchDaemons\u002Ftrollvnc.plist\")\n\n# Edit \u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist \n# remove if already exist\nos.system(\"rm custom_26.1\u002Flaunchd.plist 2>\u002Fdev\u002Fnull\")\nos.system(\"rm custom_26.1\u002Flaunchd.plist.bak 2>\u002Fdev\u002Fnull\")\n# backup launchd.plist before patch\nfile_path = \"\u002Fmnt1\u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist.bak\"\nif not check_remote_file_exists(file_path): \n     print(f\"Created backup {file_path}\")\n     remote_cmd(\"\u002Fbin\u002Fcp \u002Fmnt1\u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist \u002Fmnt1\u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist.bak\")\n# grab launchd.plist\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull -P 2222 root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist.bak .\u002Fcustom_26.1\")\nos.system(\"mv custom_26.1\u002Flaunchd.plist.bak custom_26.1\u002Flaunchd.plist\")\n\n# Inject bash, dropbear, trollvnc to launchd.plist\nos.system(\"plutil -convert xml1 custom_26.1\u002Flaunchd.plist\")\n\n# 1. bash\ntarget_file = 'custom_26.1\u002Flaunchd.plist'\nsource_file = 'jb\u002FLaunchDaemons\u002Fbash.plist'\ninsert_key  = '\u002FSystem\u002FLibrary\u002FLaunchDaemons\u002Fbash.plist'\n\nwith open(target_file, 'rb') as ft, open(source_file, 'rb') as fs:\n    target_data = plistlib.load(ft)\n    source_data = plistlib.load(fs)\n\ntarget_data.setdefault('LaunchDaemons', {})[insert_key] = source_data\n\nwith open(target_file, 'wb') as f:\n    plistlib.dump(target_data, f, sort_keys=False)\n\n# 2. dropbear\nsource_file = 'jb\u002FLaunchDaemons\u002Fdropbear.plist'\ninsert_key  = '\u002FSystem\u002FLibrary\u002FLaunchDaemons\u002Fdropbear.plist'\n\nwith open(target_file, 'rb') as ft, open(source_file, 'rb') as fs:\n    target_data = plistlib.load(ft)\n    source_data = plistlib.load(fs)\n\ntarget_data.setdefault('LaunchDaemons', {})[insert_key] = source_data\n\nwith open(target_file, 'wb') as f:\n    plistlib.dump(target_data, f, sort_keys=False)\n\n# 3. trollvnc\nsource_file = 'jb\u002FLaunchDaemons\u002Ftrollvnc.plist'\ninsert_key  = '\u002FSystem\u002FLibrary\u002FLaunchDaemons\u002Ftrollvnc.plist'\n\nwith open(target_file, 'rb') as ft, open(source_file, 'rb') as fs:\n    target_data = plistlib.load(ft)\n    source_data = plistlib.load(fs)\n\ntarget_data.setdefault('LaunchDaemons', {})[insert_key] = source_data\n\nwith open(target_file, 'wb') as f:\n    plistlib.dump(target_data, f, sort_keys=False)\n\n# send to apply\nos.system(\"tools\u002Fsshpass -p 'alpine' scp -q -r -ostricthostkeychecking=false -ouserknownhostsfile=\u002Fdev\u002Fnull -o StrictHostKeyChecking=no -P 2222 custom_26.1\u002Flaunchd.plist 'root@127.0.0.1:\u002Fmnt1\u002FSystem\u002FLibrary\u002Fxpc'\")\nremote_cmd(\"\u002Fbin\u002Fchmod 0644 \u002Fmnt1\u002FSystem\u002FLibrary\u002Fxpc\u002Flaunchd.plist\")\n# clean\nos.system(\"rm custom_26.1\u002Flaunchd.plist 2>\u002Fdev\u002Fnull\")\n# ========= End of MAKE RUN bash, dropbear, trollvnc automatically when boot =========\n\n...\nremote_cmd(\"\u002Fsbin\u002Fhalt\")\n...\n```\n\n# First Boot Attempt\n\nThe boot process should work fine now, but when you try to proceed past the black setup screen, it resprings and won't go any further.\n\n![image.png](contents\u002Fimage%205.png)\n\n![image.png](contents\u002Fimage%206.png)\n\n# Implementing Metal\n\nWhen checking with a custom program called MetalTest, it shows that Metal is not supported.\n\n```python\n#import \u003Cstdio.h>\n#import \u003CMetal\u002FMetal.h>\n#import \u003CFoundation\u002FFoundation.h>\n\nint main(int argc, char *argv[], char *envp[]) {\n    id\u003CMTLDevice> device = MTLCreateSystemDefaultDevice();\n    NSLog(@\"device: %@\", device);\n\n    if (device) {\n        NSLog(@\"Metal Device Create Success: %@\", [device name]);\n    } else {\n        NSLog(@\"Metal Not Supported!\");\n    }\n\n    return 0;\n}\n```\n\n- Running result\n\n```python\n-bash-4.4# .\u002FMetalTest \n2026-02-08 22:49:02.293 MetalTest[633:9434] device: (null)\n2026-02-08 22:49:02.294 MetalTest[633:9434] Metal Not Supported!\n-bash-4.4# sysctl kern.version\nkern.version: Darwin Kernel Version 25.1.0: Thu Oct 23 11:11:48 PDT 2025; root:xnu-12377.42.6~55\u002FRELEASE_ARM64_VRESEARCH1\n```\n\nNormally, the output should have looked like the result below.\n\n```python\nseo@seos-Virtual-Machine Desktop % sysctl kern.version\nkern.version: Darwin Kernel Version 25.0.0: Mon Aug 25 21:17:21 PDT 2025; root:xnu-12377.1.9~3\u002FRELEASE_ARM64_VMAPPLE\nseo@seos-Virtual-Machine Desktop % .\u002FMetalTest        \n2026-02-08 23:16:56.846 MetalTest[682:5810] device: \u003CAppleParavirtDevice: 0x102c48fe0>\n    name = Apple Paravirtual device\n2026-02-08 23:16:56.847 MetalTest[682:5810] Metal Device Create Success: Apple Paravirtual device\nseo@seos-Virtual-Machine Desktop % \n```\n\nChecking with `ioreg -l`, as you can see, the kernel was actually recognizing AppleParavirtGPU.\n\n![image.png](contents\u002Fimage%207.png)\n\nWhen checking on an iPad 7th Gen running iOS 16.6.1, calling the `MTLCreateSystemDefaultDevice` function internally accesses the IOGPU driver through a specific library called `AGXMetalA10`. This `AGXMetalA10` library is located in `\u002FSystem\u002FLibrary\u002FExtensions`.\n\nA thought suddenly crossed my mind here: wouldn't there be GPU\u002FMetal-related libraries used for virtual iPhone as well?\n\n![image.png](contents\u002Fimage%208.png)\n\nChecking that same path in the PCC virtual machine reveals that 7 files exist there.\n\nI took the \u002FSystem\u002FLibrary\u002FExtensions\u002FAppleParavirtGPUMetalIOGPUFamily.bundle used in PCC and placed it directly into the virtual iPhone. (I used the SSH Ramdisk for this.)\n\n![image.png](contents\u002Fimage%209.png)\n\nChecking MetalTest again, the `MTLCreateSystemDefaultDevice` function now works properly.\n\n![image.png](contents\u002Fimage%2010.png)\n\nHowever, because a specific dylib file does not exist in the iPhone 16 model's dsc(dyld shared cache), I needed to separately reverse-engineer and implement it from the dsc in the PCC.\n\n- \u002FSystem\u002FLibrary\u002FExtensions\u002FAppleParavirtGPUMetalIOGPUFamily.bundle\u002FlibAppleParavirtCompilerPluginIOGPUFamily.dylib\n\n![Screenshot 2026-02-25 at 1.19.40 PM.png](contents\u002FScreenshot_2026-02-25_at_1.19.40_PM.png)\n\n![image.png](contents\u002Fimage%2011.png)\n\n# Second Boot Attempt\n\nOnce implemented, you are now greeted by the setup screen with a background.\nSince I couldn't properly implement the home button, I resolved this using a temporary workaround by controlling it via iproxy\u002FVNC.\n\n![image.png](contents\u002Fimage%2012.png)\n\n# Compatibility\n\nIt is only compatible with Apple Silicon Macs, and the devices\u002Fversions confirmed to work are as follows:\n\n- Apple M3, 16GB RAM, Sequoia 15.7.4\n- Apple M1 Pro, 32GB RAM, Tahoe 26.3\n\nI expect it will probably work on any target that supports pccvre.\n\n![Source: [https:\u002F\u002Fsecurity.apple.com\u002Fdocumentation\u002Fprivate-cloud-compute\u002Fvresetup](https:\u002F\u002Fsecurity.apple.com\u002Fdocumentation\u002Fprivate-cloud-compute\u002Fvresetup)](contents\u002Fimage%2013.png)\n\nSource: [https:\u002F\u002Fsecurity.apple.com\u002Fdocumentation\u002Fprivate-cloud-compute\u002Fvresetup](https:\u002F\u002Fsecurity.apple.com\u002Fdocumentation\u002Fprivate-cloud-compute\u002Fvresetup)\n\n## Enabling Touch Interaction on Sequoia\n\nUnlike Tahoe version 26, touch interaction is not possible using only the VZVirtualMachineView object, so it was necessary to override the mouse event functions.\n\n[ScreenSharingVNC.swift](contents\u002FScreenSharingVNC.swift)\n\n### Project SRC\n- https:\u002F\u002Fgithub.com\u002Fwh1te4ever\u002Fsuper-tart-vphone","该项目旨在利用PCC固件中的VPHONE600AP组件构建虚拟iPhone。核心功能包括支持触摸交互、Cryptex、设备激活和Ramdisk启动等，并且实现了Metal加速，使得虚拟iPhone运行流畅。项目采用Swift语言开发，适合安全研究人员和开发者在云端环境中进行iOS系统的测试与研究。",2,"2026-06-11 03:50:36","high_star"]