Thursday, November 5, 2026

Inside vac: a byte-exact C++20 reconstruction of Valve Anti-Cheats scan modules

Inside vac: a byte-exact C++20 reconstruction of Valve Anti-Cheat's scan modules

vac reconstructs fifteen classic x86 Valve Anti-Cheat scan modules and steamservice.dll in modern C++20, producing byte-for-byte identical output for authorized anti-cheat and defensive research.

Toolsapdragon/vac — byte-for-byte C++20 reconstruction of 15 x86 Valve Anti-Cheat (VAC) scan modules and steamservice.dll
CategoryWindows internals reverse-engineering and anti-cheat research framework
Primary UseStudying how VAC modules enumerate drivers, handles, processes, and memory through steamservice.dll in a lab environment, with verified parity against original signed binaries
Safe UseEducational and documentary analysis for authorized security researchers, anti-cheat engineers, and defensive professionals working in isolated research environments; this is a study artifact, not a deployment tool
Telemetry NoteThe reconstruction itself contacts nothing; the original VAC behavior it models is server-sealed via RSA-512 packets and observed through ETW process monitoring, giving defenders a precise map of the telemetry the real system generates

vac, published at sapdragon/vac under the MIT license, is one of the more unusual research artifacts to land in the security tooling space: a C++20 reconstruction of fifteen classic x86 Valve Anti-Cheat (VAC) scan modules plus the steamservice.dll loader that ships them. What separates this from a typical annotated disassembly is the verification discipline. Every rebuilt worker is checked against the original signed Valve binaries for exact 4232-byte output parity, and the author deliberately preserves original quirks, uninitialized stack garbage, and genuine implementation bugs, each annotated in-source with // valve bug, keep it. The result is closer to a living museum exhibit than a tool you run in production, and that framing matters for how professionals should read it.

The repository is organized around a shared runtime in sdk/, which re-implements the common module infrastructure: the _runfunc@20 entry contract, the .vacini module descriptor format, a RunDispatcher, and BootstrapMain spanning 172 imports. The SDK also contains the cryptographic and packing primitives the real modules depend on — ICE block encryption, raw RSA-512 sealing, MD5 and CRC32, LZ4 compression, and PE/NT header helpers. Because every scan module inherits this same skeleton, the reconstruction doubles as a clean teaching reference for how commercial anti-cheat systems structure plugin-style scan workers around a common dispatcher.

The service/ directory reconstructs steamservice.dll itself, and this is where the architecture becomes interesting from a defensive-research standpoint. It includes the IPC module manager, an VLV RSA-1024 signature check over incoming modules, a manual mapper exposed as LoadModuleHiddenInternal, and a five-minute ETW-based process monitor. In plain terms, this documents how Valve's service loads scan modules without conventional module registration, authenticates them with a strong signature check, and watches process activity on an interval. Nothing here is a surprise to anyone who has analyzed the binary before, but having a readable, testable reconstruction of the loader chain is genuinely rare.

The fifteen reconstructed modules read like a catalog of Windows introspection techniques. boot_config (0x06A79A9E) walks the BCD registry hive at HKLM\BCD00000000\Objects looking for testsigning and nointegritychecks flags plus NX policy — a classic kernel-environment attestation. cpuid (0x023429C3) pins to CPU 0 and dumps specific CPUID leaves including the hypervisor range at 0x40000000, a straightforward virtualization-detection primitive. devices (0x05EC50DC) enumerates active PCI and USB devices through SetupAPI, useful for spotting hardware spoofers.

Process- and driver-focused modules form the densest cluster. driver_inventory (0x06ACD913, 0x06C2B5BB) reconciles active driver services against the \Driver object directory and computes normalized MD5 hashes of driver files, catching drivers that are loaded but hidden from the service manager. process_file_identity builds a dossier per process — SID, PEB32/PEB64, command line, hashes — along with the ancestor NTFS File ID chain, which is a notably clever way to establish true parentage that resists PID-reuse and spoofing. process_memory_map walks PEB->Ldr and the virtual address space, applies page folding, computes relocation-stripped PE MD5 values, and appends an LZ4-compressed report tail.

The handle-hunting modules deserve their own paragraph because they demonstrate techniques more often associated with offensive tooling. system_handles takes a Toolhelp snapshot, applies 64-bit handle type masks, and performs hidden PID brute-force with the memorable unPid -= 4 loop — scanning potential PID values in steps of four, matching kernel handle-table layout. target_handles (0x08A9324E) goes further, using WoW64 Heaven's Gate (0x33 segment selector) to issue direct x64 syscalls from a 32-bit process while hunting for processes holding handles to the game. For defenders, these reconstructed scanners are effectively a documented checklist of the exact detection surfaces cheat frameworks historically had to evade.

Rounding out the set, image_scan and its image_scan_threads variant implement disk and memory PE scanning with relocation-stripped MD5 hashing, icon and PDB extraction, WinTrust validation, pattern scanning, and thread start-address collection; the _threads variant shares the same .text built with rotated keys and different worker IDs, illustrating how Valve repacked one implementation under multiple identities. service_lookup resolves drivers by service-name hash with sysnative path expansion, shared_section locates named sections by GUID pattern through OpenFileMappingW and NT directory walks, system_info parses KUSER_SHARED_DATA and the on-disk ntdll.dll export table for raw system call numbers, and timing_check is a legacy module predating BootstrapMain that measures KUSER_SHARED_DATA ticks around a patched .data stub. Finally, payload_executor (0x0236ED5F) handles memory allocation, an RSA payload unpacker, PAGE_EXECUTE_READWRITE protection changes, and the entry call — documented here for comprehension, not reuse.

The engineering centerpiece is the parity test suite in tests/. tests/parity/run_all.py executes each worker live against the original DLLs, filtering OS noise by first running the original binary twice against itself, then verifying full _runfunc@20 output packets down to the ICE encryption and RSA-512 sealing. Deterministic fuzz and synthetic suites supplement the live comparisons. The tools/ directory supports the workflow with module blob generators, a worker node inspector, and IDA export plus @orig verification scripts, which strongly suggests the reconstruction was produced through disciplined decompilation cross-referenced against binary-level ground truth.

Getting the code running is straightforward for a Windows research workstation: open vac.sln in Visual Studio 2022 with the Release | Win32 configuration, or drive everything from the command line — python tests/build_tests.py, then python tests/parity/run_all.py, and python tools/ida/fill_orig.py --check sdk modules service to confirm original-address annotations. Be aware that meaningful parity testing presumes access to the original signed binaries referenced under ../vac-research, which you must supply yourself; the repo does not distribute Valve's code or binaries, only clean-room reconstruction and tests.

The accompanying writeup — WRITEUP.en.md and WRITEUP.ru.md, each with a PDF rendering under docs/writeup/ — covers steamservice.dll, the shared SDK, all fifteen scanners, and Valve's bugs in both languages, which signals a serious documentation effort aimed at the research community rather than drive-by users. At 33 stars the project is early in its discovery curve, but the density of technical material is well beyond typical hobbyist reconstructions.

For authorized professionals, vac has three practical values. Anti-cheat engineers get a readable reference for how a mature commercial system structures detection; malware analysts get annotated examples of Heaven's Gate syscalls, manual mapping, hidden-PID enumeration, and NTFS File ID ancestry in non-weaponized form; and blue-team researchers get a precise map of the observable behaviors — ETW process monitoring, section-object lookups, handle-table walks — that kernel-level introspection generates. As with any reconstruction of detection logic, the ethical line is clear: study it in your lab, against binaries you own, and treat it as documentation of an ecosystem rather than an instrument for evading it. The project's own philosophy — preserving bugs byte-for-byte rather than fixing them — is exactly the right posture for that kind of work.

Official project repository for sapdragon/vac.
Download Tool

Educational analysis for authorized security professionals. Use only in controlled, authorized environments.

Share articleFacebookXLinkedIn

Continue exploring

Browse all articles →

0 comentários:

Post a Comment

Note: Only a member of this blog may post a comment.