Anti-cheat tool reverse Srungoat Protector WebView2 + YARA Ships screenshots

Trace Anti-Cheat Scanner, Trace_7TXBS1AV.exe

A complete static reverse of the Trace Anti-Cheat scanner. Three-and-a-quarter megabytes of MSVC C++ wrapped in Srungoat Protector v1.0, whose entire contribution is a 61-byte badge in a section literally named .1337. Every string, every URL, every registry key, every YARA path, every Event Log query is in plaintext. Below: the complete C2 map (nine endpoints on traceac.cc), the injected WebView2 JavaScript that auto-fills the PIN input and auto-clicks the scan button, the seven finding categories the scanner emits, the twenty-two FiveM cheat brands it hunts, the sixty-three cheat-vendor auth panels it compares against browser history, the five hardcoded wevtutil XPath queries and the eight decoy JWTs plus seventeen fake auth-response templates it uses as trip-wires.

22 min read Published 2026-07-10 Static reverse + string forensic + protocol inference Third-party scanner
Prologue  ·  The unreverseable file

Let's begin.

Two people on the internet spent an afternoon reposting an AI hallucination that said our scanner was stealing browser tokens. Then, in the same breath, they promised the next release of Trace_7TXBS1AV.exe, their scanner, would be “unreverseable”. They had, they said, hired new devs. Their protection was final.

The file eventually arrived. Three-point-three-five megabytes, unsigned, with a manifest demanding administrative privileges and an executable section named .1337 that was sixty-one bytes long and contained, in plaintext, the literal words Protected by Srungoat Protector v1.0. That was the entire protection. No control-flow flattening. No section decryption. No TLS callback shell. No anti-debug beyond the same IsDebuggerPresent import every C++ template ships with. The badge was the shield.

The strings inside were not obfuscated. Not one. The scanner's own name for itself is the C++ namespace TraceScanner; its seven finding categories are stored as MSVC-mangled types, UActivityEntry, UAdminAppEntry, UFileFinding, UFiveMModEntry, UMemoryFinding, URegistryFinding, USystemFinding, visible to undname.exe and printed by any RTTI dump. Its C2 domain, traceac.cc, appears seven times in the binary as a wide-character constant, exactly as the compiler emitted it. The header on every outbound POST reads X-Trace-Scanner: TRACE-Scanner/QMSAPRSqM4xK2JnP. The download URL for its YARA binary is https://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN>, also in plaintext and it is verified against a SHA-256 that is itself a plaintext JSON field named sha256.

The WebView2 UI it renders is served from a remote page at https://scanner.traceac.cc/send/ui/. Into that page it injects, at load-time, a JavaScript block whose prefix is stored, in full, uncompressed, UTF-16-LE, starting at file offset 0x290E00 and whose suffix is stored at 0x290C00. Between them, the C++ concatenates the user's runtime PIN. Together they auto-fill the #pin-input field, dispatch an input event so React (or whatever) sees the change, wait for the #scan-btn to become enabled and click it. That is the whole authentication flow.

What follows is every string, every path, every field, every URL. Nine C2 endpoints. Twenty-two cheat brand names. Sixty-three cheat-vendor auth panels searched in the user's browser history. Seven forensic sources. Five hardcoded Windows Event Log XPath queries. Seventeen fake auth-response JSON templates the scanner uses to detect that a machine has been talking to cheat panels. Eight decoy JWTs. Every AV vendor it looks for. Every reverse-engineering tool it flags. Every VPN. Every hypervisor CPUID string. Every registry hive it walks.

The tool reads browser history, Event Logs, Prefetch, BAM, SRUM, Amcache and the Discord LevelDB store, takes a JPEG of the desktop with GDI+ and ships the lot as JSON to https://traceac.cc/api/scan/submit. Whether that qualifies as an infostealer is a definitional question. Whether the file is unreverseable is not.

— Every claim below is anchored to a byte-offset, a section, or a wide-string reference in the sample's .rdata. Nothing here is inference where a plaintext string wasn't there to read.

Executive summary

File size
3.19 MB
Protector
Srungoat v1.0
C2
traceac.cc
Strings encrypted
0 / 6,577
  • Third-party FiveM anti-cheat retroactive-trace scanner. Internal namespace is TraceScanner. Public brand is traceac.cc (“Trace Anti-Cheat”). Requires local administrator. Users get a PIN via the vendor's website; the scanner validates and consumes it against scanner.traceac.cc URL parameters (?pin=<PIN>).
  • Srungoat Protector v1.0 is decorative. No section encryption, no TLS callback, no anti-debug of substance, no runtime string decoder. The .1337 section contains 61 bytes: SRUNGOATPROT\\xde\\xad\\xbe\\xef v1.0\\0Protected by Srungoat Protector v1.0. Strings appear in plaintext at multiple encodings.
  • Nine hardcoded C2 endpoints on traceac.cc / scanner.traceac.cc. Fixed User-Agent TraceScanner and header X-Trace-Scanner: TRACE-Scanner/QMSAPRSqM4xK2JnP. All bodies are JSON (nlohmann::json v3.11.3, git 961c151d2e87f2686a955a9be24d316f1362bf21).
  • Downloads YARA at runtime. Fetches yara64.exe from its own CDN with SHA-256 verification against a manifest JSON, drops it under %APPDATA%\\trace, writes rules text to custom_rules.yar, executes the CLI (-w -m --scan-list).
  • WebView2 UI is remote-hosted at scanner.traceac.cc/send/ui/. A hardcoded JavaScript prefix + runtime PIN + hardcoded JS suffix is injected as a script into the page; it auto-fills the PIN and auto-clicks the scan button. The full prefix and suffix are quoted verbatim in section § WebView2 UI + injected JS.
  • Captures a JPEG desktop screenshot with GDI+ and includes it in the POST /api/scan/submit body. The visible copy inside the binary reads [*] Capturing desktop screenshot... and, on failure, [-] JPEG encoder not found.
  • No embedded secrets. No Discord webhook, no Telegram bot token, no Slack hook, no X.509 certificate, no RSA/AES key material, no high-entropy blob larger than 4 KB anywhere in .rdata or .data. Everything routes through the fixed traceac.cc hosts.
  • Kills cmd.exe and powershell.exe before submission via taskkill /f /im cmd.exe >nul 2>&1 and the same for PowerShell. This is a hardcoded self-hygiene step, not a defensive one against user tampering.
  • Watches for four environment variables: PIN, YARA, SELF_SCAN and TRACE_YARA_VALIDATION_FILE. Single-instance mutex is Global\\TraceAntiCheatScanner_Mutex.

On the “unreverseable” claim

The vendors of this scanner publicly stated, at the time this build was released, that they had hired new developers and that their protection was unreverseable. The claim is stated here without paraphrasing because the file itself refutes it in a specific and measurable way:

  • Srungoat Protector v1.0 is a marker, not a transform. It contributes exactly 61 bytes of text in a section named .1337. The bytes read: 53 52 55 4E 47 4F 41 54 50 52 4F 54 DE AD BE EF 76 31 2E 30 00 00 00 00 50 72 6F 74 65 63 74 65 64 20 62 79 20 53 72 75 6E 67 6F 61 74 20 50 72 6F 74 65 63 74 6F 72 20 76 31 2E 30 00 (“SRUNGOATPROT…v1.0…Protected by Srungoat Protector v1.0”). The rest of the binary is the compiler's output verbatim.
  • No section is encrypted. Entropy scans of every 4 KB window in .rdata and .data yield zero windows above 7.5 bits/byte, the threshold below which content is not compressed or encrypted. The strings the scanner uses to identify itself, its C2, its user-agent, its endpoints, its cheat-brand watchlist and every one of its 22 cheat family names is stored in plaintext at either UTF-8 or UTF-16-LE.
  • No TLS callback is registered. The Thread Local Storage directory's AddressOfCallBacks pointer resolves to a table whose first entry is NULL. There is no pre-main shim to unwrap. Entry-point at 0x140266520 jumps straight to the MSVC CRT's __scrt_common_main_seh.
  • No control-flow flattening, no opaque predicates. Disassembly of the WinHttp call chains at 0x1400CF920, 0x1400B9C90 and 0x1401ED500 reads as standard MSVC WinHttpOpen → WinHttpConnect → WinHttpOpenRequest → WinHttpSendRequest boilerplate with no interposed junk instructions.
  • No anti-debug beyond three imports. The binary imports IsDebuggerPresent, CheckRemoteDebuggerPresent, and OutputDebugStringA/W. None of them is called in a loop or timed; none checks the PEB's NtGlobalFlag; none uses NtQueryInformationProcess(ProcessDebugPort). The imports are here because MSVC's CRT references them.
  • No PE header wipe, no IAT hiding, no FNV-1a API resolution. The Import Address Table lists 36 imports from USER32, 40 from ADVAPI32, 186 from MSVCP140, and every other import in the clear.

A binary that ships with all of the above is not, in any operational sense, protected. The claim of un-reverse-engineerability describes a build state that does not exist in the file that was released. What follows is what the file actually contains, extracted with pefile, strings -eL and half a page of Python.

File identity

Original nameTrace_7TXBS1AV.exe
TypePE32+ EXE (x64, GUI)
Size3.19 MB (3,345,920 bytes)
ImageBase0x140000000
Entry RVA0x266520
Compile time2026-06-25 19:21:28 UTC (real)
Sections.text · .rdata · .data · .pdata · .1337 · .rsrc · .reloc
MD537644acaf1725dcf01b8c0b9227ca111
SHA-15c40f76fc4b25c00f60970bb17dae9e16f9f45a1
SHA-2569d1b210b06d942863e49f0cf7baf629fcdc3cf76d33a5383a6caec65783eb4fc
AuthenticodeUnsigned (Security dir size = 0)
ManifestrequestedExecutionLevel level='requireAdministrator' uiAccess='false'
Class nameTraceAntiCheatScannerClass
Single-instance mutexGlobal\TraceAntiCheatScanner_Mutex
ProtectorSrungoat Protector v1.0 (marker-only .1337 section)
RuntimeMSVC (MSVCP140 · 186 imports), WebView2, nlohmann::json v3.11.3, GDI+

Srungoat Protector v1.0

The scanner is wrapped by a commodity protector that has left a marker section and nothing else. The .1337 section is 61 virtual bytes, entropy 1.01, well below the level of even compressed text. Its raw contents:

Offset (raw)  : 0x00302000
Size (virtual): 0x3d bytes
Entropy       : 1.01 bits/byte

00: 53 52 55 4E 47 4F 41 54  50 52 4F 54 DE AD BE EF   SRUNGOATPROT.....
10: 76 31 2E 30 00 00 00 00  50 72 6F 74 65 63 74 65   v1.0....Protecte
20: 64 20 62 79 20 53 72 75  6E 67 6F 61 74 20 50 72   d by Srungoat Pr
30: 6F 74 65 63 74 6F 72 20  76 31 2E 30 00            otector v1.0.

That is the full protection. Every other byte of executable code was emitted by MSVC unmodified. TLS callback table is empty; entry point at 0x140266520 is a stock CRT initialiser; strings live in .rdata at both UTF-8 and UTF-16-LE and are readable with any triage tool.

C2 map, everything talks to traceac.cc

Nine URLs. Two hostnames (traceac.cc for API, scanner.traceac.cc for downloads and UI). Every wide-character copy of these strings is emitted verbatim by the linker, no obfuscation, no runtime assembly. Auth is the ?pin=<PIN> query parameter on GETs plus a static header X-Trace-Scanner: TRACE-Scanner/QMSAPRSqM4xK2JnP on POSTs.

VerbURLPurpose
GEThttps://traceac.cc/api/versionversion check (UA = 'blablublewidfjhsfhdshGFDSBSDUFGDFDSBNTRACE', placeholder)
GEThttps://scanner.traceac.cc/api/scanner/yara_manifest?pin=<PIN>YARA manifest JSON (url + sha256 + min_size)
GEThttps://scanner.traceac.cc/api/scanner/yara_rules?pin=<PIN>YARA rules text
GEThttps://scanner.traceac.cc/api/scanner/rules?pin=<PIN>rules dispatch
GEThttps://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN>YARA CLI binary; SHA-256 verified against manifest before execution
POSThttps://traceac.cc/api/scan/progresslive progress updates during scan
POSThttps://traceac.cc/api/scan/submitfindings JSON + JPEG screenshot
POSThttps://traceac.cc/api/scan/closedfinalize scan session
POSThttps://traceac.cc/api/download/validatePIN validation ping, body {"pin":"<PIN>"}, sent 5× during scan flow
UIhttps://scanner.traceac.cc/send/ui/WebView2 UI host (WebResourceRequested filter = https://scanner.traceac.cc/*)
Fixed header pair on every outbound request:
User-Agent: TraceScanner
Content-Type: application/json
X-Trace-Scanner: TRACE-Scanner/QMSAPRSqM4xK2JnP

# (except the /api/version ping, which uses a placeholder UA:)
User-Agent: blablublewidfjhsfhdshGFDSBSDUFGDFDSBNTRACE

WebView2 UI + injected JavaScript

The scanner renders its UI by embedding a Microsoft Edge WebView2 controller and navigating it to https://scanner.traceac.cc/send/ui/. A resource-request filter of https://scanner.traceac.cc/* permits fetches to that host and blocks everything else. On NavigationCompleted the C++ side calls ExecuteScript with a script built as three concatenated pieces: the constant prefix stored at .rdata:0x290E00, the user's runtime PIN and the constant suffix stored at .rdata:0x290C00. The prefix and suffix are quoted here verbatim from the binary:

// prefix, .rdata offset 0x290E00 (UTF-16-LE, constant)
(function() {
    function waitForElement(selector, callback, maxWait, interval) {
        maxWait = maxWait || 3000;
        interval = interval || 50;
        const start = Date.now();
        const check = setInterval(function() {
            const element = document.querySelector(selector);
            if (element) {
                clearInterval(check);
                callback(element);
            } else if (Date.now() - start > maxWait) {
                clearInterval(check);
                console.warn('Element not found: ' + selector);
            }
        }, interval);
    }
    waitForElement('#pin-input', function(pinInput) {
        pinInput.value = '<RUNTIME_PIN>

// suffix — .rdata offset 0x290C00 (UTF-16-LE, constant)
';
        pinInput.dispatchEvent(new Event('input', { bubbles: true }));
        waitForElement('#scan-btn', function(scanBtn) {
            if (!scanBtn.classList.contains('disabled')) {
                scanBtn.click();
            }
        });
    });
})();

The full set of state / event names passed between the WebView2 UI and the native side (via WebMessageReceived):

opentypestart_scanpinscan_errorSELF_SCANmessageclose_afterpin_validatedcheck_security_before_consenthas_security_toolssecurity_blockeddefender_realtime_enableddefender_service_runningantivirus_processesthird_party_antivirus_processesantivirus_blockedsecurity_clearantivirus_clearstart_scan_consentedtos_acceptedprivacy_accepteddrag_windowclose_appmin_appwindow_restoredscan_progressscan_doneprogressresultverdictseverityreasoncategorysysmain_enableddiagtrack_enabledsecure_boot_enabledis_signedis_live

Auth flow, PIN + fixed header

Users obtain a numeric PIN from the vendor's website and paste it into the UI (or receive it via the PIN environment variable). All GET requests to scanner.traceac.cc append ?pin=<PIN>to the URL and on failure the UI is told scan_error = "Invalid, expired, or used PIN.". The consent chain before any scan can start is:

  1. tos_accepted and privacy_accepted must both be true
  2. check_security_before_consent, inventory Defender + third-party AV
  3. if has_security_tools, display “Disable the blocking protection temporarily, then reopen the scanner” and set state security_blocked / antivirus_blocked
  4. pin_validated, HTTP validation against traceac.cc
  5. start_scan_consented, user pressed the button (or the injected JS pressed it for them)

YARA download chain

The scanner does not carry a YARA engine. It downloads one, at runtime, from its own CDN. The chain is:

  1. Read PIN from UI / PIN env var.
  2. GET https://scanner.traceac.cc/api/scanner/yara_manifest?pin=<PIN>, server returns a JSON with fields url, sha256, min_size. Manifest failures produce the strings YARA manifest HTTP failed, YARA manifest URL rejected, YARA manifest SHA256 is invalid, or YARA manifest JSON parse failed, all present verbatim in .rdata.
  3. GET https://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN>, download and SHA-256 verify against the manifest.
  4. GET https://scanner.traceac.cc/api/scanner/yara_rules?pin=<PIN>, download rules text; write to %APPDATA%\\trace\\custom_rules.yar.
  5. Validate rules with the downloaded binary: yara64.exe -w -m --scan-list. Emit output to TRACE_YARA_VALIDATION_FILE.
  6. Run YARA against the enumerated file list; every hit is turned into a UMemoryFinding or UFileFinding.

Directory exclusions embedded in the binary (fed to YARA's --scan-list): windows, program files, program files (x86), programdata, $windows.~bt, $windows.~ws, $recycle.bin, system volume information, recovery, perflogs.

Scan orchestration, 7 finding types

The C++ side runs its scan tasks via std::async / PPL and emits one of seven finding-vector types back to the UI. Each is a fully-mangled MSVC namespace visible with undname.exe, ?$vector@U<Type>@TraceScanner@@V?$allocator@U<Type>@TraceScanner@@@std@@@std@@.

Vector typeWhat it holds
UActivityEntrybrowser typed URLs, execution history, recent-activity artefacts
UAdminAppEntryapplications launched with elevated tokens (Security EventID 4688 + TokenElevationType %%1936 / %%1937)
UFileFindingcheat / injector / spoofer files on disk
UFiveMModEntrymods/plugins under \FiveM\FiveM.app\{mods,plugins,citizen\common\data,data}
UMemoryFindingYARA memory-scan hits against live processes
URegistryFindingcheat / VPN / VM / secure-boot registry markers
USystemFindinghypervisor CPUID, DeviceGuard/HVCI state, SecureBoot state, Defender/AV posture

The console-style status lines printed to the WebView2 UI during scanning are also embedded verbatim: [*] Scanning FiveM mods... · [*] Scanning admin-executed applications (Event Log 4688)... · [*] Scanning all services for unsigned kernel drivers... · [*] Scanning for newly installed drivers (Event Log 7045)... · [*] Scanning recent computer activity (BAM full dump)... · [*] Capturing desktop screenshot... · [*] Submitting.

Complete cheat family inventory (22)

Every FiveM cheat brand that the scanner searches for by file name. Each brand is checked in up to four variants, <name>.exe, <name>.dll, <name>menu.exe, <name>menu.dll, plus its known driver and registry markers.

2Take1AbsoluteBrutanCheraxCobra (cobrafree, cobraloader)Crystal (crystalunban)Desudo (+ desudoclient)DisturbedDopamineEulen (+ eulen_loader, eulenclient, C:\Windows\eulen_hwid.ini)FalloutFalcon / RedEngine (falcon.sys, HKLM\Services\FalconDriver, falcon.redengine.eu)Hammafia (+ hammafiaclient)HydroImpulseKeyser (keyser_core.dll in C:\Windows\Temp)LumiaLynxMaestroMidnightOzarkParagonPhantom / PhantomXReaperRobustSkript (+ skriptclient, skriptgg, skriptloader)StandSurgeSusano (susano.sys, api.susano.cc, HKLM\Services\susano)tiagomodzhostXenos / Xenos64 (DLL injector)

Injector / loader / bypass tools

extremeinjector.exeghinjector.exeinjector.exekdmapper.exemanualmapper.exemapper.exetdloader.exetdfree.exetdpremium.exeprocesshacker.execheatengine.execheatengine-x86_64.execobraloader.exe

HWID / spoofer / cleaner tools

hwid_changer.exehwid_clean.exehwid_get.exehwid_reset.exe/.dllhwid_spoof.exe/.dllmac_changer.exeserial_changer.exespoofer.exe/.dllbrowser_loader.exechrome_loader.exeedge_loader.exefirefox_loader.exeloader.exeloader_prod.exe

Cheat-vendor auth URLs (63), browser-history matches

The scanner reads typed-URL history from every installed Chromium browser and compares each entry against a list of 63 hardcoded cheat-vendor authentication panels. A hit becomes an UActivityEntry with severity suspicious. The full list, in the order it appears in .rdata:

https://api.cryptauth.net/v2/verify?key=
https://api.fluxauth.net/v2/validate?token=
https://api.secureauth.net/v2/auth?license=
https://auth-guard.cc/api/v1/session?hwid=
https://auth-panel.com/api/v2/init?ver=
https://auth-protect.com/panel/validate?token=
https://auth-secure.net/api/v2/check?license=
https://auth-service.net/api/check?hwid=
https://auth-system.io/api/v3/verify?key=
https://auth.cryptauth.io/v1/session?token=
https://auth.fluxauth.io/v1/verify?license=
https://auth.secureauth.cc/v1/validate?token=
https://authifly.cc/panel/customer?id=
https://authifly.co/dashboard?session=
https://authifly.com/api/v1/check?license=
https://authifly.net/api/validate?token=
https://crypt-auth.com/panel/user?license=
https://cryptauth.cc/dashboard?session=
https://cryptauth.com/api/v3/check?uid=
https://cryptauth.io/api/validate?license=
https://cryptauth.net/panel/admin?token=
https://cryptauth.org/api/v2/init?auth=
https://flux-auth.com/api/v3/init?session=
https://fluxauth.cc/panel/reseller?user=
https://fluxauth.com/api/check?key=
https://fluxauth.io/api/session?auth=
https://fluxauth.net/api/verify?hwid=
https://fluxauth.org/dashboard/user?id=
https://guard-system.com/panel/auth?id=
https://guard.secure.cc/api/v2/check?hwid=
https://license-api.com/v1/verify?key=
https://license-guard.com/panel/verify?key=
https://license-system.net/api/v2/validate?key=
https://license-verify.com/api/auth?key=
https://license.auth.io/v3/verify?hwid=
https://license.protection.cc/v2/check?id=
https://license.secure.com/api/check?token=
https://license.shield.io/api/v3/validate?hwid=
https://licensing.pro/api/v1/check?session=
https://panel.cryptauth.com/admin/check?hwid=
https://panel.fluxauth.com/admin/check?key=
https://panel.secureauth.com/admin/verify?key=
https://protect-auth.com/api/v1/verify?key=
https://protect.license.io/v1/auth?session=
https://protection-api.com/v2/verify?license=
https://protection.cc/api/v2/validate?token=
https://secure-auth.com/api/v1/check?token=
https://secure-license.net/api/validate?token=
https://secure.auth-api.com/v3/check?hwid=
https://secure.cryptauth.cc/api/v3/validate?id=
https://secure.fluxauth.net/api/check?hwid=
https://secureauth.cc/panel/validate?hwid=
https://secureauth.cloud/api/v2/init?session=
https://secureauth.io/api/v3/session?id=
https://secureauth.win/api/v2/verify?key=
https://security-auth.com/panel/user?key=
https://security-guard.io/api/v1/session?key=
https://security.shield.com/api/v3/verify?key=
https://shield-auth.net/api/v3/check?hwid=
https://shield.auth-api.net/v3/validate?token=

Cheat-vendor hostnames (short form)

eulen.ccapi.eulen.ccapi.susano.ccapi.tzproject.comapi.hxsoftwares.comhxsoftwares.comtzproject.comfalcon.redengine.euban-bypass.comban-evade.netcfx-unban.netfivem-cleaner.comfivem-unban.comhwid-reset.comhwid-spoof.comhwid-spoofer.commac-changer.comserial-spoof.netspoofer-service.net

Forensic sources read

ArtifactLocation / detail
PrefetchC:\Windows\Prefetch, .pf files enumerated for execution artefacts
BAMHKLM\SYSTEM\CurrentControlSet\Services\bam\State\UserSettings, per-user execution timestamps
SRUDBC:\Windows\System32\sru\SRUDB.dat, per-hour process network activity (SRUM)
ShimCache / AppCompatCacheHKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache
AppCompat persistedSOFTWARE\...\AppCompatFlags\{Persisted,Store,Custom,InstalledSDB}
Image File Execution OptionsSOFTWARE\...\Image File Execution Options
USN JournalNTFS $UsnJrnl, file activity history
EventTranscriptC:\ProgramData\Microsoft\Diagnosis\EventTranscript
ETLLogsC:\ProgramData\Microsoft\Diagnosis\ETLLogs, Windows telemetry event traces
DiagTrackC:\ProgramData\Microsoft\Diagnosis\DownloadedSettings
USBSTORHKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR\, USB storage history
Clipboard History\Packages\Microsoft.Windows.ShellExperienceHost_cw5n1h2txyewy\LocalState, clipboard log
MuiCacheClasses\Local Settings\Software\Microsoft\Windows\Shell\MuiCache
TypedURLs / TypedURLsTimebrowser typed-URL history (matched vs cheat-vendor URL list)
TypedPathsSoftware\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths
Task SchedulerC:\Windows\System32\Tasks, task XML enumeration
Discord Local State\discord\Local Storage\leveldb, discord username extraction
SteamSoftware\Valve\Steam registry + \Steam\config\config.vdf + loginusers.vdf, SteamID

Cross-references: Discord username is read from the LevelDB store and matched against the SteamID and Steam username extracted from Software\\Valve\\Steam and the loginusers.vdf / config.vdf files. A match becomes an UActivityEntry with description "Same username used across platforms".

Event Log XPath queries (5 hardcoded)

Every Windows Event Log channel the scanner reads, with the exact XPath filter it emits to wevtutil. All are dropped verbatim into the binary, no runtime construction.

ChannelQueryPurpose
Security*[System[(EventID=4624 or EventID=4625)]]logon success + logon failure events (last 20)
Security*[System[(EventID=5152 or EventID=5156 or EventID=5157)]]Windows Filtering Platform packet allowed/blocked (network telemetry)
Security*[System[(EventID=4688)] and EventData[Data[@Name='TokenElevationType']='%%1937' or Data[@Name='TokenElevationType']='%%1936']]process creation events with elevated tokens (admin apps)
Application*[System[(EventID=7045)]]service installation (driver/service register)
Microsoft-Windows-DNS-Client/Operational*[System[(EventID=3008 or EventID=3010)]]DNS query completed / blocked
Microsoft-Windows-Sysmon/Operational*[System[(EventID=3)]]Sysmon network connection events
Microsoft-Windows-Sysmon/Operational*[System[(EventID=6)]]Sysmon driver-load events

AV / EDR presence detection

The scanner enumerates process names against a hardcoded AV/EDR list. If Defender real-time is enabled or any third-party AV process is running, the UI displays "PIN accepted, but active protection is blocking the scanner. Disable the blocking protection temporarily, then reopen the scanner." and the scan will not proceed. The list embedded in the binary:

VendorProcess names
Avastavastsvc.exe · avguard.exe · aswidsagent.exe
AVGavgnt.exe · avgsvc.exe · avguard.exe
Aviraavira.servicehost.exe · egui.exe · savservice.exe
Bitdefenderbdagent.exe · bdservicehost.exe · epsecurityservice.exe
BullGuardbullguard.exe
ESETekrn.exe · egui.exe · edevmon · eamonm
F-Securef-secure.exe · fsav32.exe
Kasperskyavp.exe · kavfs.exe
McAfeemcshield.exe · mfemms.exe
Malwarebytesmbamservice.exe · mbamtray.exe
Nortonnortonsecurity.exe · ns.exe · ccsvchst.exe
Pandapavfnsvr.exe · psanhost.exe · psuamain.exe
Sophossophoshealth.exe · savservice.exe
Webrootwrsa.exe
ZoneAlarmvsmon.exe · zatray.exe
Qihoo 360360tray.exe
Windows Defenderwindowsdefender / MsMpEng (registry + service state)

Reverse-engineering + analysis tool detection

Process names the scanner treats as evidence of an ongoing reversing session (turned into a USystemFinding with description "analysis or credential dumping"):

ida.exe / ida64.exeghidra.exex32dbg.exe / x64dbg.exeollydbg.exewindbg.exeimmunitydebugger.exehttpdebugger.exednspy.exe / dnspy-x86.exepestudio.exelordpe.exepetools.exeimportrec.exescylla.exewireshark.exedumpcap.exefiddler.execharles.exenetworktrafficview.exesniff_hit.exeprocesshacker.exeprocexp.exeprocmon.exeregmon.exefilemon.exeapimonitor.exesysanalyzer.exesysinspector.exeproc_analyzer.exexenos.exe / xenos64.exe (DLL injector)kdmapper.exe / manualmapper.exe (kernel driver mappers)cheatengine.exeautohotkey.exe / autoit3.exe

BYOVD driver watchlist

DriverNotes
capcom.sysCapcom vulnerable driver (arbitrary kernel R/W)
iqvw64e.sysIntel Network Adapter Diagnostic (BYOVD favourite)
gdrv.sysGIGABYTE tool driver (BYOVD)
dbk64.sysCheat Engine driver
kerb3961kernel.sysunclassified, suspicious name
fse.sysflagged
dbgmflagged as debug helper

The full driver-services enumeration (HKLM\\SYSTEM\\CurrentControlSet\\Services) is compared against a whitelist of ~200 canonical Windows drivers embedded in the binary; anything not in the whitelist and not signed by Microsoft becomes a URegistryFinding.

Decoy JWTs + fake auth-response templates

The scanner carries a corpus of well-known example JWTs (from RFC/documentation samples and cheat-panel boilerplate) plus seventeen fake auth-response JSON shapes. They are matched against browser cache and LocalStorage entries as trip-wires: any of these values found in a browser storage file indicates the machine has been interacting with a cheat vendor's licensing panel.

JWTs (8 embedded)

Base64URLDecoded
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9{"alg":"HS256","typ":"JWT"}
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9{"alg":"HS512","typ":"JWT"}
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9{"alg":"RS256","typ":"JWT"}
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9{"typ":"JWT","alg":"HS256"}
eyJ1c2VyIjoicHJlbWl1bSIsInBsYW4iOiJlbnRlcnByaXNlIiwiZXhwIjoxNzA5MjkzMDIxfQ{"user":"premium","plan":"enterprise","exp":1709293021}
eyJpZCI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiQWxpY2UiLCJhZG1pbiI6dHJ1ZX0{"id":"1234567890","name":"Alice","admin":true}
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ{"sub":"1234567890","name":"John Doe","iat":1516239022}
eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJzdXBlcnVzZXIiLCJwZXJtcyI6ImFsbCJ9{"sub":"admin","role":"superuser","perms":"all"}

JSON response templates (17 embedded)

{"success":true,"data":{"user":{"id":"","username":"","email":"","role":"premium"},"license":{"key":"","type":"lifetime","expires":"never"},"session":{"token":"","expires":"3600"},"hwid":""}}
{"success":false,"error":"Invalid license key","code":"AUTH001"}
{"success":0,"error":"Version outdated","required":"2.0.0"}
{"license":"active","plan":"premium","restrictions":{"ip_lock":true}}
{"auth":"granted","permissions":{"admin":true,"modify":true}}
{"security":{"integrity":"valid","tamper":"none","debug":"none","vm":"none"}}
{"protection":{"level":"maximum","encryption":"enabled","monitoring":"active"}}
{"valid":true,"type":"subscription","expires":"2025-01-01","features":[]}
{"verification":"success","level":"enterprise","modules":["premium","business"]}
{"check":{"memory":"clean","process":"verified","modules":"valid"}}
{"environment":{"secure":true,"trusted":true,"verified":true}}
{"status":"success","response":{"account":{"id":"","level":"vip","created":"2024-01-01"},"subscription":{"plan":"enterprise","features":["premium","priority"],"active":true},"security":{"2fa":true,"ip_lock":true}}}
{"result":"ok","auth":{"token":"","refresh":"","scope":"full","permissions":["read","write","admin"]},"user":{"verified":true,"status":"active"},"app":{"version":"1.0.0","build":"stable"}}
{"code":401,"error":"Unauthorized","details":"Invalid token"}
{"error":true,"code":403,"message":"Access denied","info":"IP blocked"}
{"status":"error","message":"Session expired","details":"Please login again"}
{"status":"failed","type":"security","message":"Tampering detected"}

Desktop screenshot capture

Before submitting, the scanner captures a full-desktop bitmap with GDI+, encodes it as a JPEG in memory, and includes the base64 payload in the JSON body posted to /api/scan/submit. Failure paths are visible in the binary as:

  • "[*] Capturing desktop screenshot..."
  • "[+] Screenshot captured (<bytes> bytes)"
  • "[-] Failed to encode screenshot."
  • "[-] Failed to initialize GDI+."
  • "[-] JPEG encoder not found."

Windows with the WDA_EXCLUDEFROMCAPTURE / WDA_MONITOR display-affinity flag are handled explicitly, the scanner logs [!] Stream-proof window detected! Bypassing... and attempts to capture them anyway by cloning the DC. This is the standard technique for defeating “stream-proof” cheat overlays.

Secrets, keys, webhooks, none present

An exhaustive scan for every shape of embedded credential returned zero results in each of the following categories:

  • Discord webhook URLs (discord.com/api/webhooks/, discordapp.com/api/webhooks/)
  • Slack, Zapier, Telegram bot tokens / URLs
  • AWS/GCP/Azure access keys (AKIA*, ASIA*, AGPA*, etc.)
  • PEM-encoded X.509 certificates or RSA/EC private keys
  • Cloudflare R2 SigV4 signing material
  • SMTP / mailto: destinations
  • High-entropy binary blobs > 4 KB in .rdata or .data (no encrypted regions)

The only tokenised strings the file contains are the eight decoy JWTs (all standard textbook examples), the fixed X-Trace-Scanner header value TRACE-Scanner/QMSAPRSqM4xK2JnP and 105 32-byte hex or base64 strings that on inspection are all MSVC template-instantiation hashes or C++ lambda IDs.

IOCs

File

SHA-2569d1b210b06d942863e49f0cf7baf629fcdc3cf76d33a5383a6caec65783eb4fc
SHA-15c40f76fc4b25c00f60970bb17dae9e16f9f45a1
MD537644acaf1725dcf01b8c0b9227ca111
Size3,345,920 bytes
Compile time2026-06-25 19:21:28 UTC
Authenticodeunsigned
Protector marker.1337 section, "Protected by Srungoat Protector v1.0"

Network

API hosttraceac.cc
Static / UI hostscanner.traceac.cc
User-Agent (POST)TraceScanner
User-Agent (version)blablublewidfjhsfhdshGFDSBSDUFGDFDSBNTRACE
Custom headerX-Trace-Scanner: TRACE-Scanner/QMSAPRSqM4xK2JnP
PIN transportquery parameter ?pin=<PIN> on GET
Body formatapplication/json (nlohmann::json v3.11.3)

Host

MutexGlobal\\TraceAntiCheatScanner_Mutex
Window classTraceAntiCheatScannerClass
Working directory%APPDATA%\\trace
Dropped filesyara64.exe · custom_rules.yar · yara_validate_<n> · trace_srudb_scan.dat · t_hist_<n>
Env vars watchedPIN · YARA · SELF_SCAN · TRACE_YARA_VALIDATION_FILE
Self-hygienetaskkill /f /im cmd.exe / powershell.exe

Detection guidance

Network

  • Alert on HTTPS requests carrying User-Agent: TraceScanner or the placeholder blablublewidfjhsfhdshGFDSBSDUFGDFDSBNTRACE. Both are stable across builds and unique to this family.
  • Alert on any request carrying X-Trace-Scanner: TRACE-Scanner/QMSAPRSqM4xK2JnP. The value is baked in as a UTF-16 constant.
  • Alert on any egress to traceac.cc or scanner.traceac.cc. Two hostnames, both dedicated to this scanner.
  • Alert on the URL path pattern /api/scanner/yara_manifest?pin=, /api/scanner/yara_rules?pin= and /static/bin/yara64.exe?pin=, all specific to this tool.

Host

  • Alert on the creation of the named mutex Global\\TraceAntiCheatScanner_Mutex or the window class TraceAntiCheatScannerClass.
  • Alert on drop of yara64.exe to %APPDATA%\\trace\\ followed by execution with argv -w -m --scan-list.
  • Watch for a process with requireAdministrator manifest that spawns a Microsoft Edge WebView2 controller and navigates to https://scanner.traceac.cc/.

YARA candidate rule

rule TraceAntiCheat_Scanner {
  meta:
    author      = "Clubhouse AC Research"
    description = "Third-party FiveM Trace Anti-Cheat scanner"
    reference   = "traceac.cc"
    hash_sha256 = "9d1b210b06d942863e49f0cf7baf629fcdc3cf76d33a5383a6caec65783eb4fc"
  strings:
    $marker    = "Protected by Srungoat Protector v1.0"
    $ua        = "TraceScanner" wide
    $ua2       = "blablublewidfjhsfhdshGFDSBSDUFGDFDSBNTRACE" wide
    $hdrname   = "X-Trace-Scanner" wide
    $hdrvalue  = "TRACE-Scanner/QMSAPRSqM4xK2JnP" wide
    $mutex     = "Global\\TraceAntiCheatScanner_Mutex" wide
    $wnd       = "TraceAntiCheatScannerClass" wide
    $ui        = "https://scanner.traceac.cc/send/ui/" wide
    $c2a       = "traceac.cc" wide
    $yaraep    = "/api/scanner/yara_manifest?pin=" wide
    $submit    = "/api/scan/submit" wide
  condition:
    uint16(0) == 0x5A4D and
    3 of them
}

Runtime capture attempt, fake C2 + LD_PRELOAD

Static extraction gave us the wire format for every endpoint, but not what a live request body actually contains once populated with real machine data. To grab that, we stood the binary up under Wine + Xvfb against a synthetic C2 and watched what it sent. The attempt reached the wire but stopped one step short of the payload and where it stopped is itself a finding.

Harness

  • Fresh WINEPREFIX on Wine 9.0, Xvfb :99 (1280×800×24).
  • A self-signed CA (CN=Trace-Fake-C2-CA) + leaf cert with SAN DNS:traceac.cc, DNS:scanner.traceac.cc, DNS:*.traceac.cc, EKU=serverAuth, KeyUsage=digitalSignature,keyEncipherment. The CA was imported into HKLM\\Software\\Microsoft\\SystemCertificates\\ROOT\\Certificates (and CA and AuthRoot for good measure) via a hand-built Blob registry value carrying property 0x14 (SHA-1) and 0x03 (encoded cert).
  • LD_PRELOAD=libdns.so intercepts getaddrinfo(3) and rewrites any hostname containing traceac.cc to 127.0.0.1. It also intercepts connect(2) and logs every TCP connect the scanner attempts.
  • A Python TLS server on 127.0.0.1:443 that accepts on a plain socket, logs the raw peer, does the ssl.wrap_socket handshake, logs the negotiated cipher, then reads and dumps every byte the client sends before replying with a synthetic version / manifest / yara-rules response.

What we captured

The DNS interposer fires, [libdns] getaddrinfo(traceac.cc) → 127.0.0.1 , and the binary connects to 127.0.0.1:443 with WinHTTP. Wine's Schannel completes the TLS 1.2 handshake against our CA (cipher ECDHE-RSA-AES256-GCM-SHA384, TLS 1.3 also negotiates cleanly when we allow it). And then, immediately after the handshake finishes, the client closes the connection without sending a single application byte:

[libdns] getaddrinfo(traceac.cc, ?) → 127.0.0.1
[libdns] connect(fd=240, 127.0.0.1:443)

# server side
[connect]     ('127.0.0.1', 43430)
[tls-ok]      ('127.0.0.1', 43430) cipher=('ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256)
[body]        ('127.0.0.1', 43430) len=0
[send-error]  ('127.0.0.1', 43430): EOF occurred in violation of protocol

To sanity-check the harness, a curl to the same URL with the CA trusted goes all the way through and delivers the synthetic response body untouched. So the TLS stack, DNS interposer and server are all correct. What differs is whatever Wine's WinHTTP does after the handshake and before dropping WinHttpSendRequest's bytes on the wire.

Why it stopped there, what it isn't

The behaviour reads like classical certificate pinning, but the binary's imports rule that out cleanly. The full WinHTTP import table is:

WINHTTP.dll:
  WinHttpOpen
  WinHttpConnect
  WinHttpSetOption
  WinHttpCrackUrl
  WinHttpQueryHeaders
  WinHttpReceiveResponse
  WinHttpSendRequest
  WinHttpOpenRequest
  WinHttpQueryDataAvailable
  WinHttpReadData
  WinHttpCloseHandle
  • No WinHttpSetStatusCallback, the binary cannot receive a WINHTTP_CALLBACK_STATUS_SENDING_REQUEST notification to inspect the server cert and cannot install a callback that closes the handle on mismatch.
  • No WinHttpQueryOption(WINHTTP_OPTION_SERVER_CERT_CONTEXT), a search for the immediate mov edx, 0x4E returns nothing in .text. The binary never pulls the peer cert into user code.
  • A scan for mov edx, 0x1F (WINHTTP_OPTION_SECURITY_FLAGS) matches once, inside CRT support code. There is no application-level SetOption on security flags either way — no SECURITY_FLAG_IGNORE_* and no explicit flag pinning.
  • WINTRUST is imported (WinVerifyTrust, CryptQueryObject, CertGetNameStringA, CertFindCertificateInStore), but only against downloaded files, the shape is Authenticode verification of the yara64.exe drop, not TLS peer pinning.

That leaves the closure at Wine's Schannel layer, not in the sample's code. Wine's Schannel accepts the handshake because the CA lives in the store, but the subsequent chain-build inside winhttp.dll before it hands the socket back to WinHttpSendRequest fails and WinHTTP quietly drops the handle. Under a real Windows Schannel with a real Windows-trusted CA, the same handshake would be followed by the actual GET /api/version HTTP/1.1, which is exactly what we see when we curl the endpoint with our CA installed system-wide.

What this confirms

  • The scanner really does dial out to traceac.cc the moment it comes up, unattended, before any UI action from the operator, the DNS/TCP hits are the first thing that happens after the mutex check.
  • All C2 traffic runs over WINHTTP_FLAG_SECURE (0x00800000 shows up as an immediate at the WinHttpOpenRequest call sites). There is no plaintext fallback, no HTTP retry.
  • Nothing extra rides in the SNI or TCP layer we couldn't already read out of .rdata: the connection is a stock WinHTTP call to traceac.cc:443, request path built from the wide-string constants documented in the C2 map above.
  • Cert validation happens in Wine, not in the binary, so a Windows host with a policy-installed CA and a route pointing traceac.cc at a local sink would capture the full /api/scan/submit body. The shape of that body is already documented from the static parser above (JSON with a pin, results[], duration, type, description, details, severity and a base64 screenshot field). Runtime just confirms the field names get filled with real content, not the schema itself.

Second pass, Wine says the actual failure reason

Re-running under WINEDEBUG=+winhttp,+schannel named the failure directly. Wine imports the CA into HKLM, negotiates TLS and then Wine's own netconn_verify_cert refuses to trust it:

trace:winhttp:WinHttpOpenRequest 0x2, L"GET", L"/api/version", (null), (null), 0, 0x800000
trace:winhttp:open_connection connecting to L"127.0.0.1":443
trace:winhttp:netconn_secure_connect sending 221 bytes
trace:winhttp:netconn_secure_connect recv 1275 bytes
trace:winhttp:netconn_secure_connect InitializeSecurityContext ret 0x90312
trace:winhttp:netconn_secure_connect sending 93 bytes
trace:winhttp:netconn_secure_connect recv 242 bytes
trace:winhttp:netconn_secure_connect InitializeSecurityContext ret 0
trace:winhttp:netconn_verify_cert verifying L"traceac.cc"
trace:winhttp:netconn_verify_cert returning 0x2f0d          # CERT_E_UNTRUSTEDROOT
warn:winhttp:netconn_secure_connect cert verify failed: 12045  # ERROR_WINHTTP_SECURE_INVALID_CA
warn:winhttp:netconn_secure_connect Failed to initialize security context: 0
trace:winhttp:netconn_release Closing connection

The blob we wrote to HKLM\\Software\\Microsoft\\SystemCertificates\\ROOT\\Certificates\\... is loaded by Wine's crypt32, but Wine's chain-build inside winhttp.dll still returns CERT_E_UNTRUSTEDROOT, a known gap between Wine's registry-loaded store and its internal trust anchor set. The failure lives in Wine, not in the scanner.

Third pass, patch WINHTTP_FLAG_SECURE out of the binary

With the TLS problem localised to Wine, we bypassed it by patching the scanner itself. Every WinHttpOpenRequest call site in .text pushes the flags argument as an inline immediate. Three matches for mov dword ptr [rsp+0x30], 0x00800000, file offsets 0xB916D, 0xCEDBD, and 0x24FDE7. Flipping the single byte at each site (offset +6, from 0x80 to 0x00) turns WINHTTP_FLAG_SECURE into a no-op. WinHTTP now dials plain HTTP to 127.0.0.1:443 and our fake C2 answers as HTTP.

On the very next run, the patched binary hit /api/version live — with the scanner's own placeholder user agent, cleanly delivered to our sink:

{
  "ts": 1783704379.113549,
  "method": "GET",
  "host": "traceac.cc",
  "path": "/api/version",
  "headers": {
    "User-Agent":  "blablublewidfjhsfhdshGFDSBSDUFGDFDSBNTRACE",
    "Host":        "traceac.cc",
    "Connection":  "Keep-Alive"
  },
  "body_len": 0
}

That UA is the exact wide-string constant that lives at file offset 0x28BB09 in .rdata. Nothing in the request is randomised, rotated, or environment-derived, it's a literal ROM string. The X-Trace-Scanner header does not appear on this endpoint (the header lives on the scanner's authenticated traffic only, /api/scan/* and /api/scanner/*). After our server answered {"success":true,"version":"1.4"}, the binary accepted the response and moved on to WebView2 environment creation, which fails under Wine (no WebView2 runtime), producing the “Failed to create WebView2 environment” dialog and stopping the scan flow before the PIN prompt and subsequent authenticated endpoints. To reach the scan-submit body we would need to either supply a WebView2 host to Wine or patch out the environment-creation path, both are out of scope for this write-up.

Fourth pass, full capture under Windows 10 in QEMU

To defeat both the Wine cert-chain failure and the Wine WebView2 gap, we skipped Wine entirely and booted a real Windows 10 Lite (Build 18363) guest under qemu-system-x86_64 in TCG mode (no KVM), 4 GB RAM, 4 vCPUs, -cpu Haswell-v4 (AVX/SSE4.2 needed by the WebView2 installer). Guest network is SLIRP; the host is 10.0.2.2 from inside the guest.

  • Installed MicrosoftEdgeWebView2Setup.exe (194 MB offline installer) and vc_redist.x64.exe (Win 10 Lite ships without VCRUNTIME140/MSVCP140). Added the fake CA to Windows trust with certutil -addstore -f Root.
  • Wrote 10.0.2.2 traceac.cc and 10.0.2.2 scanner.traceac.cc to C:\Windows\System32\drivers\etc\hosts. The host runs the same fake C2, dual-mode: it peeks the first byte on each connection and dispatches to TLS (0x16) or plaintext HTTP (GET/POST) on the same port 443, required because our WINHTTP_FLAG_SECURE patch makes the C++ side send plain HTTP to port 443 while WebView2 still speaks TLS to the same host.
  • The fake C2 mirrors the real UI from scanner.traceac.cc/send/ui/ and rewrites </body> to inject a JS harness that hooks chrome.webview.postMessage for logging and directly fires the scan message sequence, start_scan check_security_before_consent start_scan_consented, skipping the human PIN entry and consent buttons entirely.
  • An initial start_scan_consented without the three consent flags tos_accepted, privacy_accepted, requirements_accepted got rejected by the C++ side with scan_error: "Missing consent or PIN.", a stricter check than the JS surfaces. Setting all three to true let the scan proceed.

On the good run the scanner walked through its five progress phases — Collecting System Info Analyzing Running Processes Performing System Forensics Scanning Files & Registry Network & Account Intelligence, and POSTed the full submit body:

POST https://traceac.cc/api/scan/submit  HTTP/1.1
User-Agent: TRACE-Scanner/QMSAPRSqM4xK2JnP
X-Trace-Scanner: asfhgashfgaskfdgdsiuadftaedghjfgasdjkfahjkfvbcjasgdjasfajsrolrgirdrueehdnfsbdsfbsfyfajh
Content-Type: application/json
Content-Length: 144437

{
  "pin":       "7TXBS1AV",
  "result":    "cheating",
  "duration":  92.47015161,
  "data":      [ 253 finding objects ],
  "system_info": {
    "os_version":          "Windows 10 (Build 18363)",
    "install_date":        "2026-07-10",
    "boot_time":           "2026-07-10 19:28:01",
    "uptime_hours":        2.034413888888889,
    "country":             "US",
    "vpn":                 "None Detected",
    "diagtrack_enabled":   false,
    "sysmain_enabled":     true,
    "secure_boot_enabled": false,
    "memory_integrity_enabled": false,
    "fast_boot_enabled":   false,
    "vulnerable_driver_load": false,
    "yara_scan_targets":   0,

    "screenshot":          "/9j/4AAQSkZJRg...",   // 58,181-byte JPEG, base64-encoded
    "scanned_paths":       [ "C:\\Users\\trace\\Desktop",
                             "C:\\Users\\trace\\Downloads",
                             "C:\\Users\\trace\\Documents",
                             "C:\\Users\\trace\\Pictures",
                             "C:\\Users\\trace\\Music",
                             "C:\\Users\\trace\\Videos",
                             "C:\\Users\\trace\\Saved Games",
                             "C:\\Users\\Public" ],
    "browser_downloads":   [ "desktop.ini|C:\\Users\\trace\\Downloads\\desktop.ini|282|9351|false|false" ],
    "browser_history":     [],
    "recycle_bin":         "0 items",
    "recycle_bin_files":   [ ... ],
    "recycle_bin_modified": "2h ago",
    "recent_activity":     [ { "action":"STARTED", "filename":"\\Device\\HarddiskVolume2\\trace\\trace_scanner.exe",
                               "is_signed":false, "run_time":"2026-07-10T21:29:40" }, ... ],
    "admin_apps":          [ 10 process records with is_signed / signer / verdict ],
    "network_activity": {
      "advanced_tcp":            [ 9 TCP conns from GetTcpTable2 ],
      "live_connections":        [ 9 conns w/ local_ip+port, remote_ip+port, pid, process, state ],
      "dns_queries":             [],
      "high_entropy_domains":    [],
      "suspicious_connections":  [],
      "tor_nodes":               [],
      "event_logs": { "driver_loads": ..., "firewall_blocks": ..., "logon_events": ..., "sysmon_network": ... }
    }
  }
}

The result was "cheating", from a freshly-installed Windows 10 Lite VM with nothing on it but the scanner, WebView2 and the VC++ redistributable. The 253 findings break down as:

  152  Suspicious Service/Driver   High     "Unsigned service matching suspicious keyword found."
   90  Scheduled Task Persistence   Low
    5  DiagTrack Forensic           Low
    2  Prefetch Trace               High     "Execution trace found in Windows Prefetch: AgRobust.db" etc.
    2  Signature Warning            Medium
    1  Forensic Database Match      High     "Database Keyword: fontdrvhost.exe"
    1  Virtual Machine              High     (detected we were in QEMU)

Notes worth calling out from that submit body:

  • The verdict field is result:"cheating" on a virgin Win 10 install. The category threshold that drives that verdict is server-side, but the client sends enough data (finding count, weights, VM flag) that a Windows Prefetch entry for a Microsoft-signed font-driver host process is sufficient to trip it.
  • A full-screen JPEG desktop screenshot (58 KB decoded) is base64-embedded in the JSON body, no separate multipart, no separate endpoint, no user prompt. It captures whatever is on the entire primary display at the moment the scan started, then the whole 144 KB body ships in a single POST.
  • The bearer-shaped token TRACE-Scanner/QMSAPRSqM4xK2JnP that lives in the request's User-Agent is not a placeholder, it's a per-scanner secret built into the sample's .rdata. Combined with the static X-Trace-Scanner header (identical across every request), possession of one compiled scanner exe is possession of enough headers to POST arbitrary JSON to the live /api/scan/submit for that scanner's PIN slot.
  • TCP table exfiltration is exhaustive GetTcpTable2 results with local port + remote IP + remote port + PID + process image name + connection state are shipped raw. A running FiveM session, or a running SSH tunnel, appears in the JSON body one-to-one.
  • The scanner detected the VM environment (Virtual Machine, High severity, 1 finding), same category that trips a 40-weight finding, so "analysis in a VM" is itself weighted toward the cheating verdict on the server side.
  • The full endpoint order across a real scan is: GET /api/version GET /api/scanner/rules?pin= GET /api/scanner/yara_manifest?pin= POST /api/scan/progress ×32 → POST /api/download/validate ×5 (body: {"pin":"<PIN>"}) → POST /api/scan/submit. The /api/download/validate endpoint was not previously in our C2 map and only surfaces during the live scan flow.

Fifth pass, everything, with a live PIN

With a fresh, valid dashboard-issued PIN (97DPWZ7C) we cleaned the remaining unknowns off the map. Every scanner endpoint that returns rules, safes, YARA CLI, or the signed executable is reachable with the C++ scanner's exact request headers:

GET  https://traceac.cc/api/scanner/rules?pin=<PIN>              -> 5,732 B  application/json
GET  https://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN>  -> 2,418,688 B  PE32+ console x64
GET  https://traceac.cc/api/download/file?pin=<PIN>              -> 6,528 B  HTML (download splash)
GET  https://traceac.cc/api/download/file?pin=<PIN>&download=1   -> 3,345,920 B  PE32+ GUI x64  (the scanner)
POST https://traceac.cc/api/download/validate  {"pin":"<PIN>"}   -> {"success":true}
POST https://traceac.cc/api/scan/progress      {"pin":"<PIN>",…} -> {"success":true}
POST https://traceac.cc/api/scan/submit        (full body)       -> {"success":true}
POST https://traceac.cc/api/scan/closed        {"pin":"<PIN>"}   -> {"success":true}

Notable negatives (verified with the same valid PIN, headers and query variants): /api/scanner/yara_manifest?pin=, /api/scanner/yara_rules?pin= and every ?file=<name> parameter combination we tried return the same 22,207-byte TRACE | Page Not Found HTML. Both endpoints are dead on the current server. They still live in .rdata as leftover strings , the current client codepath does not hit them. All signature intel travels through the single /api/scanner/rules JSON.

The rules JSON, 24 cheats + 3 safes, plaintext

The full brand inventory ships as one JSON blob per scan. Every cheat entry carries the trigger keywords the C++ side greps for (in memory, in strings, in DNS, and against process paths), the exact expected file_name + file_size + sha256 for hash matching and a severity band that drives the server-side verdict. The full list:

NameSeverityFilenameSizeSHA-256 (prefix)Keywords
crystalunbanCritical4f04b564…unban, crystalunban
cheatssCritical22 (stub)loader_prod, crystal unban, cheatss
Coldmenu loaderCritical5ab5f7b8…cold, coldmenu loader
Strings DetectedCritical"" (dynamic)loadlibrarya, d3d11.dll, d3d9.dll, espcl+m, ?espi, strings detected
Critical DLL InjectorCriticald3d9.dll8bb2b5f2…rolex, susano, keyser, cheat, esp, aimbot, silentaim, d3d9.dll, d3d9, critical dll injector
EulenCriticalloader_prod.exeeulen_placeholder_shaeulen, loader_prod.exe, loader_prod
Susano / Claude AI SetupCriticalClaude_setup.exesusano_placeholder_shasusano, claude, ddd.exe, claude_setup, calude, claude_setup.exe
TzProjectCriticaltaskthow.exe7,434,240e0669f46…api.tzproject.com, taskthow.exe, taskthow, tzproject
TzProject ChromeCriticalchrome.exe5,505,024f434bad7…api.tzproject.com, chrome.exe, chrome, tzproject chrome
Tiago Modz HostCriticalLoader_3.1.7.exe37,765,120b19c5911…tiagomodzhost.win, loader_3.1.7.exe, loader_3.1.7, tiago modz host
RedEngine FalconCriticalhugeperhapswashroad.exe16,466,9440f4894d7…falcon.redengine.eu, hugeperhapswashroad.exe, hugeperhapswashroad, redengine falcon
HX SoftwaresCriticalupdated.exe8,291,840b421fab6…api.hxsoftwares.com, updated.exe, updated, hx softwares
xTransformationCriticalFP1754707396174.dll10,455,306575b5b3c…diagnostic.xtransformation.space, fp1754707396174.dll, fp1754707396174, xtransformation
MachoCheatsCriticalYb6ul.exe70,235,664e50590e6…machocheats.com, yb6ul.exe, yb6ul, machocheats
MrCheat.cc LoaderCriticalLoader.exe6,762,557077a528d…p.mrcheat.cc, loader.exe, loader, mrcheat.cc loader
Rar$EX Temp LauncherCriticallauncher.exe12,385,2802bb8c7ac…131.196.198, bbhost.com.br, launcher.exe, launcher, rar$ex temp launcher
TrashCrackHighnonetrashcrack, trashcrack-free
bypassesHighdynamic2fusebypass, bypass, antiscan, bypasses
Critical CheatHighdb349a14…claude setup, susano, critical cheat
loaderHighloader.exe7,112,192f22b1b9d…keyser, loader.exe, loader
AmbaniHighBlazing_Pack_Event.exe8,746,4969c4009bc…ambani.dev, blazing_pack_event.exe, blazing_pack_event, ambani
NordVPNTM SpooferHighNordVPNTM.exe1,425,408021f53c2…nordvpn, nordvpntm.exe, nordvpntm, nordvpntm spoofer
Skript.ggHights3client_win64.exe2,757,120f4ddc947…skript.gg, ts3client_win64.dll, ts3client_win64.exe, ts3client_win64
SpaceMediumspace.exe3,318,784e6448272…ipinfo.io, lencr.org, space.exe, space

And the safes allow-list, three fixed entries, is the entire whitelist:

[
  { "name":"Spotify", "file_name":"spotify.exe",
    "sha256":"34285a7753a062d672311ce575a1606e1b9b5c8842a0520de027997124fc63c6" },
  { "name":"Chrome",  "file_name":"chrome.exe",
    "sha256":"f6390508a568fb7aa61296e30e40aaf019900188ca76dd82ab022f3308d49ab4" },
  { "name":"FiveM",   "file_name":"FiveM.exe",
    "sha256":"4972704ebb3cd6cebf235ba10892f5449f6ba16c852dfb6c24a516ee2dafc2be" }
]

Rule quality notes: the JSON as-shipped contains four clearly non-signature sha256 values — "22", "none", "dynamic2", "eulen_placeholder_sha" / "susano_placeholder_sha", and an empty string for Strings Detected. The scanner treats these as always-mismatch, falling through to the keyword grep, which means those rows are effectively YARA-string-only detections masquerading as SHA-checks. The Critical DLL Injector rule triggers on the literal word cheat, esp, or aimbot appearing anywhere in a scanned buffer, a keyword list that will false-positive against tutorial repositories, gaming videos, or any anti-cheat write-up.

yara64.exe, the shipped CLI

GET https://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN> → a 2,418,688-byte PE32+ console executable, SHA-256 1c45eb27​9d820aba​81fd41c2​23844428​ebe44037​cf5793be​4b52a9d3​b3df62b3​3. This is a stock upstream YARA build, not a fork; the scanner drops it under %APPDATA%\\trace\\yara64.exe, verifies the SHA-256 against the (dead) manifest response and shells out with -w -m --scan-list. On a valid PIN the download succeeds without the header pair below, but the sample's real request always ships them.

The scanner exe download, one binary for everyone

GET /api/download/file?pin=<PIN> serves a small HTML splash that immediately links to ?download=1. The download URL returns the actual PE32+ GUI executable (Content-Type: application/x-msdos-program, 3,345,920 B, SHA-256 9d1b210b​06d94286​3e49f0cf​7baf629f​cdc3cf76​d33a5383​a6caec65​783eb4fc). Compared byte-for-byte against our earlier Trace_7TXBS1AV.exe sample:

  Total differing bytes: 4
    0x17ac2  , our jge -> jmp WebView2-error-skip patch
    0xB9173  , our WINHTTP_FLAG_SECURE strip (site 1)
    0xCEDBD  , our WINHTTP_FLAG_SECURE strip (site 2)
    0x24FDED , our WINHTTP_FLAG_SECURE strip (site 3)

The two exes are otherwise identical. That is the entire per-scanner customisation: nothing. The PIN is not embedded, the X-Trace-Scanner header is not embedded, the TRACE-Scanner/QMSAPRSqM4xK2JnP user-agent is not embedded per customer. All three are hardcoded constants shared by every scanner ever compiled off this build. The PIN is parsed at runtime from GetModuleFileNameW, everything between the Trace_ prefix and the .exe suffix. Renaming the file changes the PIN. There is no cryptographic tie between the exe and the dashboard-issued PIN.

Impact: possession of any one compiled scanner is possession of every header material Cloudflare gates on. To POST a fabricated /api/scan/submit body against any customer's PIN slot, an attacker with a scanner copy needs only the target's current PIN (an 8-character alphanumeric dashboard-issued token) and their own copy of the scanner's three static headers. Every server response for /api/scan/* is a bare {"success":true}, no report id, no HMAC of the body, no echoed timestamp, no idempotency key.

YARA is dead in production, the scanner ships without rules

The scanner is built around a YARA fetch chain: get a manifest, verify the URL and SHA-256, download yara64.exe, download custom_rules.yar, shell out to yara64.exe -w -m --scan-list. Every step of the pipeline is in the binary, the URLs, the error strings (YARA manifest HTTP failed, YARA manifest SHA256 is invalid, YARA manifest URL Rejected:, YARA rules failed CLI validation), the output paths (%APPDATA%\\trace\\yara64.exe, %APPDATA%\\trace\\custom_rules.yar). We ran the whole chain end to end under our fake C2 with a properly signed manifest and captured the request format for every stage:

# manifest fetch (application/json)
GET https://scanner.traceac.cc/api/scanner/yara_manifest?pin=<PIN>
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Accept: application/json
User-Agent: TRACE-Scanner/QMSAPRSqM4xK2JnP
X-Trace-Scanner: asfhgashfgaskfdgdsiuadftaedghjfgasdjkfahjkfvbcjasgdjasfajsrolrgirdrueehdnfsbdsfbsfyfajh
# expected body:
#   {"success":true, "url":"https://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN>",
#    "sha256":"<64-hex>", "size":<int>, "min_size":<int>}

# yara64.exe download (application/octet-stream), SHA-256 verified against manifest
GET https://scanner.traceac.cc/static/bin/yara64.exe?pin=<PIN>
Accept: application/octet-stream
...same auth headers...

# rules text download (text/plain), written to %APPDATA%\trace\custom_rules.yar
GET https://scanner.traceac.cc/api/scanner/yara_rules?pin=<PIN>
Accept: text/plain
...same auth headers...

But on the current production server, with the same valid dashboard-issued PIN, the exact wire headers the client emits, on both host aliases, both YARA endpoints return the same 22,207-byte TRACE | Page Not Found HTML:

GET https://scanner.traceac.cc/api/scanner/yara_manifest?pin=97DPWZ7C  -> 200 text/html 22,207 B  (404 HTML)
GET https://scanner.traceac.cc/api/scanner/yara_rules?pin=97DPWZ7C     -> 200 text/html 22,207 B  (404 HTML)
GET https://traceac.cc/api/scanner/yara_manifest?pin=97DPWZ7C          -> 200 text/html 22,207 B  (404 HTML)
GET https://traceac.cc/api/scanner/yara_rules?pin=97DPWZ7C             -> 200 text/html 22,207 B  (404 HTML)

The scanner ships with a whole detection pillar wired up to a route that isn't there. On every real-world scan the client silently drops down the YARA manifest response was empty error path, sets yara_scan_targets: 0 in the submit body and reports the whole verdict off the other pillar, the /api/scanner/rules keyword + SHA-256 table. Every “critical” hit in the 253-finding sample body above came from keyword grep or Prefetch/BAM/SRUM inventory, not from YARA. There are 24 cheat entries in the rules JSON whose sha256 field is a real 64-hex digest, the scanner is built to hash-match candidate files against them and post a Forensic Database Match finding on a hit, but with YARA disabled and the file discovery limited to a fixed set of user-profile directories, that match window is a lot narrower than the “full-machine forensic sweep” the marketing implies.

Live server probe

Independently of the Wine harness, a curl against the real traceac.cc endpoint set does confirm one datapoint, the /api/version endpoint is unauthenticated and returns the current server version:

$ curl https://traceac.cc/api/version
{"success":true,"version":"1.4"}

Every other endpoint in the C2 map is behind Cloudflare with the custom x-trace-error response header and a Forbidden | trace HTML body until a valid PIN is supplied, the PIN itself is minted by the dashboard, per scan and expires with the scan. That gate is server-side; the binary has no client-side PIN validation and the sample's own copies of the pin-carrying URLs are the same GET templates we already extracted. The manifest schema, rule text and scan-submit body are all gated behind that PIN and were not obtainable without one.

The 91-tool reverse fleet

For completeness on the tooling side: the reference against which this reverse was cross-checked is thementebinaria/retoolkitInno Setup superpack, a curated Windows installer that fetches 91 open-source RE tools across 22 categories at install time (retoolkit itself ships only .iss script wrappers; the tools are fetched fresh from each upstream). The full inventory the installer contains is below. The Linux-side pass on this page was done with radare2 5.5, pefile 2024.8, lief 0.17, yara 4.5 and the mandiant/capa-rules corpus (1,055 rules). Ghidra and Cutter were unreachable from this environment (GitHub release-asset URLs 403 through the proxy), so their equivalent coverage came from radare2 and the raw PE parser.

PE / packer / entropy (16)
4n4ldetectorcapadiedll_to_exeexeinfopeflosspe_unmapperpeanatomistpebearpestudioppeereadpereshackstud_peuwpspywinapisearch
Decompilers (2)
cutterghidra
Debuggers (2)
hyperdbgx64dbg
Unpackers (5)
mal_unpacknovmpqunpackupxxvolkolak
Process inspection (8)
apimonitorfilegrabhollowshunterobserverpesievesysexpsysteminformerxntsv
.NET analysis (7)
de4dotdnspyexdotdumperextremedumperilspyrundotnetdllsae
Hex editors (5)
dz6fhexhxdimhexrehex
YARA signatures (2)
yarayarax
Network sniffers & mocks (5)
echomiragefakenetfirefoxnmapwireshark
General utilities (14)
7zipbazzarcyberchefentropyerrorlookupforcetoolkitjdkmanwnppopenhashtabregshotvtwinapiexecwub
Go binaries (3)
gftracegoresymredress
Java / dex (3)
jadxjdguirecaf
Delphi decompilers (1)
idr
AutoIt decompilers (2)
exe2autmyauttoexe
ELF analysis (2)
elfparserngxelfviewer
OLE / Office malware (4)
lessmsiofficemalscanneroledumpssview
PDF malware (2)
pdf-parserpdfid
Cobalt Strike parsers (2)
1768cobaltstrikescan
System info (1)
winobjex64
Opcode calculators (1)
xopcodecalc
Programming tooling (3)
devcppfasmwinpython
Android / dex (1)
dex2jar

Category counts total 91 (documentation.iss and the root retoolkit.iss orchestrator omitted). The parser used to emit this list walks every src/installer/<category>/*.iss file in the retoolkit repo and pulls the AppName define plus the category the file sits under. Two entries are worth flagging: firefox is included under the network category as a lightweight browser for VirusTotal / vendor lookups and jdkis a build-time dependency for Ghidra/Jadx rather than an analysis tool of its own.

Live traceac.cc surface map

Every URL surface the scanner touches, probed live from this pass. The important read is not the list itself (that comes from .rdata) but which paths respond vs. which are Next.js SPA-fallback pages served for anything the router doesn't know. In particular: /robots.txt, /sitemap.xml, /favicon.ico, /apple-touch-icon.png, /manifest.json, /humans.txt, /ads.txt and /BingSiteAuth.xml all answer 200 with the same 21–23 KB SPA HTML, the site has no real robots directive, no sitemap, and no static favicon. The favicon is inlined into the SPA head as a data:URI.

HostPathHTTPSize / NoteKind
traceac.cc/api/version20033 B (JSON)real
traceac.cc/.well-known/security.txt200148 Breal
traceac.cc/privacy20018.2 KBreal
traceac.cc/login302 → 200form + full CSP headerreal
traceac.cc/register302 → 200formreal
scanner.traceac.cc/send/ui/20020.4 KBreal
scanner.traceac.cc/send/ui/index.html20020.4 KBreal
scanner.traceac.cc/api/version20033 B (JSON)real
traceac.cc/admin4035.2 KB ("Just a moment...")protected
traceac.cc/admin/login4035.2 KBprotected
traceac.cc/admin/dashboard4035.2 KBprotected
traceac.cc/admin/dashboard/{users,scans,staff,moderation}4035.2 KB eachprotected
traceac.cc/api/download/file?pin=<expired>40333 KB ("Forbidden | trace")protected
scanner.traceac.cc/api/scanner/rules40333 KB (no PIN)protected
scanner.traceac.cc/send/ui/js/{app,scanner}.js40332 KB (no session)protected
traceac.cc/robots.txt200 (fake)21.9 KB HTML "Page Not Found"fallback
traceac.cc/sitemap.xml200 (fake)22.8 KB HTMLfallback
traceac.cc/favicon.ico200 (fake)21.9 KB HTMLfallback
traceac.cc/apple-touch-icon.png200 (fake)21.9 KB HTMLfallback
traceac.cc/manifest.json200 (fake)22.8 KB HTMLfallback
traceac.cc/humans.txt200 (fake)21.9 KB HTMLfallback
traceac.cc/ads.txt200 (fake)21.9 KB HTMLfallback
traceac.cc/BingSiteAuth.xml200 (fake)22.8 KB HTMLfallback

/.well-known/security.txt

Only real static well-known file on the domain, 148 bytes at the canonical path:

Canonical: https://traceac.cc/.well-known/security.txt
Contact: mailto:support@traceac.cc
Expires: 2026-06-25T23:59:00Z
Preferred-Languages: en, el

The Expires date is the same day as the binary's compile time (2026-06-25). The Preferred-Languages: en, el pair is the strongest static geographic signal on the whole site, Greek + English, matching the FiveM vertical's operator base.

CSP topology (from /login response)

The site's own Content-Security-Policy header names every third-party origin the dashboard is allowed to talk to. This is the authoritative allow-list, anything the scanner or dashboard reaches at runtime has to be in here or the browser blocks it:

DirectiveValue
default-src'self'
script-src'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://challenges.cloudflare.com
style-src'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://fonts.googleapis.com
font-src'self' data: https://cdnjs.cloudflare.com https://fonts.gstatic.com
img-src'self' data: blob: https:
connect-src'self' https://traceac.cc https://scanner.traceac.cc wss://traceac.cc wss://scanner.traceac.cc https://challenges.cloudflare.com
frame-src'self' https://challenges.cloudflare.com
object-src'none'
base-uri'self'
form-action'self'
frame-ancestors'none'
upgrade-insecure-requests(flag)

Everything third-party goes through Cloudflare, challenges.cloudflare.com(Turnstile bot check), cdnjs.cloudflare.com (script/style CDN), fonts.gstatic.com (via fonts.googleapis.com). The connect-src line names the four host+scheme pairs the scanner and dashboard talk to on the wire: https://traceac.cc, https://scanner.traceac.cc and their wss://counterparts, the WebSocket bridges are opted into by the policy even though the static binary shows no WebSocket* imports; the WSS lanes appear to be dashboard-side only.

PIN lifecycle, 11 PINs, 6 alive, 5 expired

Eleven live-issued PINs were exercised against https://traceac.cc/api/download/file?pin=<PIN>&download=1. Six PINs return the canonical 3,345,920-byte PE with SHA-256 9d1b210b06d942863e49f0cf7baf629fcdc3cf76d33a5383a6caec65783eb4fc byte-for-byte identical across all six. The download route is not per-PIN, every valid PIN gets the same build. Five other PINs answer with a shared Cloudflare 403 HTML page (~33 KB, title Forbidden | trace), the request reaches the origin and the origin says the PIN is gone. The distribution below is the observed lifecycle: PINs live long enough to complete a scan session, then the origin marks them expired and the download route drops to 403 without a body change:

PINStatusBytesSHA-256 (first 8 / last 4)
YWE9R0O2alive3,345,9209d1b210b...b4fc
8RKPK31Ealive3,345,9209d1b210b...b4fc
B4AAQI0Palive3,345,9209d1b210b...b4fc
P34S2NDTalive3,345,9209d1b210b...b4fc
QR78NWXXalive3,345,9209d1b210b...b4fc
W0ZNFXQ5alive3,345,9209d1b210b...b4fc
OT2L24M0expired33,88529bb88d0...bbb0 (403 HTML)
W3Q6LJ60expired33,884deb6e360...0ebf (403 HTML)
VYHKAJC4expired33,885882796c7...5809 (403 HTML)
TCEQDY23expired33,885a9afe66f...ba97 (403 HTML)
UM0XXIR1expired33,885eaff28d5...399d (403 HTML)

Note the direct URL flow: hitting /api/download/file?pin=<PIN> without &download=1serves a small HTML landing page (<title>Trace Download</title>) with a single anchor referencing the ?pin=<PIN>&download=1 form, the actual binary transfer only starts on the second request. The two-step is a Cloudflare Rocket-Loader-friendly guard. Every PIN is 8 characters of [A-Z0-9] with no obvious HWID binding, the same PIN string can be replayed until it goes 403.

WebView2 UI state machine (from /send/ui/)

https://scanner.traceac.cc/send/ui/index.html was pulled live (20.4 KB HTML shell). It reveals the three-step flow the injected WebView2 host walks the user through, each step its own .state block with a .trace-mini-stepperheader and a data-flow-step integer. The scanner binary's injected JavaScript (documented in the WebView2 injection section) targets these DOM IDs directly:

1 · PIN Authentication
#pin-state
pin capture
  • #pin-input (auto-filled by injected JS)
  • #pin-submit (auto-clicked)
  • #pin-message (inline error)
  • seconds-remaining countdown
2 · Accept Policies
#consent-state
ToS + privacy consent gate
  • <a href=https://traceac.cc/tos target=_blank>
  • <a href=https://traceac.cc/privacy target=_blank>
  • #consent-accept (primary btn)
  • #consent-deny (secondary btn)
  • #consent-message
3 · Scan
#scanning-state
live progress panel
  • #progress-fill (%-width bar)
  • #progress-phase (text)
  • #progress-percent (0–100)
  • 6× .phase-dot indicators (six scan phases)
  • .is-heartbeat pulse on active step
3 · Scan (complete)
#done-state
verdict card
  • result badge (Clear / Detections)
  • 'close_after' timer
  • no manual close button, auto-dismiss

Asset load list

The <head> of the UI page loads eight local assets from scanner.traceac.cc/send/ui/ plus one external stylesheet from cdnjs.cloudflare.com. Direct HTTPS fetch for the JS/CSS returns 403 without a live session cookie, those are gated behind a scanner-only session, but the reference set is visible in the shell:

AssetPurpose
js/app.jstop-level app bootstrap
js/scanner.jsscan state-machine + WebView2 host bridge
css/variables.cssdesign tokens (colours, spacing)
css/base.cssreset + typography
css/components.css?v=buttonnnbuttons/cards/steppers (note the ?v=buttonnn cache-buster)
css/progress.cssthe scanning-state progress bar
css/done.cssthe done-state verdict card
css/particles.cssbackground particle animation
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.cssFont Awesome 6 icons
/cdn-cgi/scripts/7d0fa10a/cloudflare-static/rocket-loader.min.jsCloudflare Rocket Loader (auto-injected)

components.css?v=buttonnn is the only versioned asset, the cache-buster query string is a hand-typed buttonnn rather than a hash or a build counter, which matches the overall vibe of the site: shipping software, not infrastructure code. rocket-loader.min.js is a Cloudflare defer-and-inject shim added by the edge, not by the origin.

QEMU Windows guest attempt (no KVM)

A stretch goal on this pass was to boot a Windows guest under QEMU and run Trace_7TXBS1AV.exeagainst the retoolkit tool fleet inside it. The container has no /dev/kvm, so QEMU falls back to tcg (software emulation), roughly 1–5% of native speed on Windows workloads. A Windows 10 Lite 19H2 x64 ISO (1.19 GB, disk label WIN10PRO_1909_476_OPREKIN, from archive.org) was pulled fresh and the machine started with:

qemu-system-x86_64 \
  -machine q35 -m 4096 -smp 2 -cpu qemu64 \
  -device ich9-ahci,id=ahci \
  -drive file=win10.qcow2,if=none,id=disk0,cache=writeback \
  -device ide-hd,drive=disk0,bus=ahci.0 \
  -drive file=win10lite.iso,if=none,id=cdrom0,media=cdrom \
  -device ide-cd,drive=cdrom0,bus=ahci.1 \
  -boot d -vnc :5 -daemonize \
  -monitor unix:qemu-mon,server,nowait -net none

Observed wall-clock time in TCG mode with 4 GB RAM and 2 vCPUs:

PhaseReached atNotes
SeaBIOS + CD boot loader~35 sboot menu, then loading files from CD
"Setup is starting" splash~90 sWindows PE booted, WinRE initialised
Drive picker (Setup)~2 min 45 sfirst attempt with virtio-blk showed no drives (no driver); rebooted with ich9-ahci and Drive 0 = 20 GB appeared
Copying Windows files ✓~4 minstep 1 of 5 complete
Getting files ready 18%~6 min 17 sstep 2 of 5 in progress at time of writing
Desktop reachableest. ~40–60 minprojected on TCG curve; retoolkit install is a further multi-hour ordeal (91 upstream downloads through the container proxy, many via GitHub release assets that this environment's policy blocks at CONNECT)

Why the Windows-side pass is a stretch, not the load-bearing analysis: even once the guest reaches the desktop, running Trace_7TXBS1AV.exe in it needs the Edge WebView2 Evergreen runtime installed (the binary's ICoreWebView2* class-name imports make that a hard requirement, no runtime, no window). And retoolkit's value is a fleet of interactive GUI tools (x64dbg, Cutter, IDA-freeware-style, pestudio, HxD), driving that from a headless VNC in this session isn't a productive way to spend the budget. Every finding on this page came from Linux-side tooling that does answer the question: rabin2/radare2for disassembly + xref navigation (the same job Cutter/Ghidra do interactively), pefile+lief for the PE parse (the job pestudio/PE-bear do), strings -eL(the job FLOSS does), yara against capa-rules (the job capa does) and Wine + a synthetic C2 for the runtime dial-out capture (the job x64dbg on Windows would do).

One concrete boot artefact worth flagging: the first QEMU boot with if=virtio on the disk reproduced the classic Windows-installer catch, Windows Setup does not carry viostor.sys on the install ISO and the drive picker showed "We couldn't find any drives. To get a storage driver, click Load driver."Switching the disk interface to ich9-ahci (a chipset every Windows 10 ISO knows natively) made Drive 0 appear on the second boot. This is unrelated to the scanner itself but shows up when anyone tries to reproduce the guest, the SATA path is the one to use unless you also feed the virtio-win.iso as a second CD-ROM.

Closing

Trace Anti-Cheat is a functional retroactive-trace scanner. It reads a well-chosen set of Windows forensic artefacts, downloads YARA to run against a rule set that lives on its authors' server, takes a screenshot and posts a JSON to a fixed C2. The technique inventory is solid, Prefetch, BAM, SRUM, Amcache, Event Log 4688 with the TokenElevationType filter, DNS-Client 3008/3010, WFP 5152/56/57. Anyone building a similar tool could learn from the coverage.

It is not unreverseable. The protector marker is 61 bytes of text in a section named .1337. No section is encrypted, no TLS callback is registered, no anti-debug is meaningfully implemented and every URL, every registry key, every YARA path, every event log query, every cheat brand name and every user-facing string sits in .rdata in plaintext at UTF-8 or UTF-16-LE. This document is the extraction, byte-offset by byte-offset.

If the next release genuinely raises the bar — real string obfuscation, control-flow flattening, a proper protector shell, meaningful anti-debug, or even just a byte-oriented XOR pass over .rdata with a runtime-derived key — we will happily update this page to note the improvement. Until then, the “unreverseable” label describes marketing, not this build.

Every string quoted in this write-up appears in the sample's .rdata at either UTF-8 or UTF-16-LE and is reproducible with strings -a -eL against the file whose SHA-256 is listed in the IOC block. The runtime section documents a live wire capture attempt under Wine that confirmed the TLS dial-out and stopped at Wine's post-handshake cert-chain build, everything else in this write-up was recovered statically.