Writing a Kernel-Level HWID Spoofer: Complete Developer Guide
Hardware ID (HWID) bans are the nuclear option of anti-cheat enforcement. When a player gets HWID banned, their entire computer is blacklisted — new accounts, new game purchases, nothing works until the hardware fingerprint changes. For cheat developers, building a reliable HWID spoofer is both a lucrative product and a necessary tool. This guide covers everything from what identifiers are tracked to writing a kernel driver that spoofs them.
HWID spoofers are consistently among the best-selling products on CheatBay. Every banned player needs one, and they need it to work reliably. Let's build one.
What Do HWID Bans Track?
Anti-cheat systems collect multiple hardware identifiers to create a composite fingerprint. Here's exactly what they look for:
1. Disk Drive Serial Numbers
The most commonly tracked identifier. Anti-cheats query disk serials through multiple methods:
- SMART data: Via
IOCTL_SMART_RCV_DRIVE_DATA— returns the drive's firmware serial. - Storage query: Via
IOCTL_STORAGE_QUERY_PROPERTYwithStorageDeviceProperty— returns vendor, product, and serial strings. - ATA IDENTIFY: Via
IOCTL_ATA_PASS_THROUGH— raw ATA command that returns the drive identity page including serial. - SCSI inquiry: Via
IOCTL_SCSI_MINIPORT— for SCSI/SAS drives. - WMI:
Win32_DiskDrive.SerialNumber— high-level query that ultimately uses the above IOCTLs.
A proper spoofer must intercept ALL of these paths. Missing even one means the anti-cheat can still read the real serial.
2. Network Adapter MAC Addresses
Every NIC has a unique MAC address. Anti-cheats collect these via:
GetAdaptersInfo()/GetAdaptersAddresses()— Win32 APIIOCTL_NDIS_QUERY_GLOBAL_STATSwithOID_802_3_PERMANENT_ADDRESS- Direct registry reads from
HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e972-...} - WMI:
Win32_NetworkAdapter.MACAddress
3. Motherboard / BIOS Identifiers
- SMBIOS data: Motherboard serial, BIOS serial, system UUID. Accessible via
GetSystemFirmwareTable('RSMB', ...). - Registry:
HKLM\HARDWARE\DESCRIPTION\System\BIOS— contains BaseBoardProduct, SystemProductName, etc. - WMI:
Win32_BaseBoard.SerialNumber,Win32_BIOS.SerialNumber,Win32_ComputerSystemProduct.UUID.
4. TPM (Trusted Platform Module)
Modern anti-cheats (especially Vanguard) leverage TPM 2.0:
- TPM endorsement key — unique per chip
- TPM platform registers (PCRs)
- Windows uses TPM for device attestation, and anti-cheats piggyback on this
5. Windows Installation ID
HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid— unique per Windows installHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId- Credential Guard and Windows Hello device keys
6. Monitor EDID and GPU Serial
Some anti-cheats have started collecting:
- Monitor serial numbers from EDID data
- GPU serial via vendor-specific APIs (NVAPI for NVIDIA)
- Display adapter registry entries
// Complete HWID fingerprint (what anti-cheats build):
//
// ┌─────────────────────────────────────────────┐
// │ HWID FINGERPRINT │
// ├─────────────────────────────────────────────┤
// │ Disk Serials: WD-WMC4N0K1234, ... │
// │ NIC MACs: AA:BB:CC:DD:EE:FF, ... │
// │ Motherboard SN: MB12345678 │
// │ BIOS Serial: BIOS-9876 │
// │ System UUID: {4C4C4544-0042-...} │
// │ MachineGuid: a1b2c3d4-... │
// │ TPM EK: (hash) │
// │ Monitor EDID: DEL-U2415-SN123 │
// │ GPU Serial: GPU-abc-123 │
// │ Install Date: 1703001234 │
// │ Volume Serial: ABCD-1234 │
// └─────────────────────────────────────────────┘
// Hash of all = your HWID ban identifier
Windows Driver Development Basics
HWID spoofing requires kernel-level access. You can't reliably spoof hardware identifiers from user mode because anti-cheats read them from kernel mode too. Here's what you need:
Development Environment
- Visual Studio 2022 with C++ desktop workload
- Windows Driver Kit (WDK) matching your Windows SDK version
- A test VM with test signing enabled (
bcdedit /set testsigning on) - WinDbg for kernel debugging (connect via serial or network to your VM)
Minimal WDM Driver Structure
#include <ntddk.h>
// Forward declarations
DRIVER_UNLOAD DriverUnload;
DRIVER_DISPATCH DispatchPassthrough;
void DriverUnload(PDRIVER_OBJECT DriverObject) {
// Unhook everything, clean up
DbgPrint("[Spoofer] Driver unloaded\n");
}
NTSTATUS DispatchPassthrough(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// Default: pass IRPs down the stack
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceObject, Irp);
}
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = DriverUnload;
// Set default dispatch for all IRP types
for (int i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = DispatchPassthrough;
}
DbgPrint("[Spoofer] Driver loaded\n");
// Install hooks here
SpoofDiskSerials();
SpoofNicMac();
SpoofSmbios();
SpoofRegistry();
return STATUS_SUCCESS;
}
Spoofing Disk Serial Numbers
This is the most important and most complex part. You need to intercept disk IOCTLs at the storage driver level.
Approach: Hooking the Storage Miniport Driver
The cleanest approach is to attach a filter device to the disk device stack and intercept IOCTL responses:
NTSTATUS SpoofDiskSerials() {
// 1. Find the disk device objects
// Enumerate \Device\Harddisk0\DR0, etc.
UNICODE_STRING diskName;
RtlInitUnicodeString(&diskName, L"\\Device\\Harddisk0\\DR0");
PFILE_OBJECT fileObj;
PDEVICE_OBJECT diskDevice;
NTSTATUS status = IoGetDeviceObjectPointer(&diskName, FILE_READ_DATA, &fileObj, &diskDevice);
if (!NT_SUCCESS(status)) return status;
// 2. Find the miniport driver in the device stack
PDEVICE_OBJECT lowestDevice = IoGetDeviceAttachmentBaseRef(diskDevice);
// 3. Hook the miniport's IRP_MJ_DEVICE_CONTROL handler
PDRIVER_OBJECT miniportDriver = lowestDevice->DriverObject;
// Save original handler
g_OriginalDeviceControl = miniportDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL];
// Replace with our hook
InterlockedExchangePointer(
(PVOID*)&miniportDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL],
(PVOID)HookedDeviceControl
);
ObDereferenceObject(fileObj);
return STATUS_SUCCESS;
}
NTSTATUS HookedDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG ioctl = stack->Parameters.DeviceIoControl.IoControlCode;
// Set completion routine to modify output AFTER the real driver fills it
if (ioctl == IOCTL_STORAGE_QUERY_PROPERTY ||
ioctl == IOCTL_SMART_RCV_DRIVE_DATA ||
ioctl == IOCTL_ATA_PASS_THROUGH) {
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, SpoofCompletionRoutine, NULL, TRUE, TRUE, TRUE);
return IoCallDriver(DeviceObject, Irp);
}
return g_OriginalDeviceControl(DeviceObject, Irp);
}
NTSTATUS SpoofCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) {
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG ioctl = stack->Parameters.DeviceIoControl.IoControlCode;
if (ioctl == IOCTL_STORAGE_QUERY_PROPERTY) {
// Modify the serial string in the output buffer
PSTORAGE_DEVICE_DESCRIPTOR desc = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
if (desc->SerialNumberOffset != 0) {
char* serial = (char*)desc + desc->SerialNumberOffset;
GenerateRandomSerial(serial, strlen(serial));
}
}
// Handle other IOCTLs similarly...
}
if (Irp->PendingReturned)
IoMarkIrpPending(Irp);
return STATUS_SUCCESS;
}
Spoofing NIC MAC Addresses
MAC address spoofing can be done at multiple levels:
Registry-Based Spoofing
// For each network adapter, set the NetworkAddress registry value
// HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-...}\0001
NTSTATUS SpoofNicMac() {
UNICODE_STRING regPath;
RtlInitUnicodeString(®Path,
L"\Registry\Machine\SYSTEM\CurrentControlSet\Control\Class\"
L"{4D36E972-E325-11CE-BFC1-08002BE10318}");
// Enumerate subkeys (0000, 0001, etc.)
// For each adapter, write a new NetworkAddress value
UNICODE_STRING valueName;
RtlInitUnicodeString(&valueName, L"NetworkAddress");
WCHAR newMac[] = L"AABBCCDDEEFF"; // Generate random
GenerateRandomMacString(newMac);
ZwSetValueKey(adapterKey, &valueName, 0, REG_SZ,
newMac, sizeof(newMac));
return STATUS_SUCCESS;
}
NDIS-Level Spoofing
For deeper spoofing, hook the NDIS miniport's OID_802_3_PERMANENT_ADDRESS and OID_802_3_CURRENT_ADDRESS queries. This catches anti-cheats that bypass the registry and query the driver directly.
Spoofing SMBIOS / BIOS Data
SMBIOS data is exposed through GetSystemFirmwareTable which calls NtQuerySystemInformation with SystemFirmwareTableInformation:
// Hook NtQuerySystemInformation to intercept SMBIOS queries
NTSTATUS HookedNtQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
) {
NTSTATUS status = OrigNtQuerySystemInformation(
SystemInformationClass, SystemInformation,
SystemInformationLength, ReturnLength
);
if (NT_SUCCESS(status) &&
SystemInformationClass == SystemFirmwareTableInformation) {
PSYSTEM_FIRMWARE_TABLE_INFORMATION info =
(PSYSTEM_FIRMWARE_TABLE_INFORMATION)SystemInformation;
if (info->ProviderSignature == 'RSMB') {
// Parse SMBIOS structure and replace serial strings
SpoofSmbiosData(info->TableBuffer, info->TableBufferLength);
}
}
return status;
}
void SpoofSmbiosData(PUCHAR buffer, ULONG length) {
// SMBIOS structures are type-length-data format
// Type 0 = BIOS (serial at specific offset)
// Type 1 = System (UUID, serial)
// Type 2 = Baseboard (serial, product name)
PUCHAR current = buffer + 8; // Skip header
while (current < buffer + length) {
SMBIOS_HEADER* header = (SMBIOS_HEADER*)current;
if (header->Type == 1) { // System Information
// UUID is at offset 0x08 from structure start (16 bytes)
GenerateRandomBytes(current + 0x08, 16);
}
// Move past the formatted area
current += header->Length;
// Move past the unformatted string area (double null terminated)
while (current < buffer + length - 1) {
if (current[0] == 0 && current[1] == 0) {
current += 2;
break;
}
// Replace string content with random data
if (*current != 0) *current = RandomAlphaNum();
current++;
}
}
}
Registry Spoofing
Many identifiers are also cached in the registry. You need to intercept registry queries:
// Key registry values to spoof:
// HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid
// HKLM\HARDWARE\DESCRIPTION\System\BIOS\*
// HKLM\SYSTEM\CurrentControlSet\Control\SystemInformation\*
// HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId
// Approach: Hook ZwQueryValueKey
NTSTATUS HookedZwQueryValueKey(
HANDLE KeyHandle,
PUNICODE_STRING ValueName,
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
PVOID KeyValueInformation,
ULONG Length,
PULONG ResultLength
) {
NTSTATUS status = OrigZwQueryValueKey(
KeyHandle, ValueName, KeyValueInformationClass,
KeyValueInformation, Length, ResultLength
);
if (NT_SUCCESS(status) && ValueName) {
if (RtlEqualUnicodeString(ValueName, &g_MachineGuidName, TRUE)) {
// Replace MachineGuid in the output buffer
SpoofRegistryValue(KeyValueInformation, KeyValueInformationClass);
}
}
return status;
}
Loading Your Driver: Test Signing vs Vulnerable Drivers
Getting a kernel driver loaded on modern Windows is the biggest challenge:
Test Signing (Development Only)
:: Enable test signing
bcdedit /set testsigning on
:: Reboot
:: Create a self-signed cert and sign your driver
makecert -r -pe -ss PrivateCertStore -n "CN=TestCert" TestCert.cer
signtool sign /s PrivateCertStore /n "TestCert" /t http://timestamp.digicert.com spoofer.sys
:: Load with sc.exe
sc create Spoofer type= kernel binPath= C:\path\to\spoofer.sys
sc start Spoofer
Limitation: Test signing shows a watermark and is easily detected by anti-cheats.
Vulnerable Driver Loading (BYOVD)
The industry-standard approach for production spoofers is to exploit a legitimately signed but vulnerable driver:
- Load a known vulnerable signed driver (e.g., certain versions of Capcom.sys, Intel drivers, etc.)
- Exploit its vulnerability to gain arbitrary kernel code execution
- Map your unsigned driver into kernel memory manually
- Unload the vulnerable driver to clean up evidence
// Simplified BYOVD flow:
// 1. Load vulnerable driver
LoadVulnerableDriver("vuln_signed.sys");
// 2. Exploit it to get kernel R/W or execution
KernelExecute(vuln_handle, shellcode, sizeof(shellcode));
// 3. The shellcode maps our spoofer driver
// - Allocates kernel pool memory
// - Copies driver image
// - Resolves imports
// - Calls DriverEntry
// 4. Clean up
UnloadVulnerableDriver();
EV Code Signing Certificate
The legitimate approach is to obtain an Extended Validation (EV) code signing certificate and submit your driver to Microsoft's WHQL program. This is expensive ($300-500/year) and requires a registered business, but it produces a properly signed driver that loads without test signing.
Anti-Cheat Specific Considerations
EasyAntiCheat (EAC)
EAC collects HWIDs during its initialization and periodically sends them to its servers. It reads disk serials via direct IOCTL calls from kernel mode, making user-mode spoofing useless. Your spoofer must be loaded before the game and EAC start.
BattlEye (BE)
BattlEye's HWID collection is similar to EAC but also includes monitor EDID data and USB device serials. BattlEye's kernel driver (BEDaisy.sys) has its own IOCTL dispatch that can read hardware directly.
Vanguard (Riot)
Vanguard is the most aggressive. It loads at boot time (before any spoofer typically loads), monitors TPM, and uses Secure Boot attestation. Spoofing for Vanguard requires your spoofer to load at boot time as well — either as a boot-start driver or via UEFI. This is significantly more complex.
Testing Your Spoofer
Before selling, verify every vector is covered:
// User-mode verification script (PowerShell):
// Run before and after spoofer to compare
# Disk serials
Get-WmiObject Win32_DiskDrive | Select SerialNumber
Get-PhysicalDisk | Select SerialNumber
# MAC addresses
Get-NetAdapter | Select MacAddress
Get-WmiObject Win32_NetworkAdapter | Where {$_.MACAddress} | Select MACAddress
# Motherboard / BIOS
Get-WmiObject Win32_BaseBoard | Select SerialNumber, Product
Get-WmiObject Win32_BIOS | Select SerialNumber
Get-WmiObject Win32_ComputerSystemProduct | Select UUID
# Machine GUID
(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Cryptography").MachineGuid
# Volume serial
vol C:
If ANY value is the same before and after running your spoofer, you have a gap that anti-cheats will exploit.
Selling Your HWID Spoofer on CheatBay
HWID spoofers are the #1 most needed tool for banned gamers. On CheatBay, spoofer sellers consistently earn top revenue because:
- Universal demand: Every banned player in every game needs a spoofer. It's game-agnostic.
- Recurring revenue: Spoofers need updates as anti-cheats evolve. Subscription pricing is the norm.
- High perceived value: Players pay premium prices ($10-30/month) for reliable spoofers because the alternative is buying new hardware.
- CheatBay handles the business side: BTC/Lightning payments, subscription management, key delivery — you focus on the code.
Ready to Level Up?
Browse verified, undetected cheats on CheatBay — or start selling your own and earn crypto.
Browse Cheats Start Selling