AACGUARD: Evidence-Weighted, User-Mode Forensic Cheat Detection for Community Game Servers
Abstract
Community-run servers for competitive shooters such as Counter-Strike have no access to the kernel-level anti-cheat that protects official matchmaking. Their administrators often decide on suspected cheaters with little more than spectator footage. We present AACGUARD, a user-mode forensic scanner that a player runs on request, together with the web platform used to review its reports. The client examines 22 evidence sources: Windows execution history (Prefetch, BAM, MUICache, AmCache, ShimCache), file-system and autostart locations, removable-media history, browser history, game configuration files, virtualization and RAM-disk indicators, anti-forensic tooling, and the live state of the game process and kernel. Each finding is recorded as a weighted item of evidence, and a two-dimensional decision rule over total score and number of findings produces a verdict of CLEAN, SUSPICIOUS or CHEAT DETECTED.
Version 0.0.10 adds automatic game identification for six titles and attributes the game server a player is connected to, using header-only packet observation, the Source/GoldSrc A2S query protocol and DNS verification. It also inspects the 32-bit processes that were previously invisible to the 64-bit client, detects manually mapped code, and applies a three-stage trust model against false positives caused by legitimate system components. In a documented case study, the trust model reduced a clean player's score from 395 to 130 and corrected the verdict from CHEAT DETECTED to CLEAN. A complete scan takes about 17 seconds and performs about 1.9 × 105 individual checks. The public deployment had recorded 11,181 scans at the time of writing.
Keywords: anti-cheat · digital forensics · Windows artifacts · evidence scoring · false-positive reduction · process memory inspection · A2S protocol · Counter-Strike · community game servers
1Introduction
Cheating in online games undermines fair competition and drives honest players away. Large publishers respond with commercial anti-cheat systems that run kernel drivers, monitor continuously and are tied to official matchmaking. A large part of the Counter-Strike ecosystem, however, is played on community servers: independently hosted servers with their own rules, plugins and moderation teams. These servers are often built on older engines (GoldSrc for CS 1.6, Source for CS:GO), where the only built-in protection is Valve Anti-Cheat (VAC), and VAC bans are delayed and not visible to server staff.
In this setting a common moderation practice has formed. When a player is suspected, an administrator asks them to run a scanner and share the result. The scanner has to answer a narrow forensic question: does this machine show credible traces of cheat software, and how strong is that evidence? The answer has to be produced without a kernel driver, within seconds, on hardware the scanner has never seen, and in a form that another person can check.
AACGUARD is built for this workflow. Its design follows three principles:
- User-mode only. The client runs with administrator rights but installs nothing permanent and loads no driver. This makes it easy to distribute and to trust, at the cost of visibility (Section 15).
- Evidence, not per-check verdicts. No single heuristic decides the outcome. Findings carry a strength and a weight, and the verdict depends on the combination.
- Reviewability. Every scan is stored with its complete log and per-check status, so a human reviewer can see why a verdict was reached and dismiss findings that do not hold.
This report makes the following contributions:
- A description of a complete user-mode forensic pipeline for cheat detection with 22 evidence sources, together with its full detection catalogue and weights (Sections 5–7, Appendix A).
- A two-dimensional verdict rule that requires either one decisive finding or several corroborating ones, and an analysis of its properties (Section 7).
- A method to attribute the connected game server from user mode for UDP-based games, combining header-only packet observation, A2S queries and DNS verification, with a history-based fallback (Section 9).
- A three-stage trust model that removes a class of high-scoring false positives, with a documented case study (Section 11).
- A description of the review platform that turns scan data into moderation decisions, including privacy measures (Sections 12 and 14).
2Background and related work
2.1Cheating and its classification
Yan and Randell give a systematic classification of cheating in online games by vulnerability, consequence and cheater [1]. The cheats that matter for AACGUARD fall into their category of exploiting a lack of secrecy or integrity on the client: internal cheats that run inside the game process (typically an injected DLL that reads entity data and draws an overlay or adjusts aim) and external cheats that run as a separate process and read or write game memory through the operating system. Both have to be delivered, usually by a loader or injector, and both leave traces on the machine they ran on.
2.2Client-side anti-cheat
Commercial systems move detection into the kernel to see what user-mode code cannot. Dorner and Klausner examine kernel-level anti-cheat critically and compare its capabilities and risks with rootkits [2]. Collins et al. evaluate client-side defences against a range of attacks and show that user-mode protections can be bypassed by attackers who control the machine [3]. AACGUARD accepts this limit. It does not try to prevent cheating while the game runs. It performs a post-hoc examination designed to catch the traces that delivery and use of a cheat leave behind, which a cheater has to remove completely and in advance to stay hidden.
2.3Windows forensic artifacts
Many of AACGUARD's evidence sources are standard in digital forensics. The Windows registry records program execution and user activity in several places [4]. Prefetch files record the executables the system has launched. The AmCache hive stores metadata about programs that have been present or executed, and its interpretation has been analysed in detail by ANSSI [5]. Memory forensics tools identify injected code by looking for executable memory that no file on disk backs [6]. The internal structures AACGUARD relies on (process address spaces, module lists, WOW64 redirection) are documented in Windows Internals [7] and the Win32 API reference [8–12]. AACGUARD's contribution is not a new artifact but an automated, weighted combination of these artifacts, tuned to one domain and exposed for human review.
3Threat model and design goals
We assume a player who may have used cheat software on the machine being scanned and who controls that machine, including administrator access. The scan is started voluntarily, usually at an administrator's request. The player may run the scanner on a machine that has been cleaned, may close the cheat before scanning, and may rename files. We assume the player cannot tamper with the server side (API, database, panel).
| Stage | Typical activity | Evidence surfaces examined |
|---|---|---|
| Acquisition | Visiting a cheat forum or shop, downloading an archive | Browser history, Downloads/Desktop, Recycle Bin, shortcuts |
| Staging | Extracting, keeping files on USB, RAM disks or in a VM | AppData, USB history, RAM-disk and VM indicators |
| Execution | Running a loader or external cheat | Prefetch, BAM, MUICache, AmCache, ShimCache, running processes |
| Injection | Loading code into the game, possibly via a vulnerable driver | Game modules, private executable memory, loaded drivers |
| Persistence and use | Autostart, cheat-specific configs | Run keys, game .cfg files |
| Concealment | Cleaners, deleting traces | Anti-forensic tool indicators, Recycle Bin |
The design goals follow from this model:
- Coverage across the life cycle. A cheater who hides one stage should still be exposed by another.
- Precision over recall. A false accusation damages a player and the scanner's credibility. Weak signals may raise suspicion but must not produce a cheat verdict on their own.
- Updatability. Cheat names, sites and whitelists change weekly, so they are loaded from the server at scan time, not compiled into the client.
- Explainability. Every contribution to the score is logged in plain language, with its source and path.
- Low friction. One click, no installation, results in under half a minute.
4System architecture
AACGUARD has three tiers (Figure 1): a Windows desktop client (.NET 10, WPF), an HTTPS API that accepts scan reports, and a PHP web panel backed by MariaDB.
4.1Scan life cycle
Figure 2 shows the sequence of one scan. The client loads the remote configuration and identifies the running game. It then runs the checks in a fixed order, derives the verdict, and uploads the report only if its version exactly matches the minimum version published by the server. This version gate keeps reports from outdated detection logic out of the database. The client then shows a local report window, and the scan becomes visible in the panel. An automated interpretation of the log is attached to the scan asynchronously (Section 12.3).
4.2Client structure
The engine is a single orchestrator that owns the shared state: configuration, metrics, the list of findings and the per-check status. Each evidence source is implemented as a separate class with an Execute(token) method. A check never decides a verdict. It calls a single registration method, which logs the finding, updates the totals and notifies the user interface (Listing 1). This keeps all checks accountable to the same scoring and logging path.
internal void RegisterDetection(string description, EvidenceStrength strength, int scoreDelta, string? filePath = null, string? source = null) { Log($"DETECTION ({strength}): {description}"); _metrics.TotalDetections++; _metrics.Score += scoreDelta; _detections.Add(new DetectionItem { Description = description, Strength = strength, ScoreDelta = scoreDelta, FilePath = filePath, Source = source ?? "Unknown" }); UpdateMetrics(); // live UI counters }
5Forensic artifact analysis
This section describes each evidence source, what it records, and how AACGUARD interprets it. Table 2 gives an overview. The weights for every finding are listed in Appendix A.
| # | Source | What it records | Survives deletion of the cheat? |
|---|---|---|---|
| 1 | Prefetch | Executables launched, with last-run time | Yes |
| 2 | BAM | Per-user executable paths with last-execution time | Yes |
| 3 | MUICache | Display names of executed programs | Yes |
| 4 | AppData | Files in the user's application-data folders | No |
| 5 | Recycle Bin | Deleted files with original path and deletion time | Until emptied |
| 6 | Downloads / Desktop | Cheat-like files, loaders, archives | No |
| 7 | CS directory | Foreign DLLs inside the game folder | No |
| 8 | USB history | Storage devices seen, last connection, recent executables | Partly |
| 9 | Browser history | Visits to cheat sites and cheat-related searches | Until cleared |
| 10 | AmCache | Programs present or executed, with metadata | Yes |
| 11 | ShimCache | Executables seen by the compatibility engine | Yes |
| 12 | Run keys | Programs set to start with Windows | No |
| 13 | Shortcuts | .lnk files and their targets | Often |
| 14 | Processes and modules | Running tools, DLLs loaded into the game | No (live) |
| 15 † | Injection | Executable private memory holding a PE image | No (live) |
| 16 † | Drivers | Loaded kernel drivers | No (live) |
| 17–19 | Virtualization, VM history, VM registry | VM software, hardware markers, installer events | Yes |
| 20 | RAM disk | RAM drives and software | Partly |
| 21 | Anti-forensics | Cleaner and trace-removal tools | Yes |
| 22 | CFG scan | Non-default game configs with cheat-specific content | No |
5.1Execution history
Prefetch. Windows keeps a .pf file per launched executable in C:\Windows\Prefetch. The file name contains the executable name, and its modification time approximates the last execution. AACGUARD weights Prefetch findings by recency, because a trace from the last 24 hours is far more relevant to a match played today than one from months ago. The weight of a finding is the sum of a base value that depends on the type of match and a recency term r(Δt):
| Approx. last execution | r(Δt) | Strength (exact / fuzzy) | w exact | w fuzzy |
|---|---|---|---|---|
| Within 24 hours | 40 | Strong / Medium | 1040 | 70 |
| Within 7 days | 25 | Medium / Medium | 1025 | 55 |
| Older | 10 | Medium / Weak | 1010 | 40 |
| Timestamp unavailable | 5 | Medium / Weak | 1005 | 35 |
BAM. The Background Activity Moderator service records, per user, the full path of executables and their last execution time in the registry. It survives deletion of the executable and gives a full path, which helps reviewers. MUICache stores the display names of programs the user has run. AmCache and ShimCache are compatibility databases that record programs present on or executed by the system; their exact semantics depend on the Windows version [5]. AACGUARD uses all five sources for the same test (exact or fuzzy cheat-name match, Section 6), because each can survive a clean-up that misses the others.
5.2File system and persistence
The AppData, Downloads and Desktop checks look for files with cheat-like names and, if configured, compare hashes against known cheat binaries. The Downloads and Desktop check also looks for generic loader and injector patterns. The Recycle Bin check parses the metadata of deleted items, so it recovers the original path and the deletion time; the time of the most recent deletion is always logged, because deleting shortly before a scan is informative. The Run keys check examines autostart entries. The shortcut check resolves each .lnk file and weights it by what it points to (Table 4).
| Shortcut name | Target | Strength | w |
|---|---|---|---|
| Exact cheat name | Executable or cheat archive | Strong | 1000 |
| Exact cheat name | Other file | Medium | 30 |
| Exact cheat name | Unresolved | Medium | 20 |
| Any | Cheat-like executable | Medium | 25 |
| Any | Cheat-like archive | Medium | 15 |
| Cheat-like name | Other file | Weak | 5 |
| Cheat-like name | Unresolved | Weak | 3 |
5.3Removable media
Keeping cheat files on a USB stick is a common way to avoid leaving them on the system drive. The USB check lists storage devices recorded in the registry with their last connection time, and scans any currently connected removable drive for recent executables. Only files active in the last 24 hours are considered, and weights include a recency term of 20 (last 15 minutes), 15 (last 2 hours) or 10 (older). Findings on removable media carry high base weights (250 for an exact name, 500 for a hash match), because a cheat binary on a portable drive is strong evidence of intent.
5.4Browser history
The browser check locates the history databases of Chromium- and Firefox-based browsers, including backup copies and Microsoft Store builds, and queries them read-only. It reports visits to known cheat sites (Medium, 50) and cheat-related searches (Weak, 20). When both kinds of signal appear in the same browser, it adds a combined finding (Strong, 60). The list of browsers found is stored with the scan.
5.5Game configuration files
Counter-Strike configuration files are plain text. The CFG check collects non-default .cfg files from the game and Steam userdata folders, compares their names with a list of default files shipped with the game, and searches them for cheat names (Medium, 25), cheat-related keywords (Weak, 10) and settings typical of “HvH” (hack-versus-hack) play (Medium, 20). The files are uploaded with the scan so a reviewer can read them.
5.6Environment: virtualization and RAM disks
Some cheaters run cheats or their loaders inside virtual machines, or keep them on RAM disks that disappear at shutdown. The virtualization checks look for installed and running VM software, hardware markers such as a virtual baseboard manufacturer, VM entries in uninstall records, and VM-related installer events. The RAM-disk check looks for RAM drives, RAM-disk software and services, and system or browser paths redirected to a RAM disk. Most of these indicators are Weak (3–10), because VMs and RAM disks have many legitimate uses. Cheat files found on a RAM disk are scored like files elsewhere.
5.7Anti-forensics
The anti-forensics check detects trace-removal and cleaning tools. Its findings are recorded with a weight of zero: they increase the detection count D but not the score S. A cleaner is not evidence of cheating, but when it appears together with other findings it makes a pattern more credible (Section 7.2).
6Name matching
Most checks reduce to one question: does this file or process name refer to a known cheat? The remote configuration supplies a list of cheat names C and a list of exact names E. At scan start the engine expands C into E by adding the .exe and .dll forms of every name. Names are normalised (lower case, forward slashes turned into backslashes, whitespace trimmed) before comparison.
_, -, ., space, \}.The delimiter rule keeps short tokens from matching inside unrelated words, which a plain substring test would do. Table 5 illustrates it with a fictitious cheat token aimx.
| Normalised name | Exact | Fuzzy | Reason |
|---|---|---|---|
aimx.exe | Yes | Yes | In expanded exact list |
aimx_loader.exe | No | Yes | Prefix |
tools\aimx | No | Yes | Suffix, preceded by \ |
claimxyz.exe | No | No | Token inside a word, no delimiter |
gaimx.dll | No | Yes | Token followed by . (a known source of false positives) |
The last row shows the rule's weak point: a token followed by the extension dot matches even when a letter precedes it. This is one reason fuzzy matches carry low weights, and one reason whitelist substrings are applied before matching.
7Evidence scoring model
Every finding i has a strength si ∈ {Weak, Medium, Strong} and a weight wi ≥ 0. The engine keeps the score S and the detection count D:
The verdict function V(S, D) is:
if (_metrics.Score >= 999) FinalStatus = "CHEAT DETECTED"; else if (_metrics.Score >= 300 && _metrics.TotalDetections >= 5) FinalStatus = "CHEAT DETECTED"; else if (_metrics.Score >= 150 && _metrics.TotalDetections > 2) FinalStatus = "SUSPICIOUS"; else FinalStatus = "CLEAN";
7.1Weight classes
The weights in Appendix A fall into four classes (Figure 4). Exact-name hits in execution history, persistence and file locations carry 1000 and decide the verdict alone. Hash and removable-media hits carry 30–520. Heuristic hits carry 10–70, and environmental indicators 3–10. The gap of more than an order of magnitude between classes is intentional: no realistic number of environmental indicators adds up to a decisive finding.
7.2Properties of the decision rule
Monotonicity. Because all weights are non-negative, adding a finding never lowers S or D, and V is monotone in both. A player cannot improve a verdict by producing extra findings.
Decisive findings. Every finding with w ≥ 999 produces CHEAT DETECTED regardless of D. These are reserved for exact matches in places where a legitimate program with that name is implausible.
Corroboration. Without a decisive finding, CHEAT DETECTED needs at least five findings and 300 points. Since heuristic weights are at most 70, at least five independent heuristic hits are needed, which is the property that protects against single noisy checks. SUSPICIOUS needs three findings and 150 points.
Zero-weight findings. Anti-forensic findings raise D without raising S. Two such findings plus one Strong heuristic hit of 150 points or more would be SUSPICIOUS, while the same hit alone would be CLEAN. This lets context make a pattern more credible without ever creating a score.
Up to v0.0.9 the connected server was also registered as a Weak finding worth 5 points. It raised D for every connected player and could satisfy the D ≥ 3 condition on its own together with two unrelated findings. From v0.0.10 the server is metadata and not a finding.
8Game identification
The client enumerates processes once at scan start and classifies them (Table 6). If several games are running, a fixed priority selects one, Counter-Strike titles first. The chosen process ID is kept, so the engine can later tell whether the game exited during the scan, which the report flags.
| Priority | Game | Process image | Disambiguation |
|---|---|---|---|
| 1 | Counter-Strike 2 | cs2.exe | None needed |
| 2 | CS:GO | csgo.exe | None needed |
| 3 | CS 1.6 | hl.exe, cstrike.exe | Window title, install path, or -game cstrike argument |
| 4 | FiveM | FiveM_*GTAProcess.exe | Build suffix ignored |
| 5 | Roblox | RobloxPlayerBeta.exe | Store build identified by window title |
| 6 | Minecraft (Java / Bedrock) | javaw.exe, Minecraft.Windows.exe | Java: window title or launch arguments |
private static bool IsCs16Hl(Process p) { if (SafeTitle(p).Contains("counter-strike", OrdinalIgnoreCase)) return true; // ... install path check ... string cmd = GetCommandLine(p.Id); // WMI Win32_Process return cmd.Contains("cstrike", OrdinalIgnoreCase) || cmd.Length == 0; }
Module and memory inspection (Section 10) is restricted to Counter-Strike titles. The Java virtual machine and FiveM's JavaScript engine compile code at run time into private executable memory, and Minecraft extracts native libraries to the temporary folder. Applying the same heuristics to those games would mostly produce noise.
9Server attribution
Administrators want to know which server a player was on at scan time, ideally by domain name (e.g. go.mortall.ro). Counter-Strike clients talk to servers over UDP, which has no connection state. So the Windows socket table [10] lists the game's local UDP port but not the remote peer. The v0.0.9 approach read the TCP table instead, which lists Steam's service connections, and in practice returned the wrong address. It also declared the UDP row with two fields that do not exist in the owner-PID row format, which misaligned every entry.
9.1Passive endpoint observation
The client asks Windows for the UDP ports the game process owns, then opens a raw IPv4 socket in receive-all mode [11] on each active interface for up to 3 s. For each UDP datagram it examines only the IP and UDP headers. If the destination port is a game port, the source is a candidate; if the source port is a game port, the destination is. Private, loopback, link-local, carrier-grade NAT and multicast addresses are discarded. Observation stops early once one candidate reaches 40 packets, and the candidate with the most packets is chosen if it has at least 3. No payload is stored.
if (len < 28 || buf[9] != 17) continue; // IPv4 protocol 17 = UDP int ihl = (buf[0] & 0x0F) * 4; // IP header length var src = new IPAddress(buf.AsSpan(12, 4)); var dst = new IPAddress(buf.AsSpan(16, 4)); int sp = (buf[ihl] << 8) | buf[ihl + 1]; int dp = (buf[ihl + 2] << 8) | buf[ihl + 3]; if (gamePorts.Contains(dp) && !IsPrivate(src)) key = $"{src}:{sp}"; // inbound else if (gamePorts.Contains(sp) && !IsPrivate(dst)) key = $"{dst}:{dp}"; // outbound
9.2Name resolution and verification
The chosen endpoint is queried with A2S_INFO [13]. Newer servers answer with a 4-byte challenge (type 0x41), which the client appends to a second request. Source servers reply with type 0x49, where the name follows a protocol byte. GoldSrc servers reply with the older type 0x6D, where the name follows the server address. Community servers usually include their domain in the name, e.g. “[CS:GO] ★ GO.OLDISGOLD.RO ★ [COMPETITIVE] 128 TICK”. The client extracts every domain-shaped token and accepts one only if forward DNS resolution returns the observed IP address. This check stops a server from claiming someone else's domain. Without a verified domain, the stored value is the plain IP:port.
9.3Last-played server
Players often scan from the main menu. In that case the client reads Steam's server-browser history (serverbrowser_hist.vdf), which records each server's address and a LastPlayed Unix timestamp. It selects the most recent entry, resolves it as in Section 9.2, and stores it with a (last) suffix. The panel shows it with a LAST label, and a live observation with a LIVE label. When a scan carries no server, the panel falls back to the player's most recent known server from earlier scans, also labelled LAST.
| Situation | Stored value | Panel label |
|---|---|---|
| Connected, domain in name verified by DNS | go.example.ro | LIVE |
| Connected, no verifiable domain | 203.0.113.7:27015 | LIVE |
| In menu, Steam history available | go.example.ro (last) | LAST |
| No server on this scan, earlier scan has one | (unchanged) | LAST, from history |
| No information | empty | — |
10In-process and kernel inspection
10.1Running processes
Every running process name is tested for exact (Strong, 1000) and fuzzy (Strong, 30) cheat-name matches. A short built-in list of debuggers, memory editors, structure-reversing tools and injectors adds a Medium finding (25) when one is running during the scan.
10.2Module enumeration across bitness
The client is a 64-bit process, while CS:GO and CS 1.6 are 32-bit processes under WOW64 [12]. The .NET Process.Modules collection returns only the 64-bit WOW64 support modules of such a process, so the game's own 32-bit DLLs, where an injected cheat would be, were never examined before v0.0.10. The client now takes a Tool Help snapshot that requests both module classes [8].
// Includes 32-bit modules of WOW64 games (csgo.exe, hl.exe) IntPtr snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, (uint)pid); var me = new MODULEENTRY32W { dwSize = (uint)Marshal.SizeOf<MODULEENTRY32W>() }; if (Module32FirstW(snap, ref me)) do list.Add((me.szModule, me.szExePath, me.modBaseAddr, me.modBaseSize)); while (Module32NextW(snap, ref me));
Each module is then subjected to five ordered tests: cheat-like name (Strong, 45), configured name hint (Medium, 30), load location in a temporary, download, desktop or removable path outside the game folder (Medium, 25), missing backing file (Strong, 50) and known cheat hash (Strong, 60). A module is reported at most once per scan. Tests 1–4 are subject to the trust model of Section 11.
10.3Code without a backing image
A cheat DLL that is copied into the game's memory by hand, bypassing the system loader, appears in no module list. The injection check walks the game's address space with VirtualQueryEx and inspects every committed region that is private (not file-backed) and executable. If such a region begins with a valid PE header (MZ signature and a PE\0\0 signature at the offset given by e_lfanew), the check reports a Strong finding (60), because a complete program image was placed there manually. This mirrors the approach of memory-forensics tools [6], applied to the live process.
private static bool LooksLikePe(byte[] b) { if (b[0] != 'M' || b[1] != 'Z') return false; int e = BitConverter.ToInt32(b, 0x3C); // e_lfanew return e > 0 && e < b.Length - 4 && b[e] == 'P' && b[e + 1] == 'E' && b[e + 2] == 0 && b[e + 3] == 0; }
A pre-release build also flagged large read-write-execute regions without a header. The case study (Section 11) showed that ordinary CS:GO sessions contain such regions, so that heuristic was removed before release.
10.4Kernel drivers
Kernel-mode cheats are usually loaded through a legitimately signed but vulnerable driver, a technique documented by community projects that catalogue such drivers [14]. The driver check lists loaded drivers with EnumDeviceDrivers and compares their exact file names against two short lists: drivers of cheat and memory tools (Strong, 60), and drivers with known abuse histories that are rarely loaded on a gaming PC (Medium, 30). Exact comparison replaced substring matching after it produced accidental hits.
11False-positive mitigation
During testing, a pre-release build of v0.0.10 returned CHEAT DETECTED for a clean machine running CS:GO. Table 8 breaks the result down.
| Finding group | Hits | S before | S after | Cause |
|---|---|---|---|---|
| “Module has no file on disk” | 5 | 250 | 0 | GPU driver DLLs reported under a WOW64 path that does not exist |
| Large RWX regions | 1 | 15 | 0 | Heuristic removed (Section 10.3) |
| Browser history (1 site, 4 searches) | 5 | 130 | 130 | Unchanged; remote keyword list |
| Total | 11 → 5 | 395 | 130 | CHEAT DETECTED → CLEAN |
11.1WOW64 path translation
For a 32-bit process, Windows reports system paths under SysWOW64 [12]. The graphics driver store exists only under System32\DriverStore, so every GPU user-mode driver had a reported path that does not exist, failed the existence test and was scored as “no file on disk”. Paths are now translated back before testing.
if (File.Exists(path)) return path; string alt = path.Replace(@"\SysWOW64\", @"\System32\", OrdinalIgnoreCase); if (alt != path && File.Exists(alt)) return alt;
11.2Trust model
Games also load overlays, recorders, audio processing, peripheral software and antivirus hooks, which resemble injected code. Any module that a heuristic test would flag goes through three trust tests (Figure 7). Exact names, known hashes and the manual-mapping check are never suppressed.
- Windows directory. The file exists under the Windows directory (System32, SysWOW64, WinSxS, DriverStore), excluding
Windows\Temp. Writing there requires administrator rights. - Known module. The file name is on a curated list of about 250 components seen in the supported games (GPU drivers, overlays, capture tools, audio and peripheral software, security products, game runtimes), and the module is not in a temporary, download or desktop folder. Common proxy-DLL names such as
d3d9.dllanddxgi.dllare deliberately excluded, because cheats use them to disguise themselves. - Vendor signature. The file has a valid embedded Authenticode signature, verified with
WinVerifyTrust[9] (file hash and chain; revocation only from cache, no network access), and the signer is a known vendor. Results are cached per path for the scan.
The contents of the trust lists are not published, to avoid giving cheat authors a list of names and signers to imitate.
12The review platform
The public website at aacguard.com hosts the client download, documentation (features, changelog, trust centre, privacy, terms, cookies and GDPR pages), a list of partner servers and the review panel. The landing page shows live counters: at the time of writing, 11,181 scans completed, 3,658 players flagged and 52 new detections in the last 24 hours.
12.1Data model
Figure 8 shows the tables used by the panel. A scan belongs to a user, identified by Steam ID. Configuration files and the automated interpretation are stored in separate tables keyed by scan, and bans refer to users.
12.2Panel views
Detected players. A paginated, searchable list (by Steam name or ID) of scans, newest first, with player, Steam ID, game, server (LIVE/LAST, copyable), verdict, time and ban status. Scans made with clients older than 0.0.4 after February 2026 are excluded. A version comparison bug hid new scans and was fixed by comparing versions numerically instead of as text:
-- lexical comparison ranked '0.0.10' below '0.0.4' and hid all new scans AND INET_ATON(CONCAT(s.client_version, '.0')) >= INET_ATON('0.0.4.0')
Scan view. One page per scan with the player's Steam avatar (read from the public profile and cached for 24 hours), a link to the Steam profile, a copyable Steam ID, game and server, metrics, a plain-language summary generated from the log, per-check status, the collected configuration files with a viewer, the raw log, and the player's other scans.
Player lookup. Resolves a user name, SteamID64, legacy SteamID or profile link to a SteamID64 (via the Steam Web API's vanity-URL resolution where needed) and shows the Steam profile summary, VAC and game-ban status, and the player's AACGUARD scan history. Where configured, it adds public FACEIT statistics (level, Elo, K/D, win rate, headshot rate) and lifetime Counter-Strike statistics from the Steam API (K/D, accuracy, headshot rate, matches won).
12.3Automated interpretation
Each scan can receive an automated, language-model-based interpretation stored in scan_ai_analysis, with one of four verdicts (CLEAN, CHEATER, SUSPECT, IDK) and a short text. The panel labels it as a beta feature and warns that the model has no internet access and bases its reading only on the scan data. It is advisory: the scanner's own verdict (Eq. 3) is computed independently and is not changed by the interpretation.
12.4Time presentation
Timestamps are stored in UTC. The panel sends them as ISO-8601 values in <time> elements and converts them in the browser to each visitor's time zone, while the stored data stays unchanged. Without JavaScript the UTC value is shown with a label.
13Operational characteristics
We report the timing of the case-study scan from its log, which has a resolution of one second. The machine had six fixed drives (about 4.1 TB in total), three browsers and a running CS:GO client connected to a community server. The scan performed 188,830 individual checks and took 17 s from start to verdict (Table 9, Figure 9).
| Stage | Seconds |
|---|---|
| Prefetch, BAM, MUICache | < 1 |
| AppData | 11 |
| Recycle Bin, Downloads/Desktop | 1 |
| CS directory, USB | < 1 |
| Browser history | 1 |
| AmCache, ShimCache, Run keys | < 1 |
| Shortcuts | 2 |
| Processes, modules, server, injection | 1 |
| Environment, anti-forensics, CFG | 1 |
| Total | 17 |
Server attribution completed within the same second as module inspection: the early-stop condition was reached well before the 3-second capture limit on an active connection. The AppData stage dominates because it walks deep directory trees. It is the natural target for optimisation, for example by restricting depth or parallelising enumeration.
At the deployment level, 3,658 of 11,181 scans (32.7%) had been flagged, meaning a verdict other than CLEAN. Because players are usually asked to scan because they are suspected, this is not an estimate of cheating prevalence in the general population, and without ground truth it is not a measure of precision either.
14Privacy and ethics
A forensic scanner looks at personal data by nature, so AACGUARD follows data minimisation. The website states that the tool collects only what anti-cheat needs (Steam ID, Steam name, scan metadata, verdicts and game-related data such as non-default configs), runs only when the player presses Start or Restart, and does not run in the background. The download page states that scans are logged and associated with the player's Steam account for administrators to review. Table 10 summarises what is stored and how it is protected.
| Data | Purpose | Protection |
|---|---|---|
| Steam ID and name | Associate scans with a player | Public Steam identifiers only |
| Public IP address | Detect shared or duplicated identities | Stored masked |
| Scan log and file paths | Human review of findings | Windows user names masked as C:\Users\***\ on display |
| Game configuration files | Cheat-specific settings | Only Counter-Strike .cfg files |
| Browser findings | Evidence of acquisition | Only matching URLs are logged, not the full history |
| Connected server | Context for administrators | Public address or domain only |
| Network capture | Server attribution | Headers of the game's own UDP traffic, in memory, ≤ 3 s, nothing stored |
Two ethical risks deserve mention. First, a false CHEAT DETECTED verdict can lead to a ban and public listing. The design answers this with conservative thresholds, the trust model, full logs and a dispute process described on the website. Second, the public list of detected players names individuals, so listing should follow administrator review, not the automated verdict alone.
15Limitations and threats to validity
- No kernel visibility. A kernel-mode cheat can hide processes, modules and memory from any user-mode scanner. The driver check can show that a loader was used, not what it loaded.
- Point-in-time and clean-up. Live findings describe only the moment of the scan. Historical artifacts extend the window but can be cleared; the anti-forensics check makes some clearing visible, not all of it.
- List dependence. Exact and fuzzy matching depend on the quality of the remote name lists. A renamed private cheat is invisible to name matching and has to be caught by the location, hash, memory or driver checks.
- Fuzzy matching. The delimiter rule still produces false positives in some cases (Table 5), which is why fuzzy weights are low.
- Server attribution. Valve-hosted CS2 matches route traffic through relays [15], so the observed endpoint is a relay. Servers that disable A2S, or whose names contain no domain, are shown by address. Third-party firewalls may block raw capture; the
+connectfallback then applies. Non-Steam CS 1.6 clients have no Steam history. - Evaluation. The false-positive analysis is a single case study, and deployment counts are not labelled. We make no claims about precision or recall at scale. Stage timings come from one machine and a log with one-second resolution.
- Self-selection. Players scan at the request of administrators, so the scanned population is not representative of all players.
16Future work
- A labelled evaluation: collect reviewed outcomes for a sample of scans and report precision and recall per evidence source, then fit the weights to the data instead of setting them by hand.
- Per-game trust lists and extension of in-process inspection to FiveM with JIT-aware rules.
- Recency weighting, as used for Prefetch (Eq. 1), for all time-stamped sources (BAM, AmCache, Recycle Bin, USB).
- Faster file-system stages through bounded depth and parallel enumeration.
- Signed, integrity-checked reports so that the server can verify a report was produced by an unmodified client.
17Conclusion
AACGUARD shows that a user-mode scanner can give community-server administrators a structured and reviewable basis for moderation decisions. The scanner combines standard Windows forensic artifacts with live inspection of the game process, expresses every finding as weighted evidence, and uses a decision rule that requires either one decisive finding or several corroborating ones. Version 0.0.10 adds game and server context to every report, extends inspection to the 32-bit processes where Counter-Strike cheats run, and removes a class of false positives that could label clean players as cheaters, while keeping the verdict thresholds unchanged so that scores stay comparable with earlier reports. The main open problem is evaluation at scale, which requires labelled outcomes from administrator review.
AAppendix A: Detection catalogue
All findings the v0.0.10 client can register, with strength and weight w. Prefetch weights follow Eq. (1). “Exact” and “cheat-like” refer to Definitions 1 and 2. Anti-forensic findings have w = 0 by design.
| Source | Finding | Strength | w |
|---|---|---|---|
| Prefetch | Execution trace, exact name | Strong/Medium | 1005–1040 |
| Prefetch | Execution trace, cheat-like name | Medium/Weak | 35–70 |
| BAM | Execution trace, exact name | Strong | 1000 |
| BAM | Execution trace, cheat-like name | Medium | 20 |
| MUICache | Exact name | Strong | 1000 |
| MUICache | Cheat-like name | Weak | 8 |
| AmCache | Exact name | Strong | 1000 |
| AmCache | Cheat-like name | Medium | 20 |
| ShimCache | Exact name | Strong | 1000 |
| ShimCache | Cheat-like name | Medium | 20 |
| AppData | Exact cheat file | Strong | 1000 |
| AppData | Known cheat hash | Strong | 40 |
| AppData | Suspicious file | Medium | 10 |
| Downloads/Desktop | Exact cheat file | Strong | 1000 |
| Downloads/Desktop | Known cheat hash | Strong | 50 |
| Downloads/Desktop | Cheat-like file | Strong | 35 |
| Downloads/Desktop | Loader/injector-like file | Medium | 20 |
| Recycle Bin | Exact cheat file (deleted) | Strong | 1000 |
| Recycle Bin | Cheat-like file (deleted) | Medium | 20 |
| CS directory | Exact cheat-like module in game folder | Strong | 1000 |
| CS directory | Known cheat hash | Strong | 50 |
| CS directory | Potential injection module | Strong | 40 |
| USB | Recent executable, known cheat hash | Strong | 510–520 |
| USB | Recent executable, exact name | Strong | 260–270 |
| USB | Recent executable, cheat-like name | Medium/Weak | 35–45 |
| Browser | Cheat site and search in same browser | Strong | 60 |
| Browser | Cheat site visited | Medium | 50 |
| Browser | Cheat-related search | Weak | 20 |
| Run keys | Startup entry, exact name | Strong | 1000 |
| Run keys | Startup entry referencing cheat | Medium | 20 |
| Shortcuts | See Table 4 | — | 3–1000 |
| Processes | Exact cheat process | Strong | 1000 |
| Processes | Cheat-like process | Strong | 30 |
| Processes | Debug / memory tool running † | Medium | 25 |
| Modules | Known cheat hash | Strong | 60 |
| Modules | No backing file on disk | Strong | 50 |
| Modules | Cheat-like name | Strong | 45 |
| Modules | Suspicious name hint | Medium | 30 |
| Modules | Loaded from suspicious path | Medium | 25 |
| Injection † | Manually mapped PE image | Strong | 60 |
| Drivers † | Cheat/tool kernel driver | Strong | 60 |
| Drivers † | Driver abused by kernel loaders | Medium | 30 |
| CFG | Contains cheat name | Medium | 25 |
| CFG | HvH / rage settings | Medium | 20 |
| CFG | Cheat-related keyword | Weak | 10 |
| RAM disk | Exact cheat executable on RAM disk | Strong | 40 |
| RAM disk | Known cheat hash on RAM disk | Strong | 30 |
| RAM disk | Cheat-like executable on RAM disk | Medium | 20 |
| RAM disk | RAM drive present | Medium | 8 |
| RAM disk | TEMP or browser data on RAM disk | Weak | 4 |
| RAM disk | RAM-disk software (files, service, uninstall entry) | Weak | 3–4 |
| Virtualization | VM-related installer event | Medium | 10 |
| Virtualization | VM software, process, baseboard or uninstall entry | Weak | 5 |
| Anti-forensics | Cleaner / trace-removal tool | varies | 0 |
BAppendix B: Glossary
- A2S_INFO
- Valve's UDP query that returns a game server's name, map and player count [13].
- AmCache / ShimCache
- Windows compatibility databases that record programs present on or run by the system.
- BAM
- Background Activity Moderator; a Windows service whose registry data records executable paths and last-run times per user.
- External cheat
- A cheat running as its own process that reads or writes game memory.
- HvH
- “Hack versus hack”; servers or settings for players who openly use cheats against each other.
- Internal cheat
- A cheat running inside the game process, usually as an injected DLL.
- Manual mapping
- Loading a DLL by copying it into another process's memory without the system loader, so it does not appear in module lists.
- PE
- Portable Executable; the file format of Windows executables and DLLs.
- Prefetch
- Windows start-up optimisation files that also record which executables have run.
- Vulnerable driver
- A legitimately signed kernel driver with a flaw that lets user-mode code read or write kernel memory; used to load unsigned kernel cheats.
- WOW64
- The subsystem that runs 32-bit programs on 64-bit Windows, including file-system path redirection [12].
References
- J. Yan and B. Randell. A systematic classification of cheating in online games. In Proc. 4th ACM SIGCOMM Workshop on Network and System Support for Games (NetGames), 2005.
- C. Dorner and L. D. Klausner. If it looks like a rootkit and deceives like a rootkit: A critical examination of kernel-level anti-cheat systems. In Proc. 19th International Conference on Availability, Reliability and Security (ARES), 2024.
- S. Collins, A. Poulopoulos, M. Muench and T. Chothia. Anti-cheat: Attacks and the effectiveness of client-side defences. In Proc. ACM Workshop on Research on Offensive and Defensive Techniques in the Context of Man At The End (CheckMATE), 2024.
- H. Carvey. Windows Registry Forensics, 2nd ed. Syngress, 2016.
- B. Lagny. Analysis of the AmCache. ANSSI technical report, 2019.
- M. H. Ligh, A. Case, J. Levy and A. Walters. The Art of Memory Forensics. Wiley, 2014.
- P. Yosifovich, A. Ionescu, M. E. Russinovich and D. A. Solomon. Windows Internals, Part 1, 7th ed. Microsoft Press, 2017.
- Microsoft. CreateToolhelp32Snapshot function (tlhelp32.h). learn.microsoft.com
- Microsoft. WinVerifyTrust function (wintrust.h). learn.microsoft.com
- Microsoft. GetExtendedUdpTable function (iphlpapi.h). learn.microsoft.com
- Microsoft. SIO_RCVALL control code. learn.microsoft.com
- Microsoft. File System Redirector. learn.microsoft.com
- Valve Developer Community. Server queries. developer.valvesoftware.com/wiki/Server_queries
- LOLDrivers: Living Off The Land Drivers. loldrivers.io
- Valve. Steam Datagram Relay. Steamworks documentation. partner.steamgames.com
- AACGUARD. Project website, features, changelog and privacy policy. aacguard.com, accessed September 2026.