{"id":13606865,"url":"https://github.com/danielkrupinski/VAC","last_synced_at":"2025-04-12T11:30:58.378Z","repository":{"id":39172612,"uuid":"204701393","full_name":"danielkrupinski/VAC","owner":"danielkrupinski","description":"Source code of Valve Anti-Cheat obtained from disassembly of compiled modules","archived":false,"fork":false,"pushed_at":"2020-06-12T16:19:59.000Z","size":196,"stargazers_count":756,"open_issues_count":0,"forks_count":93,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-03-14T16:49:35.759Z","etag":null,"topics":["anti-cheat","csgo","css","disassembly","dota2","reverse-engineering","steam","tf2","vac","valve-anti-cheat"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielkrupinski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-27T12:45:19.000Z","updated_at":"2025-03-12T14:59:05.000Z","dependencies_parsed_at":"2022-07-12T17:48:02.458Z","dependency_job_id":null,"html_url":"https://github.com/danielkrupinski/VAC","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielkrupinski%2FVAC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielkrupinski%2FVAC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielkrupinski%2FVAC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielkrupinski%2FVAC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielkrupinski","download_url":"https://codeload.github.com/danielkrupinski/VAC/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248560053,"owners_count":21124585,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anti-cheat","csgo","css","disassembly","dota2","reverse-engineering","steam","tf2","vac","valve-anti-cheat"],"created_at":"2024-08-01T19:01:13.154Z","updated_at":"2025-04-12T11:30:58.094Z","avatar_url":"https://github.com/danielkrupinski.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# VAC 🛡️\nThis repository contains parts of source code of Valve Anti-Cheat for Windows systems recreated from machine code.\n\n# Introduction\nValve Anti-Cheat (VAC) is user-mode noninvasive anti-cheat system developed by Valve. It is delivered in form of modules (dlls) streamed from the remote server. `steamservice.dll` loaded into `SteamService.exe` (or `Steam.exe` if run as admin) prepares and runs anti-cheat modules. Client VAC infrastructure is built using `C++` (indicated by many `thiscall` convention functions present in disassembly) but this repo contains `C` code for simplicity. Anti-cheat binaries are currently `32-bit`.\n\n# Modules\n| ID | Purpose | .text section raw size | Source folder |\n| --- | --- | --- | --- |\n| 1 | Collect information about system configuration.\u003cbr\u003eThis module is loaded first and sometimes even before any VAC-secured game is launched. | 0x5C00 | Modules/SystemInfo\n| 2 | Enumerate running processes and handles.\u003cbr\u003eThis module is loaded shortly after game is launched but also repeatedly later. | 0x4A00 | Modules/ProcessHandleList\n| 3 | Collect `VacProcessMonitor` data from filemapping created by `steamservice.dll`. It's the first module observed to use `virtual methods (polymorphism)`. | 0x6600 | Modules/ProcessMonitor\n\n# Encryption / Hashing\nVAC uses several encryption / hashing methods:\n- MD5 - hashing data read from process memory\n- ICE - decryption of imported functions names and encryption of scan results\n- CRC32 - hashing table of WinAPI functions addresses\n- Xor - encryption of function names on stack, e.g `NtQuerySystemInformation`. Strings are xor-ed with `^` or `\u003e` or `\u0026` char.\n\n# Module Description\n\n## #1 - SystemInfo\nThis module is loaded first and sometimes even before any VAC-secured game is launched.\n\nAt first module invokes [`GetVersion`](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversion) function to retrieve **major and build** system version e.g `0x47BB0A00` - which means:\n- 0x47BB - build version (decimal `18363‬`) \n- 0x0A00 - major version (decimal `10`)\n\nThe module calls `GetNativeSystemInfo` function and reads fields from resultant [`SYSTEM_INFO`](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info) struct:\n- wProcessorArchitecture\n- dwProcessorType\n\nThen it calls [`NtQuerySystemInformation`](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation) API function with following `SystemInformationClass` values (in order they appear in code):\n- SystemTimeOfDayInformation - returns undocumented [`SYSTEM_TIMEOFDAY_INFORMATION`](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/timeofday.htm) struct, VAC uses two fields:\n    - LARGE_INTEGER CurrentTime\n    - LARGE_INTEGER BootTime\n- SystemCodeIntegrityInformation - returns [`SYSTEM_CODEINTEGRITY_INFORMATION`](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/codeintegrity.htm), module saves `CodeIntegrityOptions` field\n- SystemDeviceInformation - returns [`SYSTEM_DEVICE_INFORMATION`](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/device.htm), module saves `NumberOfDisks` field\n- SystemKernelDebuggerInformation - returns [`SYSTEM_KERNEL_DEBUGGER_INFORMATION`](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/kernel_debugger.htm), VAC uses whole struct\n- SystemBootEnvironmentInformation - returns [`SYSTEM_BOOT_ENVIRONMENT_INFORMATION`](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/boot_environment.htm), VAC copies `BootIdentifier` GUID\n- SystemRangeStartInformation - returns `SYSTEM_RANGE_START_INFORMATION` which is just `void*`. Anti-cheat saves returned **kernel space start address** and **sign bit** of that address (to check if executable inside which VAC is running is linked with [`LARGEADDRESSAWARE`](https://docs.microsoft.com/en-us/cpp/build/reference/largeaddressaware-handle-large-addresses) option)\n\nFor more information about `SYSTEM_INFORMATION_CLASS` enum see [Geoff Chappell's page](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/class.htm).\n\nNext, anti-cheat calls [`GetProcessImageFileNameA`](https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessimagefilenamea) function to retrieve path of current executable and **reads last 36 characters** (e.g. `\\Program Files (x86)\\Steam\\Steam.exe`).\n\nLater VAC retrieves **system directory path** (e.g `C:\\WINDOWS\\system32`) using [`GetSystemDirectoryW`](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemdirectoryw), converts it from wide-char to multibyte string, and stores it (max length of multibyte string - 200).\nAnti-cheat queries folder FileID (using [`GetFileInformationByHandleEx`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex)) and **volume serial number** ([`GetVolumeInformationByHandleW`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationbyhandlew)). Further it does the same with **windows directory** got from [`GetWindowsDirectoryW`](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getwindowsdirectoryw) API.\n\nModule reads `NtDll.dll` file from **system directory** and does some processing on it (not reversed yet).\n\nVAC saves **handles (base addresses) of imported system dlls** (max 16, this VAC module loads 12 dlls) and **pointers to WINAPI functions** (max 160, module uses 172 functions‬). This is done to detect **import address table hooking** on anti-cheat module, if **function address** is lower than corresponding **module base**, function has been hooked.\n\nAnti-cheat gets self **module base** by performing **bitwise and** on **return address** (`_ReturnAddress() \u0026 0xFFFF0000`). Then it collects:\n- module base address\n- first four bytes at module base address (from DOS header)\n- DWORD at **module base + 0x114**\n- DWORD at **module base + 0x400** (start of .text section)\n\nNext it enumerates **volumes** using `FindFirstVolumeW` / `FindNextVolumeW` API. VAC queries volume information by calling `GetVolumeInformationW`, `GetDriveTypeW` and `GetVolumePathNamesForVolumeNameW` functions and fills following struct with collected data:\n\n```cpp\nstruct VolumeData {\n    UINT volumeGuidHash;\n    DWORD getVolumeInformationError;\n    DWORD fileSystemFlags;\n    DWORD volumeSerialNumber;\n    UINT volumeNameHash;\n    UINT fileSystemNameHash;\n    WORD driveType;\n    WORD volumePathNameLength;\n    DWORD volumePathNameHash;\n}; // sizeof(VolumeData) == 32\n```\nVAC gathers data of max. 10 volumes.\n\nIf this module was streamed after VAC-secured game had started, it attemps to get handle to the game process (using `OpenProcess` API).\n\nEventually, module encrypts data (2048 bytes), DWORD by DWORD XORing with key received from server (e.g 0x1D4855D3)\n\n## #2 - ProcessHandleList\n\nTo be disclosed...\n\n## #3 - ProcessMonitor\n\nThis module seems to be relatively `new` or was disabled for a long time. First time I saw this module in `January 2020`. It has an ability to perform many different types of scans (currently `3`). Further scans depends on the results of previous ones.\n\nEach scan type implements `four methods` of a base class.\n\nInitially VAC server instructs client to perform `scan #1`.\n\n### Scan #1 - VacProcessMonitor filemapping\n\nFirst scan function attemps to open `Steam_{E9FD3C51-9B58-4DA0-962C-734882B19273}_Pid:%000008X` filemapping. The mapping has following layout:\n\n```cpp\nstruct VacProcessMonitorMapping {\n    DWORD magic; // when initialized - 0x30004\n    PVOID vacProcessMonitor;\n}; // sizeof(VacProcessMonitorMapping) == 8\n```\n\n`VacProcessMonitorMapping::vacProcessMonitor` is a pointer to the `VacProcessMonitor` object (size of which is `292 bytes`).\n\nVAC then reads the whole `VacProcessMonitor` object (292 bytes) and its VMT (Virtual Method Table) containing pointers to `6` methods (24 bytes).\nThe base address of `steamservice.dll` is also gathered.\n\nThese data are probably used on VAC servers to detect hooking `VacProcessMonitor`. The procedure may be following:\n```cpp\nif (method_ptr \u0026 0xFFFF0000 != steamservice_base)\n    hook_detected();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielkrupinski%2FVAC","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielkrupinski%2FVAC","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielkrupinski%2FVAC/lists"}