# How the EXP Firmware Variant Bypasses Anti-VM Detection in vphone-cli

> Discover how the EXP firmware variant bypasses anti-VM detection in vphone-cli by manipulating sysctl OIDs and kernel references. Learn the technical details of this clever technique.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: internals
- Published: 2026-09-10

---

**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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/sources/FirmwarePatcher/Pipeline/FirmwarePipeline.swift) at line 380:

```swift
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`](https://github.com/Lakr233/vphone-cli/blob/main/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:

```bash

# 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:

```swift
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_present` to `kern.Xv_vmm_present` in [`KernelEXPPatchHvVmmRename.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelEXPPatchHvVmmRename.swift), causing standard sysctl queries to fail with `ENOENT`.
- 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 `KernelEXPPatcher` class manages these operations exclusively for `.exp` variant 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`](https://github.com/Lakr233/vphone-cli/blob/main/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`](https://github.com/Lakr233/vphone-cli/blob/main/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`.