Skip to content

v2.8.0 πŸŽ‰

Latest

Choose a tag to compare

@NotRequiem NotRequiem released this 06 Jul 13:01

2.8.0 Release

Additions

  • VMAware is now available in more programming languages. Rust, JS and Ruby are officially supported.

  • Official support for multiple architectures: amd64, arm64, armhf, armel, i386, mips64el, ppc64el, riscv64, s390x.

  • Windows TUI: New CLI design for Windows. You can enable it using the --rich argument.

Windows_TUI
  • VM::TPM: Analyzes measured boot logs exported by the TPM, detecting hardcoded memory bounds of the SEC and PEI execution phases of certain OVMF builds, and flagging physical CPUs not providing a real manufacturer signature or platform GUIDs directly to PCR 0 as suspicious.

  • VM::SINGLE_STEP: Detects whether a hypervisor delays trap flags over exiting instructions. It sets the trap flag via PUSHFQ/POPFQ (or PUSHFD/POPFD in 32-bit mode) and executes a vmexiting instruction. The check expects a single-step exception (EXCEPTION_SINGLE_STEP / #DB) to trigger immediately on the vmexiting instruction. If a hypervisor incorrectly delays the trap flag, execution falls through to an invalid opcode (0xC7 0xB2), triggering an undefined opcode exception (EXCEPTION_ILLEGAL_INSTRUCTION / #UD) instead.

  • VM::EIP_OVERFLOW: Detects whether a hypervisor does not correctly emulate instructions in compatibility mode. This is checked by transitioning to 32-bit compatibility mode using an IRETQ instruction and attempting to execute CPUID placed at the boundary of the 32-bit address space (0xFFFFFFFE). If correctly handled, the instruction pointer wraps to 0x0 and triggers an access violation (EXCEPTION_ACCESS_VIOLATION); incorrect emulation fails to truncate the instruction pointer. For example, if the hypervisor only handles 64 bits, it would be at 0xFFFFFFFE + 2 = 0x100000000.

  • VM::INTERRUPT_SHADOW: Detects if a hypervisor does not properly restore or respect the interruptibility state (interrupt shadow) after a VM-exit. It modifies the trap flag using PUSHF/POPF and blocks debug exceptions for one instruction using MOV SS before executing a vmexit. On bare metal, the single-step exception (EXCEPTION_SINGLE_STEP / #DB) is suppressed during the shadow and only fires afterward, whereas hypervisors like KVM trigger the exception early.

  • VM::SVM_EXCEPTIONS: Detects whether a hypervisor leaks EFER.SVME into guest context via the SVM instruction fault type. It attempts to execute SVM instructions (VMRUN, VMLOAD, VMSAVE, CLGI, INVLPGA) under conditions where SVM capabilities are hidden. When SVM is disabled, these instructions must trigger an undefined opcode exception per the AMD's APM (EXCEPTION_ILLEGAL_INSTRUCTION / #UD). If a General Protection fault exception occurs when Hyper-V or other legitimate Windows virtualization components are not present, it indicates some other privileged component (a hypervisor) enabled SVM.

  • VM::BOOT_LOGO and VM::DISK_SERIAL support for Linux.

  • VM::CGROUP: Detection for cgroup paths in /proc/self/cgroup.

  • HYPER_X: Checks for whether a hypervisor is nested within a Hyper-V partition. Checks for Hyper-V enlightenments on guest partitions, not only on root partitions.

  • VM::EXPERIMENTAL and --experimental CLI argument. Disables execution of techniques marked as experimental/untested.

Note

For Intel users, CPU-based techniques will need a patch in their respective hypervisors in order to bypass.
For AMD users, most of the detections can be passed by disabling the CPUID interception bit.

Improvements

  • VM::TIMER: Accuracy was improved over 517% after measuring billions of runs in more than 4000 machines.

    For Intel: All the bypasses explained in the 2.7.0 release were detected.

    • VMAware is now immune to interrupt-based pausing, meaning it's impossible to fake a result by trying to spoof any hardware clock or pausing the vCPU where the detection code runs. This is done by implementing hardware-based ASLR and compile-time based entropy without using exiting instructions like RDRAND/RDSEED in order to make impossible to predict the exact moment where VMAware is measuring its reference instruction, and explictly detect pauses by implementing a communication protocol between all the threads timing vmexit overhead.

    • Bypassing by only using one hypervisor (having less than 2.5 threshold) is now considered impossible without attacking the detector code itself, after several improvements in the request-for-ownership latency between the shared cache state of all threads.

    • Detections for nested virtualization were slightly improved.

    • Bypassing on Intel will only be possible on modern hardware using two hypervisors at once, with the following configuration:

      • L1 being a legitimate version of Hyper-V.
      • L0 being a hypervisor configured with:
        • Static CPUID chaching.
        • Security mitigations off to reduce latency.
        • MBEC exposed to reduce amount of vmexits.
        • Not forwarding/reflecting CPUID to L1.

      Therefore, in a nested setup with Hyper-V and KVM, the bypass path becomes:
      CPUID exit from guest -> L0 (KVM with fast CPUID handlers) -> return cached data to L2 .

    For AMD: Accuracy was improved, but bypass detections were not.

    • VMAware now forces every stealthy SVM hypervisor to intercept #GP in order to bypass some techniques (like VM::SVM_EXCEPTIONS), or to run a Hyper-V nested setup.
    • I've decided to not ship timing checks for AMD, as the overhead difference between a #GP exception in baremetal and the heaviest KVM emulation path when handling #GP is not enough to be flagged in real-world scenarios from user-mode.
  • VM::is_hardened(): Improved hardened environment detection accuracy.

  • VM::DBVM: Stronger detections for Dark Byte's VM: Dr6 and Dr7 states, and ICEBP exception probing.

  • VM::HYPERVISOR_HOOK: Stronger detections for EPT/NPT hooking via race-conditions against hypervisors, by overwritting virtual memory pages that may be hooked to intercept hardware breakpoints.

  • VM::PCI_DEVICES: Added checks for PCI Subsystem IDs.

  • VM::ACPI_SIGNATURE: Now queries all ACPI nodes instead of display device paths only. Added more detections:

    • Synthetic QEMU ACPI devices.
    • Virtual DRAM controller nodes.
    • Impossible AMD-to-Intel vendor mappings in PCI slots.
  • VM::FIRMWARE: Added more detections:

    • QEMU DBUG method and DBGB field definitions.
    • DRAC fingerprint in System Board PNPID.
    • QEMU SMI Resources reservation string.
    • QEMU CPU Hotplug.
    • QEMU PCI Hotplug.
  • VM::CLOCK: Improved PIT system timer presence detection.

  • VM::AZURE: Improved execution performance.

  • VM::KVM_INTERCEPTION: Improved stability by flushing instruction cache before attempting to check whether KVM attempts to patch a mismatched hypercall instruction.

  • CLI modularization into several C++ source and header files.

Fixes

  • ARM32/ARM64 support for every platform.
  • VM::BOOT_LOGO false flagging some legitimate MSI boards due to an update in VirtualBox repository.
  • VM::TIMER false flagging some AMD CPUs due to a delta mismatch between XSS states, falsely believing a hypervisor with CPUID interception disabled was present.
  • Duplicated brands in conclusion output.

Removals

  • VM::EDID: Not reliable enough for VM detection.
  • VM::DEVICE_STRING: Not reliable enough for VM detection.
  • VM::NSJAIL_PID: Decayed to general container brand.
  • Firmware detections for FWCF. False flags on some OEMs, like on HP ProBook 445 G8 Notebook.

Note

Techniques are not removed because they're "bypassed". Techniques are removed if they're unreliable for VM detection. It is highly recommended to test the concealment of your VM using only the latest version of VMAware.

Secondary Changes

  • Added automatic memory leak detection for Debug builds.
  • Added benchmark information about detections in all CLIs.
  • Added library compatibility with older Windows 10 SDK versions.
  • Improved presence detection for early engineering samples of AMD K5 processors.
  • Improved system model and manufacturer fetching, using multiple firmware, CPU and registry sources.
  • Improved overall security and robustness of the code against unexpected edge-cases.
  • Improved overall code readibility using automatic tools like Clang-tidy.
  • Improved SHA256 debug outputs.
  • Improved brand conclusion outputs.
  • Improved JSON report generation.
  • Improved CMake installation across multiple platforms.
  • Made each thread running VM::run_all() have its own independent copy.
  • Programmed 60 automatic GitHub CI/CD actions so that users can see real-time behavior and compilation in all platforms, under all configurations.
  • Reordered techniques in CLI by priority such as VM::TIMER (which runs at the end). Modified score of several techniques to improve accuracy.
  • Deprecated old brands namespace.
  • Updated Intel i9 CPU database.
  • Updated all guidelines and translations, including contribution, security and documentation information.
  • Removed linkage of several libraries, improving compilation compatibility and speed.
  • Rewritten most of the library in sneaky_case for consistent notation.

Ongoing Research

Since I'm on vacation for a few months, I now have more free time to work on the project, so new versions of the library will be released more frequently.

Currently, I'm focusing on the following for the next 2.9.0 and 3.0.0 releases:

TPM:

  • Software TPMs can be detected simply because they will never posses a private EK chained to a valid certification authority. Someone can dump a legitimate public EK certificate and public key from a physical motherboard, but they will never be able to leak a private EK (unless there's some heavy vulnerability in some TPM/CA) or brute-force it (unless you got a quantum computer). Therefore, even a user-mode app can do a proof-of-possesion challenge. The idea is to simulate the TPM2_MakeCredential protocol in VMAware:

    • Extract the EKPub from the EK certificate structure (spoofed by the TPM)
    • Generate a 32-byte cryptographically secure random nonce (the actual challenge), without using instructions that can be intercepted by hypervisors.
    • Generate a 32-byte random ephemeral seed (used to bootstrap symmetric encryption).
    • Perform RSA-OAEP encryption in the ephemeral seed using the spoofed EKPub as the standard IDENTITY label.
    • Do KDFa key derivation to derive a 128-bit AES symmetric key (STORAGE) and a 256-bit HMAC key ((INTEGRITY).
    • The random nonce challenge is encrypted with the derived STORAGE key using AES-128-CFB.
    • Calculate an HMAC-SHA256 signature over the encrypted nonce and the AIK name.
    • Package everything into TPM2B_ID_OBJECT, then VMAware issues the command to the TPM.
    • The physical TPM receives the command. Because the seed was encrypted with the EK public key, the TPM must utilize its private EK inside the hardware boundary to decrypt the seed. Since the swtpm/vTPM will never have the private EK, any spoofing attempt is detected, because it doesn't know how to decrypt the activation blob correctly.
  • If you passthrough your physical TPM, since PCRs can't be overwritten but extended, they will also contain the PCRs of the host, not the ones from your VM only. After reconstructing the TCG logs from the TPM itself, and comparing it to the first PCRs, you will always detect a mismatch. The TPM 2.0 specification also provides ways to quote it and receive a signed response using an attestation identity key, which prevents spoofing.

Many would say TPMs are the kind of hardware devices specifically manufactured to detect these kind of things, and it will the new meta for the next releases of VMAware.

All the detections described here are already working and being tested in https://github.com/NotRequiem/swtpm-detector

DSDT:

More aggressive checks will be added. Some DSDT checks are hard to patch because the DSDT is executable ACPI bytecode that the guest OS interprets at boot. It's becoming easier to find detections that break machines entirely after bypassers try to modify a DSDT signature that it's revealing the presence of their VM. It's not the first time a "safe-looking" edit can cause missing devices, failed boot, broken power management, or VM instability in general. Complex heuristics on this ACPI table are the new target for firmware checks.

Nested virtualization:

To bypass some hypervisor detections, and since many anticheats require HVCI at some point, it's starting to be a must. Althought many techniques of VMAware can detect nested virtualization indirectly, there's only one weak, specific check for this case, which relies only on documented CPUID leaves. Therefore, ongoing research is focusing on looking for architectural, hard-to-spoof mismatches between a host running Hyper-V only, and a VM running inside Hyper-V + another L0 hypervisor.

VirusTotal Results and Executables

https://www.virustotal.com/gui/file/2255930e7b7fc60795bd68baaaecd68798aabb665123911841b3abaef857d290?nocache=1

All the binaries were generated in GitHub's CI/CD purely from the source code here.

Contact

For any inquiries, contact us on Discord at shenzken, or email us at vmaware.support@gmail.com.