# How VMAware Detects ARM-Based Virtual Machines: Techniques and Implementation

> Discover how VMAware detects ARM-based virtual machines using Rosetta 2, CPUID inspection, and brand-string matching for hypervisors like UTM and BareVisor. Learn the implementation details.

- Repository: [Louis/vmaware](https://github.com/kernelwernel/vmaware)
- Tags: deep-dive
- Published: 2026-03-05

---

**VMAware detects ARM-based virtual machines by combining Windows translator detection for Rosetta 2, CPUID hypervisor leaf inspection for Apple Silicon, and brand-string matching for hypervisors like UTM and BareVisor.**

VMAware is an open-source C++ library designed to identify virtualized environments across multiple processor architectures. Understanding how to detect ARM-based virtual machines is essential for security research, malware analysis, and system administration on Apple Silicon and ARM64 platforms. The library implements several architecture-specific techniques in [`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp) that target the unique characteristics of ARM virtualization.

## Detecting ARM Translation Layers (Rosetta 2)

ARM-based VMs often run x86 code through translation layers, particularly on Apple Silicon. VMAware provides specific mechanisms to identify when a process is executing under such translation.

### Windows Translator Detection via IsWow64Process2

On Windows ARM64 systems, VMAware detects Rosetta 2-style translation by querying the operating system for process architecture mismatches. In [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp) at lines 3699–3775, the `VM::is_running_under_translator()` function calls `IsWow64Process2` (with a fallback to `GetProcessInformation`) to compare the process machine type against the native host architecture.

If the function detects that a 64-bit x86 process (`IMAGE_FILE_MACHINE_AMD64` or `IMAGE_FILE_MACHINE_I386`) is executing on an ARM64 host (`IMAGE_FILE_MACHINE_ARM64`), it returns **true**. This indicates the process is running under the Windows translation layer, analogous to Rosetta 2 on macOS.

```cpp
// Detect if we are running under Rosetta 2 (ARM64 host, x86 process)
bool underRosetta = VM::is_running_under_translator();   // true on an x86 binary executed on Apple Silicon

```

## CPUID-Based Detection for Apple Silicon

ARM processors that support virtualization extensions expose hypervisor information through CPUID leaves. VMAware inspects these leaves to identify specific ARM hypervisors.

### Apple Virtualization Framework (Apple VZ) Detection

VMAware identifies Apple's native virtualization framework by querying the CPUID hypervisor leaf. In [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp) around lines 3699–3735, the `cpu::cpu_manufacturer` function checks for vendor strings including **"VirtualApple"** or **"apple virtualization"**. When found, the library invokes `core::add(brand_enum::APPLE_VZ)` to register the detection.

The brand mapping table at line 6260 in [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp) explicitly maps the string `"apple virtualization"` to the `APPLE_VZ` brand enum, ensuring consistent identification across detection methods.

### VM-ID Leaf Inspection

For ARM CPUs exposing the hypervisor CPUID leaf (0x40000000–0x40000100), VMAware employs `cpu::vmid_template()` to read the vendor signature. At lines 4770–4785 in [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp), the `vmid()` function iterates through these leaves and compares returned strings against an internal map containing ARM-specific identifiers like `"apple virtualization"`.

This technique catches hypervisors that expose standardized CPUID signatures on ARM64, including experimental and custom virtualization solutions.

## Brand String Matching for ARM Hypervisors

Beyond CPUID inspection, VMAware performs string analysis on CPU brand identifiers to catch ARM-specific virtualization platforms.

The generic `cpu_brand()` routine, implemented at lines 4945–5025 in [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp), scans processor brand strings for identifiers including **"qemu"**, **"kvm"**, **"vbox"**, **"bhyve"**, **"parallels"**, **"vmware"**, and **"apple virtualization"**. This approach enables detection of ARM hypervisors that populate the CPU brand string with their identifiers, even when standard CPUID leaves provide ambiguous results.

### UTM and BareVisor Detection

VMAware specifically targets two ARM-focused hypervisors through brand aggregation:

- **UTM**: Detected by recognizing the Apple VZ hypervisor foundation (via CPUID) and confirming native ARM64 execution. The [`cli.cpp`](https://github.com/kernelwernel/vmaware/blob/main/cli.cpp) file at line 653 documents UTM as a supported brand that leverages the Apple Hypervisor framework on Apple Silicon.

- **BareVisor**: This lightweight hypervisor supports both x86 and ARM architectures. VMAware matches its vendor string `"Barevisor!"` through the generic `vmid_template()` function, registering the `BAREVISOR` brand as documented in [`cli.cpp`](https://github.com/kernelwernel/vmaware/blob/main/cli.cpp) at line 640.

## The Detection Aggregation Pipeline

VMAware combines ARM-specific checks with generic detection through a unified scoring system. When `VM::detect()` is invoked, the library executes the following pipeline:

1. **Argument parsing** builds a bit-set of enabled techniques based on configuration flags.
2. **Technique execution** runs each selected detection method, including ARM-specific translator checks and CPUID inspections.
3. **Brand scoring** allows techniques to call `core::add(brand_enum)` directly, incrementing scores for matching hypervisors like `APPLE_VZ`, `UTM`, or `BAREVISOR`.
4. **Result determination** selects the brand with the highest score via `VM::brand()`.
5. **Memoization** caches detection results to avoid re-running expensive ARM-specific checks on subsequent calls.

This architecture treats ARM hypervisor strings identically to x86 ones, enabling seamless cross-platform detection.

```cpp
// Detect any ARM-based VM (Apple VZ, UTM, BareVisor, etc.)
bool isArmVm = VM::detect();   // runs all enabled techniques; returns true if any ARM VM is found

// Retrieve the detected brand name (e.g. "Apple VZ")
std::string brand = VM::brand();   // "Apple VZ", "UTM", "Barevisor", …

```

## Summary

- **VMAware detects ARM-based virtual machines** through Windows translator detection (`IsWow64Process2`), CPUID hypervisor leaf inspection (0x40000000–0x40000100), and brand-string matching.
- **Rosetta 2 detection** identifies x86 processes running on ARM64 hosts by comparing `nativeMachine` against `IMAGE_FILE_MACHINE_ARM64` in [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp) lines 3699–3775.
- **Apple Silicon support** recognizes "VirtualApple" and "apple virtualization" vendor strings via `cpu::vmid_template()` and `cpu_brand()` functions.
- **ARM hypervisor coverage** includes UTM (using Apple VZ framework), BareVisor, and standard hypervisors like QEMU and KVM through unified brand scoring in `core::add()`.
- **Cross-platform consistency** allows ARM detection techniques to integrate seamlessly with existing x86 VM detection logic.

## Frequently Asked Questions

### How does VMAware detect Rosetta 2 translation on Windows ARM devices?

VMAware detects Rosetta 2-style translation by calling `IsWow64Process2` (or `GetProcessInformation` as a fallback) to check if the current process architecture differs from the native host architecture. If the system reports `IMAGE_FILE_MACHINE_ARM64` as the native machine while the process runs as AMD64 or I386, `VM::is_running_under_translator()` returns true, indicating execution under the Windows x86-on-ARM translation layer.

### Can VMAware detect UTM virtual machines on Apple Silicon Macs?

Yes, VMAware detects UTM by first identifying the underlying Apple Virtualization Framework (Apple VZ) through CPUID leaf inspection for the "apple virtualization" vendor string, then confirming the specific UTM brand through the detection pipeline. The library maps these identifiers to the `UTM` brand enum in its scoring system, as documented in [`src/cli.cpp`](https://github.com/kernelwernel/vmaware/blob/main/src/cli.cpp) at line 653.

### What CPUID leaves does VMAware check for ARM hypervisor detection?

VMAware checks hypervisor CPUID leaves 0x40000000 through 0x40000100 using the `cpu::vmid_template()` function implemented at lines 4770–4785 in [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp). These leaves contain vendor-specific signatures that reveal the presence of hypervisors like Apple VZ, BareVisor, and other ARM64 virtualization platforms.

### Does VMAware support BareVisor detection on ARM platforms?

Yes, BareVisor is supported on both x86 and ARM architectures. VMAware detects it by matching the vendor string `"Barevisor!"` through the standard `vmid_template()` CPUID inspection routine, then registering the `BAREVISOR` brand via the internal scoring mechanism. This detection works identically across architectures, as documented in [`src/cli.cpp`](https://github.com/kernelwernel/vmaware/blob/main/src/cli.cpp) at line 640.