How the EXP Firmware Variant Bypasses Anti-VM Detection in vphone-cli
The EXP firmware variant bypasses anti-VM detection by renaming the kern.hv_vmm_present sysctl OID to kern.Xv_vmm_present and selectively mangling kernel-internal references so that Apple services receive a "not found" error and cache a zero value, while permitted kernel callers retain access to the truth.
The EXP variant in the Lakr233/vphone-cli repository extends the standard jailbreak firmware with a sophisticated anti-detection layer that targets Apple's virtualization detection mechanisms. By manipulating the kernel's sysctl namespace and coordinating patches across kernel-space and user-space components, the variant convinces core services that the device is physical hardware rather than a virtual machine, all while preserving VM-specific capabilities like GPU passthrough.
The Core Mechanism: OID Rename and Caller Mangling
The bypass centers on a "black-list-flip" technique applied to the kern.hv_vmm_present sysctl OID, which Apple services query to determine if they are running inside a virtual machine. The EXP patcher performs two coordinated operations: renaming the OID's visible name string and mangling every internal reference to that string within the kernel binary.
According to the source code in sources/FirmwarePatcher/Kernel/EXPPatches/KernelEXPPatchHvVmmRename.swift, the rename changes hv_vmm_present to Xv_vmm_present in the kernel's oid_name cstring. After this modification, queries for kern.hv_vmm_present return ENOENT (not found), causing services to believe no hypervisor is present. Simultaneously, the patcher flips byte 5 of every internal kern.hv_vmm_present token to kern.Xv_vmm_present, ensuring kernel-internal callers like AMFI, the IO Crypto Accelerator, sandbox, and APFS can still locate and query the renamed OID.
Step-by-Step Implementation in the Kernel
Renaming the sysctl OID (Part A)
The first phase of the bypass executes in KernelEXPPatchHvVmmRename.renameOidNameCstring() at lines 90-110 of KernelEXPPatchHvVmmRename.swift. This function locates the OID's name string in the kernel's data section and modifies the character data from "hv_vmm_present" to "Xv_vmm_present". Once renamed, the sysctl framework cannot resolve the original name, effectively hiding the VM's presence from standard API consumers.
Mangling Internal Callers (Part B)
The second phase, implemented in mangleKernelInternalCallers() at lines 55-78 of the same file, ensures the kernel remains functional after the rename. By flipping the fifth byte of every kern.hv_vmm_present cstring token scattered throughout the kernel binary to kern.Xv_vmm_present, the patch redirects legitimate kernel-internal queries to the renamed OID. This preserves critical security and I/O functionality while maintaining the illusion of bare-metal operation for user-space services.
User-Mode and System-Level Patches
complement the kernel modifications, the EXP variant applies several system-level patches to maintain consistency across the software stack.
DSC Dylib Patching
The scripts/patchers/cfw_patch_hv_vmm_dsc.py script mirrors the kernel's mangling logic across all Dynamic Shared Cache (DSC) dylibs, with strategic exceptions for graphics and acceleration libraries. Black-listed dylibs—those excluded from mangling—retain the original kern.hv_vmm_present reference, query the renamed OID, receive ENOENT, and cache a zero value. This causes frameworks like Photo Booth and video codecs to behave as if running on physical hardware while GPU passthrough continues to function through the unmangled libraries.
Watchdogd Adjustment
In scripts/cfw_install_exp.sh at step [EXP-JB-3.5], a targeted two-instruction patch adjusts the watchdogd daemon's internal cache of the sysctl value. This modification aligns the daemon's state with the renamed OID, preventing the service from terminating due to VM detection timeouts and ensuring system stability in EXP environments.
DeviceTree and Build Version Spoofing
The EXP installer performs additional camouflage at step [EXP-JB-6] by rewriting /devicetree.img4 to embed EXP-only identity properties that mask boot-time virtualization signatures. Optionally, at step [EXP-JB-7], the patcher can rewrite SystemVersion.plist's ProductBuildVersion to a user-supplied value when the SPOOF_BUILD environment variable is set, further obscuring the VM environment's provenance.
Code Structure and Entry Points
All EXP-specific patches are orchestrated by the KernelEXPPatcher class, which is instantiated exclusively for the .exp variant in the firmware pipeline. As implemented in sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift at line 380:
if options.variant == .exp {
let patcher = KernelEXPPatcher(data: kernelData, verbose: verbose)
// ...
}
This conditional instantiation ensures that standard JB variants receive only jailbreak patches, while EXP variants receive the additional anti-VM layer through KernelEXPPatcher.swift, which coordinates the OID rename and caller mangling operations.
Practical Usage
To build and deploy the EXP firmware variant with full anti-VM bypass capabilities:
# Build the EXP firmware (includes all EXP patches)
make fw_patch_exp
# Create a VM that uses the EXP variant
vphone-cli vm create myExpVM --variant exp
# Boot the VM with GUI support
make boot vm=myExpVM
After patching, you can verify the bypass behavior programmatically:
import Foundation
// Returns ENOENT (0), indicating "no VM" to standard callers
let vmCheck = sysctlbyname("kern.hv_vmm_present")
print(vmCheck) // → 0
// Returns 1, the true value accessible only to mangled callers
let realCheck = sysctlbyname("kern.Xv_vmm_present")
print(realCheck) // → 1
Summary
- The EXP variant renames
kern.hv_vmm_presenttokern.Xv_vmm_presentinKernelEXPPatchHvVmmRename.swift, causing standard sysctl queries to fail withENOENT. - Internal kernel references are mangled to use the new name, preserving functionality for AMFI, sandbox, and APFS while hiding the VM from user-space services.
- The DSC dylib patcher applies selective mangling so graphics libraries retain VM awareness for hardware acceleration, while other services believe they run on physical hardware.
- Post-installation scripts patch
watchdogd, rewrite the DeviceTree, and optionally spoof build versions to complete the anti-detection profile. - The
KernelEXPPatcherclass manages these operations exclusively for.expvariant firmware builds.
Frequently Asked Questions
How does the EXP variant differ from the standard JB variant?
The JB variant provides basic jailbreak capabilities without anti-VM measures, while the EXP variant is a superset that adds the kern.hv_vmm_present OID rename, DSC patching, and system-level spoofing to mask virtualization. According to the source code, EXP patches are applied only when options.variant == .exp in the firmware pipeline.
Why rename the sysctl instead of just returning zero?
Renaming the OID to Xv_vmm_present and causing ENOENT for the original name is more robust than simply returning zero. Services that query the OID typically cache the "not found" error as a zero value, effectively disabling VM-specific code paths. Meanwhile, the renamed OID preserves the true value (1) for kernel-internal components that must remain VM-aware for security and hardware acceleration purposes.
Which files are excluded from the DSC mangling process?
Graphics and hardware acceleration libraries are explicitly excluded from the DSC mangling performed by cfw_patch_hv_vmm_dsc.py. These black-listed dylibs continue to see the original kern.hv_vmm_present name, query the renamed OID, receive ENOENT, and cache zero—while the GPU passthrough functionality remains operational through libraries that retain the original sysctl access patterns.
Can the build version spoofing be disabled?
Yes, the build version spoofing at step [EXP-JB-7] of cfw_install_exp.sh is opt-in only. It executes only when the SPOOF_BUILD environment variable is set to a specific version string. Without this variable, the installer preserves the original ProductBuildVersion from SystemVersion.plist.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →