Repository navigation
v2.8.1 π
2.8.1 Release
Additions
-
Migrated all of the library to static segment allocation in
.text, while being compliant with DEP, CFG, and any compiler optimization. This means that VMAware will allocate stubs in the binary itself rather than in page-aligned memory, increasing performance by eliminating the need to allocate/deallocate, change page protections, or flush the I-cache and being more anti-cheat friendly. -
VM::TIMER: Added new memory latency check to detect nested virtualization.- Now VMAware, from CPL3, is able to issue an unconditional #VMEXIT on any CPU when Hyper-V is running, even if all userland instruction and exception interception bit controls of the L0's VMCB/VMCS are cleared by an attacker. This is done by using a clever trick; jumping to 16-bit real address mode from user-mode (yes, I'm not drunk) by asking the hypervisor to set up a guest virtual processor and modifying CPU registers, effectively disabling paging, and architecturally making hard #PFs on the first-level address translation impossible. Any subsequent unmapped GPA access always triggers a nested page fault per Intel's SDM and AMD's APM because of the read being in the second-level address translation.
Specifically, I:
-
Set
dsSeg.Baseto 0; the physical address (GPA) it attempts to access isDS.Base + 0x3000. -
Initialize
const u8 code[] = { 0xA0, 0x00, 0x30 }. Because the CS descriptor specifies a 16-bit default size, the processor decodes0xA0asMOV AL, [0x3000]. -
Set
cs_seg.Attributes = 0x9B, translating to SegmentType = 0xB (Execute/Read, accessed code segment. NonSystemSegment = 1, DescriptorPrivilegeLevel = 0 (DPL matches real mode CPL of 0), and Present = 1). -
Set
ds_seg.Attributes = 0x93, which translates to SegmentType = 0x3 (Read/Write, accessed data segment). -
Set
values[0].Reg64 = 0x60000010. InCR0, Bit 0 (PE - Protection Enable) is set to 0 and Bit 31 (PG - Paging) too. This makes VMAware's guest VP L2 run in real-address mode. -
Since GPA
0x3000is outside our mapped range (0 to 0x2000), the CPU triggers a GPA fault because it belongs to the second-level address translation. -
The WHP environment ensures EPT violations cannot be translated as a
#VEon Intel. This type of VMEXIT (npf) is the only "unconditional" VMEXIT that can be reached from L2 CPL3 on both AMD and Intel at the same time when instruction intercepts for user-mode are disabled (on SVM) and exception bitmaps are fully cleared (or only respecting L1's bitmap, which in the case of Hyper-V, is#MC,#ACand#DB).
New timing checks to detect nested virtualization will focus on exception delivery of #AC and #DB due to the aforementioned exception bitmaps (determined by dumping VMCB/VMCS structures across several systems running HVCI). Although #NPFs can in fact reveal nested virtualization because of the severe extra page table walking cost, they are not normally reflected as a nested #VMEXIT to L1 (for example, when KVM's
TDPMMU is active). The actual hardware EPT/NPT violation is handled entirely in L0, and only when the nested MMU is walking page tables and detects a missingEPT12entry, the reflection is invoked. - Now VMAware, from CPL3, is able to issue an unconditional #VMEXIT on any CPU when Hyper-V is running, even if all userland instruction and exception interception bit controls of the L0's VMCB/VMCS are cleared by an attacker. This is done by using a clever trick; jumping to 16-bit real address mode from user-mode (yes, I'm not drunk) by asking the hypervisor to set up a guest virtual processor and modifying CPU registers, effectively disabling paging, and architecturally making hard #PFs on the first-level address translation impossible. Any subsequent unmapped GPA access always triggers a nested page fault per Intel's SDM and AMD's APM because of the read being in the second-level address translation.
-
hyper_x(): Improved checks against hypervisors pretending to be Hyper-V on Windows 11.-
Now VMAware verifies Hyper-V by scanning for kernel tags allocated by drivers. Specifically, after reverse-engineering the HAL path
HalpInitializeErrSrc->HalpInitializeMce->HalpMceInit->HalpHvInitMcaPcrContext, I found that the routine initializes machine-check/WHEA state in a hypervisor-aware context, allocating theHalHpool. -
Verifies the measured boot logs exported by the TPM to check if official Hyper-V components and drivers were actually measured.
-
Any other checks, like checking presence of Vid.sys or VMBus.sys drivers and cryptographically verify them, checking Hyper-V performance counters, issuing WHP calls, checking Hyper-V's WMI namespace presence, checking presence of Hyper-V specific processes and services, etcetera, ended in false flags (falsely detecting Hyper-V was not running when it was) across Windows 10 to 11 25H2 Pro versions.
-
-
VM::TPM:-
Added TPM pass-through detections by checking for mismatches between PCRs 1β7 mathematically reconstructed from TCG logs and the actual hardware PCR values. PCR0 is excluded, as some firmware manufacturers place PCR0-related information into the event log without extending it.
-
Added libtpm detection.
-
Complete research of virtual TPM detections has been finished. For a full set of TPM detections (software TPM, TPM passthrough, TPM resetting/flashing, and EDS/EK/PCR spoofing), refer to https://github.com/NotRequiem/swtpm-detector, officially created by VMAware developers. This detector strongly relies on the fact that a pure software TPM will never possess a manufacturer-provisioned private EK whose corresponding certificate chains to a genuine certification authority. It:
-
Ensures that every certificate in the validation chain is temporally valid.
-
Confirms that intermediate and root issuers are legitimate CAs authorized to sign certificates.
-
Interrogates the certificate chain status to confirm no key has been revoked.
-
Restricts trusted root anchors to those present in Microsoftβs official trust package.
-
Sanitizes external certificate downloads by strictly restricting them to validated manufacturer endpoints (Intel, AMD, or Microsoft).
-
Cryptographically verifies the signature validation of every certificate against its issuing authority.
-
Ensures that the leaf certificate contains the mandatory TCG Endorsement Key EKU OID (
2.23.133.8.1). -
Compares the public key extracted from the physical TPM directly with the public key on the certificate (supporting both RSA and ECC).
-
Locates the persistent EK handle, generates a transient Attestation Key, and issues a cryptographic challenge (
MakeCredentialandActivateCredentialover a policy session) to force the TPM to prove it owns the matching private key. -
Re-computes PCR registers
0β7by replaying the boot TCG log measurements and compares them to actual hardware PCR values.
-
-
-
VM::FIRMWARE: Improved detections for both Windows and Linux systems. All those added detections, except the first two, are experimental. You can disable experimental detections with the--experimental/VM::EXPERIMENTALflag.-
Added firmware checks for virtual IOAPIC and IGD conflicts via DMA Remapping table validation:
- Flags virtual IOAPIC mapped to invalid Bus 0xFF in DMAR DRHD scopes.
- Flags PCI Bridge mapped to Bus 0, Device 2, Function 0 in DMAR scopes (Intel topology conflict reserved for IGD).
-
Added detections for QEMU-specific Interrupt Source Overrides in MADT (Subtable type 0x02):
- QEMU's default PCI IRQ mask emits identity-mapped ISOs for IRQs 5, 9, 10, and 11 with active-high, level-triggered semantics. For the ISA bus, conforming polarity (0) and explicit active-high polarity (1) are equivalent, so VMAware checks for flags
0x000Cand0x000D, as they represent the same interrupt.
- QEMU's default PCI IRQ mask emits identity-mapped ISOs for IRQs 5, 9, 10, and 11 with active-high, level-triggered semantics. For the ISA bus, conforming polarity (0) and explicit active-high polarity (1) are equivalent, so VMAware checks for flags
-
Added extra AML bytecode inspection and resource declaration checks:
- 128-element
PRTPandPRTAIRQ routing table definitions. - Dynamic HPET MMIO base (
0xFED00000) and counter threshold checks (0x05F5E100). - Flat processor topology (
PR00,PR01,PR02) lacking ACPI power-management methods (_PSS,_CST,_CPC). - Synthetic CPU/PCI hotplug I/O port assignments (
0x0CD8,0xAFE0,0xAE00). - Sequential PIRQ routing rotation names (
LNKE-LNKH,GSIE-GSIH). - Motherboard resources allocated via generic
PNP0A06container onGPERvirtual device.
- 128-element
-
-
VM::DISK: Added detections for emulated drives.- Checks for Virtual OACS signatures found in emulated NVMe disks.
- Check for impossible (impossible being "not found in bare metal") synthetic LBA structure with metadata options found in QEMU's emulated disk.
-
VM::CPU_HEURISTIC: Added AVX/AVX2/AVX512 consistency checks with reported CPU capabilities. -
VM::DRIVERS: Added detections for new Looking Glass (LGIddc) driver. -
Better detections for binary translators, detecting now x86_64 and x86_32 emulation of both ARM32 and ARM64 instructions.
Improvements
VM::TIMER-
Execution speed is now 50x faster.
-
Accuraccy was improved by increasing the resolution of the context-switch latency clock by 4096x times. This means that you will see higher values on VMM and nVMM debugs.
-
Better math matrix for core selection, prioritizing:
- P-cores private L2 caches over E-cores.
- Cores within the same NUMA node and same L3 cache slice/CCD domain.
- Detection and rejection of candidate cores that share an L2 cache with the counter thread but reside on different physical cores (targeting and resolving Intel E-core cluster L2 controller bottlenecks).
- Cores with matching efficiency classes to align power and frequency (DVFS) domains.
- Minor index-distance penalty to select the closest physical neighbor on the silicon layout/ring bus stop.
-
Increased number of multi-state independent trials (from 3 to 5) to be more robust against legitimate interrupts.
-
Due to the new statistical engine, a high number of VMEXITs is no longer necessary, and were reduced from a minimum of 90000 to a minimum of 2600.
-
Timing thresholds were relaxed. This means that:
- You may experience less than 1.0 ratio in bare metal environments.
- Optimized Intel hypervisors have a greater chance of bypassing than on VMAware 2.8.0.
-
Note
Tracked unusual activity in the downloads of VMAware 2.6.0. I assume that it's because this was the last version containing a TSC check.
Testing the TSC check is nonsense, because of several reasons:
- If you bypass latest VMAware, it means that your environment do not have enough VMEXIT latency to be safely classified as an hypervisor, so you automatically bypass TSC checks too. VMAware is the only open-source tool that truly forces you to eliminate latency instead of hiding it.
- Hiding latency by intercepting instructions and offsetting TSC is not a true bypass, and leaves multiple detection vectors.
-
VM::EIP_OVERFLOW: New compatibility on systems where theWOW64subsystem is uninstalled. -
VM::CPU_BRAND: Improved performance in string lookups. -
VM::DLL: Improved performance by avoiding ASCII-to-wide conversions in array lookups. -
VM::THREAD_MISMATCH:- Made CPU database hash computation entirely constexpr.
- Improved readability by using a new hash struct, and improved general performance.
- Improved debugs for CPU manufacturer and brand.
-
VM::WINE: Added back wine_get_unix_file_name export check (I don't even remember why I removed it lol) and improved support for Windows 8. -
VM::MSR: Now it also probes proper #GP exception behavior with writes to unknown MSR indexes (instead of reads only). Performance was slightly improved by callingRtlAddVectoredExceptionHandlerdirectly. -
Better detections for Docker on Linux, as before techniques like
VM::DOCKERENVwere failing to raise the score enough to confidently detect a VM.
Fixes
-
Errata in documentation, like in
VM::typereturn type and other public APIs. -
VM::TIMERfrom freezing infinitely. Fixed a bug where very old Clang compilers would issue an access violation when executing the required inline assembly. -
VM::DEVICESfrom querying historical registry. It will not act anymore as a digital forensic check but query live devices. -
VM::TPMnull payload check false flag. -
VM::ACPI_SIGNATURE#ACPI(S QEMU pattern false flag. -
hyper_xfalsely detecting spoofed Hyper-V state on Windows 10 due to the absence of required services. -
VM::CPU_HEURISTICfalsely detecting spoofed RDRAND capabilities. -
is_x86_process_on_armnot correctly detecting binary translators when the CPU is running on compatibility mode. -
VM::INTERRUPT_SHADOWandVM::EIP_OVERFLOWcompatibility for ARM. -
VM::THREAD_MISMATCHfalse flagging SMT-disabled CPUs, as it's impossible for user-mode to know when SMT is "supported but disabled" versus "non existent" unless you maintain track of every CPU model. Now VMAware is able to recognize both states. -
Clang's stupid static analyzer false flags when trying to derefence a memory address like
8* execution_target = reinterpret_cast<u8*>(boundary_base) + 0xFFFEULL;. -
VM::AUDIOquerying keys instead of subkeys.VM::AUDIOnot redirecting access to 64-bit registry rather than theWow6432Nodepath. -
VM::TIMERfalsely reporting artificialIPIdelivery. -
VM::DBVM: false flagging "hardware debug registers were not correctly restored" under ARM CPUs.
Removals
-
VM::VMWARE_BACKDOOR: Due to risk of not being MIT-compliant. -
VM::IVSHMEM: Merged into newVM::DRIVERStechnique. -
VM::DISK_SERIAL: Merged into newVM::DRIVERStechnique. -
VM::TPM: The original 2.8.0 code it's in a new function calledVM::MEASURED_BOOT, and new code was added toVM::TPM. -
VM::HYPERVISOR_QUERY: The Windows kernel issues the CPUID instruction as the only source to return hypervisor identification to user-mode, so it's useless. -
VM::CUCKOO_DIR: Merged into newVM::CUCKOOtechnique. -
VM::CUCKOO_PIPE: Merged into newVM::CUCKOOtechnique. -
VM::HYPERV_NESTED: Logic is now handled directly inhyper_x(). -
IDT base check in
hyper_x. When Hyper-V is enabled, executingSIDTraises a #GP exception, that is later reinjected into the kernel's IDT handler (if no Hyper-V, then UMIP makes the exception be routed directly to the IDT by the CPU). Eventually,KiPreprocessFaultis reached, and callsKiOpDecode, the kernel decodes the instruction with helpers such asKiOpTwoByteTable, with routes the exception chain to to finally callKiOp_SGDTSIDTin this case, returningKiOpIdtrwith a value of 0x0F800000010000FFF (what VMAware originally checked for). As it's impossible for a hypervisor to route an exception to L2 user-mode, this Windows handler will always be reached even in spoofed hypervisors pretending to be Hyper-V, unless the exception is completely swallowed. This behavior is also the reason why protecting a__sidtintrinsic with VEH, SEH, or exception filters is normally not needed on modern Windows. -
Removed BSD-licensed techniques to make VMAware fully MIT-licensed in vcpkg again.
-
Deprecated
VM::is_hardened(). This does not mean that VMAware is now less robust against hardened environments. Hardened VMs can still be detected by usingVM::detect().VM::is_hardened()will be fully removed on the next release.
Secondary Changes
-
Added a lot of extra static assertion checks to ensure robust compilation.
-
Added Russian translation.
-
Added extra library linking to support non-updated Windows SDKs.
-
Added automatic compatibility with older Windows versions (7 and 8) without needing to define a compile target.
IsWow64Process2andIsNativeVhdBootwill not result in missing procedure entry points on imported modules. -
Added support for compiler pointer aliasing presence hints.
-
Added support for hardware prefetching.
-
Added support for cross-compiler disable of indirect call protections.
-
Added support for cross-compiler assume, likely and unlikely hints.
-
Added support for cross-compiler and C++11 compliant deprecation warnings.
-
Added support for cross-compiler
__vectorcallcalling convention. -
Added new
memorystruct with support to execute calls while bypassing CFG. -
Replaced every LoadLibraryA call with LoadLibraryExW call for both security (
LOAD_LIBRARY_SEARCH_SYSTEM32) and performance (avoiding wide string conversions). -
Redesigned entire core with performance in mind, removing unneeded atomic locks, conditional logics, heap accesses and adding stack-based removal of memory shifts in downstream elements.
-
Updated memoize tests in GitHub workflows.
-
Updated FAQ with new support and general documentation.
-
Updated CPU leaf struct to replace every magic value in
cpuidcalls, improving readability. -
Inlined calls to
VM::brand_multiplefor performance. -
Improved
VM::generate_defaultbitset logic for performance. -
Improved constexpr-isation of core and utility functions.
-
Improved overall security against memory vulnerabilities and maliciously crafted responses by drivers/hypervisors.
-
Rewrote line comments with C-style block code comments for readability, changing over 1000 comments.
-
Rewrote CLI output of "GPU capabilities" to "virtual GPU" for clarity. Rewrote "baremetal" to "bare metal" in conclusion.
-
Heavily reduced score of
VM::SVM_EXCEPTIONSandVM::TPM_PASSTHROUGHdue to possibility of false flags in exotic edge-cases. Mismatches on all PCRs were detected on Acer Aspire AG15-42P using AMD Ryzen 5 7430U with Radeon Graphics. -
Removed
guibranch. CLIs and TUIs are the only official tools used to display VM detection status for now. -
Removed -Werror & /WX from compilation in official CMake compilation to be more public-friendly.
-
Removed DeepWiki references, as information described on it was never accurate (pure hallucination), such as stating that our timer checks are done by issuing
rdtscinstructions, or thatVM::RDTSCis still a thing when it was removed years ago. I do not recommend using it to understand our code.
VirusTotal Results and Executables
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.