EMACLAB Anticheat Driver, Part 3: Anti-virtualization
- File Name: EMAC-Driver-x64.sys
- TimeDateStamp: 0x67CAFFCE (Friday, 7 March 2025 14:16:46 GMT)
- Protector: VMProtect 3.8+
Hypervisor checks
One interesting part about the anticheat is the hypervisor checks, but as far as i could find there’s nothing out of ordinary.
Most of those checks are straight taken from other anticheats, or have been talked about in game cheating forums.
The anti-hypervisor subsystem is orchestrated by EmacAntiHypervisorChecks (0xBCF13B34) and employs multiple techniques to detect virtual machines and poorly-implemented hypervisors:
| Function | Address | Description |
|---|---|---|
EmacAntiHypervisorChecks | 0xBCF13B34 | Main orchestrator dispatching all HV checks |
EmacAntiHypervisorCheckName | 0xBCF13A00 | CPUID leaf 0x40000000 hypervisor brand string check |
EmacAntiHypervisorLBR | 0xBCF13A90 | Last Branch Recording MSR 0x1D9 validation |
EmacAntiHypervisorTrashMsr | 0xBCF13C28 | Synthetic MSR probe (0x40000000 range) |
EmacAntiHypervisorAdditionalChecks | 0xBCF13C5C | KiErrata checks on kernel globals |
EmacAntiHypervisorXsetbv | 0xBCF13D4C | XSETBV instruction probing |
EmacAntiHypervisorTiming | 0xBCF1837C | RDTSC timing around CPUID |
EmacHypervisorCheck | 0xBCF16CA4 | VMX extension detection |
EmacHypervisorCheck_0 | 0xBCF16E10 | SEH-based VMM probes |
EmacAntiHypervisorCallVmfunc | 0xBCEEB1DD | VMFUNC instruction test |
EmacDetectVirtualizationPci | 0xBCF2FBA0 | PCI vendor ID enumeration |
LBR (Last Branch Recording) MSR Validation
EmacAntiHypervisorLBR writes to MSR 0x1D9 (IA32_DEBUGCTL) with LBR enable bits. Hypervisors that poorly virtualize debug MSRs will return unexpected values, revealing their presence:
__writemsr(0x1D9, 1); // Enable LBR (bit 0)
value = __readmsr(0x1D9);
// Hypervisor that intercepts but mishandles → value differs → detected
Those checks focus on exploiting bad hypervisors 

Synthetic MSR Probes
EmacAntiHypervisorTrashMsr probes the VMM-reserved MSR range (0x40000000–0x400000FF). Real hardware generates #GP; VMMs may respond with values:
__try {
value = __readmsr(0x40000000);
// If no exception → VMM present
} __except {
// Expected on real hardware
}
Messing with LBR virtualization 

KiErrata Kernel Variable Checks
EmacAntiHypervisorAdditionalChecks checks three kernel errata flags that may indicate system-level patches inconsistent with virtualization:
KiErrata1337PresentKiErrataSkx55PresentKiErrata704Present
KiErrata1337Present, KiErrataSkx55Present, KiErrata704Present 
CPUID Hypervisor Brand Check
EmacAntiHypervisorCheckName reads CPUID leaf 0x40000000 to check if the reported hypervisor is Microsoft Hyper-V ("Microsoft Hv"). Legitimate Hyper-V presence is expected on modern Windows; other brand strings may indicate third-party hypervisors.
Checks if CPUID hypervisor is Microsoft Hyper-V 
Intel CPU Feature Checks
Before performing Intel-specific checks, the driver:
- Verifies CPUID processor name contains “Intel” via
EmacDetectCpuFeatures - Checks if VMX extensions are enabled (CR4.VMXE) via
EmacHypervisorCheck - Uses SEH-wrapped
VMCALL/VMFUNCto probe for hypervisor presence viaEmacHypervisorCheck_0andEmacAntiHypervisorCallVmfunc
Checks if CPUID processor name is Intel as proceeding checks are only available for Intel CPUs 
Then verifies if VMX extensions are enabled, perform calls to try detect hypervisors using SEH 

CPUID Timing Analysis
EmacAntiHypervisorTiming measures VM exit overhead using RDTSC around CPUID:
start = __rdtsc();
__cpuid(regs, 0);
end = __rdtsc();
// Real hardware: ~200 cycles | Virtualized: ~2000+ cycles
CPU timing checks to try detect virtualization 
XSETBV Probing
EmacAntiHypervisorXsetbv tests the XSETBV instruction behavior. On real hardware, specific XCR0 combinations will generate #GP, while poorly implemented hypervisors may handle them differently.
PCI Device Enumeration
EmacDetectVirtualizationPci (0xBCF2FBA0) scans PCI configuration space for known virtual hardware vendor IDs:
| Vendor ID | Platform |
|---|---|
| 0x15AD | VMware |
| 0x1AB8 | Parallels |
| 0x1414 | Hyper-V |
| 0x1AF4 | VirtIO (QEMU/KVM) |
| 0x80EE | VirtualBox |
Returns vendor ID and device count. The decompiled logic scans for VMware (0x15AD) first, then VirtualBox (0x80EE).
PCI Timing Analysis
EmacGetPciLatency measures I/O port access latency for PCI config space reads (ports 0xCF8/0xCFC). TSC is measured around each PCI read at raised IRQL. Potentially used to detect DMA/PCIe-based cheating devices by analyzing access timing anomalies.
unsigned __int64 __fastcall EmacGetPciLatency(unsigned int a1, unsigned __int8 a2, char a3, char a4, char a5)
{
unsigned __int64 v5; // rsi
unsigned __int64 v9; // rbx
int v10; // eax
__int64 v11; // r15
unsigned int v12; // edi
unsigned __int64 v13; // r14
int v14; // edi
unsigned __int8 CurrentIrql; // bl
unsigned int v17; // [rsp+20h] [rbp-10h] BYREF
unsigned int v18; // [rsp+24h] [rbp-Ch] BYREF
unsigned int v19; // [rsp+28h] [rbp-8h] BYREF
unsigned int v20; // [rsp+50h] [rbp+20h] BYREF
v5 = 0i64;
v18 = 0;
v20 = 0;
v19 = 0;
v17 = 0;
v9 = a1;
KeGetCurrentIrql();
EmacGetTscTop(&v18, &v19);
EmacGetTscBottom(&v20, &v17);
EmacGetTscTop(&v18, &v19);
EmacGetTscBottom(&v20, &v17);
if ( (_DWORD)v9 )
{
v10 = a3 & 0x1F;
v11 = (unsigned int)v9;
v12 = a4 & 7 | (8 * (v10 | (32 * (a2 | 0xFFFF8000))));
v13 = (unsigned int)v9;
v14 = a5 & 0xFC | (v12 << 8);
do
{
CurrentIrql = KeRaiseIrql(2u);
EmacGetTscTop(&v18, &v19);
__outdword(0xCF8u, v14);
__indword(0xCFCu);
EmacGetTscBottom(&v20, &v17);
KeRaiseIrql(CurrentIrql);
v5 += (v17 | ((unsigned __int64)v20 << 32)) - (v19 | ((unsigned __int64)v18 << 32));
--v11;
}
while ( v11 );
}
else
{
v13 = v9;
}
return v5 / v13;
}
PCI Infrastructure Functions
| Function | Address | Purpose |
|---|---|---|
EmacEnumeratePciBridgeSubBus | — | Traverses PCI bridge secondary buses |
EmacBuildPciDeviceRecord | — | Creates device info record from PCI config |
EmacScanPciBusByVendorId | — | Searches specific bus for target vendor |
EmacEnumerateAllPciDevices | — | Full PCI bus enumeration |
EmacEnumeratePciBusDevices | — | Per-bus device scan |
EmacReadPciConfigSpace | — | Raw PCI config space read via I/O ports |
EmacIsAddressWithinPciRange | — | Address range validation |
FNV-1a Storage Device Whitelist
Legitimate storage device identifiers are whitelisted via FNV-1a hashes to avoid false positives on real hardware:
0x5F29C8DC, 0x3B5D28B5, 0x63C3F8B6, 0x6E4F0C16,
0x21CD3EBC, 0x79B1C26D, 0x64FCF14B, ...
IDA decompiled snippets
Conclusion
I was able to run the anti-cheat on virtualized environments like VMware and KVM, as long as i had Hyper-V running i had no problems, but that doesn’t necessarely means there’s was no flags. If you wanna play safely my guess is: use KVM with QEMU patches and enable Hyper-V, this should be enought for ban evasion, or, if you’re the ultimate linux user that should work for you.
The anti-hypervisor subsystem, while comprehensive, focuses primarily on detecting poorly-configured hypervisors. The PCI device enumeration and timing analysis suggest awareness of DMA-based cheating devices. The FNV-1a storage device whitelist helps reduce false positives from legitimate hardware.
Like i said those checks are nothing new, most modern anti-cheats like Riot Games Vanguard take this more seriously and have better, advanced checks to detect virtualization.