GPULoader

Abstract

Key takeaways

  • SectopRat stealer loader chain
  • Uses a proprietary virtual machine
  • Uses the GPU and D3D11 shaders to decrypt itself
  • Targets IT and cryptocurrency software
  • Resolves its C2 through EtherHiding (BSC smart contracts)
  • Likely related to GPUGate
  • Two other tools, probably AI-generated were identified
  • One of the operators most likely made an operational-security mistake

We identified a crimeware-style compromise chain whose distinctive feature is that it decrypts itself using D3D11 shaders executed on the GPU. The chain has two stages built around two different loaders, relying on a proprietary virtual machine, GPU-based decryption, and C2 retrieval from smart contracts on the Binance Smart Chain (BSC). It finally executes in memory the SectopRat stealer, previously described by Fortinet.

This compromise chain was also covered in July by Huntress. We provide some additional details here, but we will not cover the malvertising campaign itself.

We detail here the two loaders, which we named VMLoader and GPULoader respectively. They run a SectopRat payload that also relies on BSC smart contracts to obtain its C2.

We also briefly describe an optional FakeGuard payload performing an AitM attack against the banking sector, masquerading as an application for blocking unwanted websites.

We then investigate the chain of smart contracts used to configure the SectopRat samples, which leads to what appears to be an operational-security mistake by the operator, potentially exposing their identity.

Finally, we compare these findings with the GPUGate article published by Arctic Wolf.

Overview

The initial infection happens through the download of a ZIP archive posing as a legitimate installer, such as 197b6c51 (ClaudeDesktop.zip). The archive contains a legitimate jcef_helper.exe (Java Chromium Embeded Framework) binary (renamed, for instance, to DockerDesktop.exe, Chrome.exe, ClaudeDesktop.exe) and a libcef.dll DLL).

The libcef.dll binary (which we call VMLoader) performs a system check — in particular inspecting the installed GPU (blacklisted vendors, required VRAM, etc.) — decrypts a resource holding 15 bytecodes ran by a custom virtual machine, and finally reads a BSC contract to obtain a URL from which a .zip file is downloaded. Every executable contained in that archive is then run.

The downloaded ZIP file usually contains the following files:

  • sslconf.exe: legitimate, signed executable
  • tempdir.dll: the GPULoader malware, which loads and runs an encrypted companion file
  • companion file (for example licence.dat): the encrypted SectopRat payload loaded by GPULoader
  • (optional) siteguard.exe: the FakeGuard malware, performing AitM attacks on banking-site browsing
  • (optional) vcruntime140.dll: dependency

The GPULoader malware has the distinctive feature of decrypting its companion file by having the decryption carried out by the GPU, and it uses the same proprietary virtual machine. The final payload is a SectopRat malware, which also uses a BSC control channel — different from the one used by libcef.dll. In some cases, a FakeGuard malware is also present.

VMLoader

The malware masquerades as libcef.dll, the Chromium Embedded Framework (CEF) library, used by many desktop applications to render web pages. It exports the 216 CEF API functions and a fake version info, but none of these functions are actually implemented.

The malware first performs a GPU check by enumerating graphics adapters via CreateDXGIFactory, and rejects:

  • software adapters (CPU-based software emulation)
  • less than 256 MB of dedicated VRAM and less than 1 GB of shared VRAM
  • an adapter description name shorter than 12 characters
  • vendor IDs 0x1414 (Microsoft Basic Render), 0x1234 (QEMU), 0x15AD (VMware)
  • the inability to create a Direct3D 11 device via D3D11CreateDevice

If these checks pass, the code proceeds to load an encrypted resource and decrypt it. Two modes exist depending on the loader version:

  • Version 1 6b8ecc21: XOR with a 32-byte key, no derivation
  • Version 2 6ccd6b67: AES-256-CTR using the BCrypt API
XOR decryption

Try it on Exalyze

Note: the version-1 loader (XOR) can also load a companion file when the resource is not embedded in the binary.

Once decrypted, the resource holds 15 subprograms compiled for an in-house virtual machine. Each decrypted blob carries a "VMP1" magic number in its header. The opcodes and blocks are similar across all observed versions. The virtual machine is relatively simple and essentially calls an opcode dispatcher for each element read; the operations stay fairly simple (push, pop, add, sub, xor, opr, shl, shr, reads, writes, etc.), with the exception of opcodes 0x61-0x64, which provide FNV-1A-hash-based API resolution for kernel32.dll or ntdll.dll and direct calls to them.

VM dispatch

The full VM instruction set has not been completely analyzed; however, most of the instructions were disassembled, and we were able to infer the following behaviors for the 15 modules:

Module # Role
1 Microsoft Defender emulator detection (Mp and VFS_ functions)
2 RWX memory protection
3 ntdll.dll remapping
4 Memory patching, potentially EDR unhooking
5 Anti-debug by clearing the hardware debug registers DR0-DR7
6 Privilege-elevation check (token)
7 Privilege elevation via runas
8 Windows Defender exclusion via powershell -NoProfile -Command Add-MpPreference -ExclusionPath 'C:\Users'
9 Queries the BSC contract and decrypts the URL with the XOR key deadbeefcafebabe13374269
10 Downloads the stage-2 archive as update.bin
11 Self-install: copies the malware and its executable onto the system
12 Self-install: Run-key persistence
13 Self-install: scheduled-task persistence via the schtasks.exe command
14 Extracts the archive and runs the contained .exe files
15 Downloads and runs the legitimate installer

Module #15 downloads and runs the legitimate installer based on the current process name. It supports, for example, googlechrome.exe, claudedesktop.exe and exodus.exe. However, it can also handle Сhrоme.exe, where the C and o characters are their Cyrillic homoglyphs. This may be intended to bypass detection rules that would flag malformed chrome.exe executables (unsigned, in a non-standard folder, inside a ZIP archive, etc.).

Chrome cyrillic chars

Self-installation happens in a %APPDATA%\EdgeUpdate-<8hex>\{DockerDesktop.exe, libcef.dll, update.bin} folder, where <8hex> is an 8-hex-character suffix regenerated per build.

The binaries carry a fake VERSIONINFO publisher drawn from the following set:

  • Bridge Libraries Group (brlib 4.17.966.64)
  • Foundation Libraries Project (foundlib 1.3.205.55)
  • Native Bindings Project (nbind 4.17.162.43)
  • Embedded Helpers Foundation (emhelp 1.18.932.55)
  • OpenSource Toolkit Contributors (rtlib 2.8.116.3)
  • WinFramework Helpers (apsrt 4.8.89.23)
  • Adaptive Runtime LLC (adaptrt 2.18.446.88)

We were able to identify the following mutexes:

  • Global\DefenderHydrationGate
  • Global\OneDriveStandaloneCache
  • Global\MicrosoftEdgeRolloutSync
  • Global\TaskHostSchedulerGate
  • Global\WindowsTelemetryDataAcq

And the following Run persistence keys:

  • DefenderTelemetryService
  • MicrosoftEdgeUpdateTaskMachine
  • TaskSchedulerHelperSvc
  • WindowsConfigurationService
  • WindowsTempCleanupSvc
  • OneDriveStandaloneUpdater

All of these therefore appear to be generated periodically.

The smart contracts are read from bsc-dataseed.binance.org via an eth_call request for contract 0xc190. The response is XORed with the string deadbeefcafebabe13374269. The value has been updated 6 times:

Date (UTC) Decoded value
2026-05-28 11:36 https[:]//legsotier.us/{zip.php,app.exe,dll.php}
2026-05-28 12:08 https[:]//neeitoerw.my/{zip.php,app.exe,dll.php}
2026-09-19 17:09 https[:]//apisue.click/{zip.php,app.exe,dll.php}
2026-10-13 11:01 https[:]//zippis.xyz/{zip.php,app.exe,dll.php}
2026-10-19 11:11 https[:]//faceitzip.xyz/{zip.php,app.exe,dll.php}
2026-10-23 09:01 https[:]//arzipi.xyz/{zip.php,app.exe,dll.php}

Contract 0xc190 was created on 2026-05-28 11:36:38 by 0x3695. This wallet is funded solely by the 0x8C82 common gas hub.

SteamLoader

VMLoader is not the only malware using this smart contract. In fact we found another malware, 40846f40 which uses the same contract and that does the same thing. However, in this case, this is a quite simple .NET malware with no obfuscation whatsoever, and it is a standalone .exe unsigned file. In fact the smart contract 0xc190 is in clear text, and the functions have quite speaking prefixes, such as "Res" (EtherHiding resolve), "Get" (download), "Dec" (Decoy) or "Stm" (Steam).

Exclusion .NET method

The logic is quite simple:

  • the malware will store its resources in the AppData\Roaming\Cache-XXXX folder, where XXXX is derivated from the machine name
  • if the malware runs in SYSTEM Integrity Level, it will add a Windows Defender exclusion over the C:\Users folder, install the last .exe found in the folder AppData\Roaming\LocalCache\ as a Scheduled Task (name CacheMaintenanceTask), and run it. It will also create run the process on the user session with NtCreateToken/CreateProcessAsUser
  • if the malware runs in HIGH Integrity Level, it will create a Mutex (Global\WinCacheSyncE), create the same task, add the same exclusion, resolve the smart contract C2 address, download the pointed file, and depending of the extension, it will run it. The .dll extension is not supported, the .exe is simply executed, otherwise it is handled as a ZIP archive with tar.exe in a x folder, then any .exe file is executed (cmd /c for /r \<PATH>" %f in (*.exe) do @start "" /d "%~dpf" "%~f")
  • if the malware is not elevated, it will run its decoy (download and execute the associated installer depending on its own process name) and, if the Mutex is not set, try to elevate itself. First with the Steam technique, otherwise with a simple runas command which will prompt the UAC

The Steam functions is quite interresting, as it will abuse the SteamClientService to trigger an execution of an executable having the same name in the LocalCache folder. It uses an existing, Valve-signed, InstallScript: Wallpaper Engine (appid 431960), which basically comports:

"InstallScript"
{
    "Run Process On Uninstall"
	{
		"Process_name"
		{
			"process 1"		"%INSTALLDIR%\\launcher.exe"
			"command 1"		"-uninstall"
		}
	}
    "Run Process"
    {
        "Fix Windows Network Media Throttle"
        {
            "HasRunKey"  "HKLM\Software\Valve\Steam\Apps\431960\disableNetworkThrottle"
            "process 1"  "%INSTALLDIR%\launcher.exe"
            "command 1"  "-disablenetworkthrottle"
            "NoCleanUp"  "1"
        }
    }
	"Firewall"
	{
		"Wallpaper Engine UI"		"%INSTALLDIR%\\bin\\wallpaperui.exe"
	}
}
"kvsignatures" { "InstallScript" "7a2dfd7…" }

Then it makes the %INSTALLDIR% pointing in its own folder, and call the SteamService with its SharedMemory IPC using Global\SteamClientService_SharedMemFile. This will trigger Steam to execute the launcher.exe (itself) with SYSTEM privileges. If Steam is not running, it will try to start the process.

However, an interresting check is made before the Steam technique is tried:

Steam elevation

The malware aborts this technique if a specific dll/companion file are not found in the LocalCache folder : it checks for a libcef.dll file, what looks like to be a companion .dat file, and a .exe having the same name the SteamLoader has. Thus, this file is either the SteamLoader malware itself or a file with the same name in the LocalCache folder. All of these files will be copied in a temporary folder, then installed and executed. However, the malware does not import/load any libcef.dll.

This does not make a lot of sense:

  • the malware is crafted to have the same behaviour the VMLoader has, without any obfuscation, which undermines completely the efforts put into the VMLoader development
  • it uses two different folders, the LocalCache and the Cache-XXXX, but nothing is ever copied in the LocalCache folder
  • it installs persistence for an undefined LocalCache .exe file, but nothing is ever copied in this folder by the malware
  • the only files to be written in the Cache-XXXX are the .bin file or .exe file fetched from the C2, however the .exe file is immediately ran with a simple Process.Start call. This executable will be written under the u.exe name, different of the malware's name. Thus it cannot be considered by the Steam routine
  • the Steam routine does not execute if the DLL file and its companion are not found. But it defaults on the malware itself which does not import this DLL
  • the Steam routine expects a file that looks like to be a GPULoader or VMLoader payload. However, the download routine is called only if the process runs in a High IL mode, skipping this routine. Moreoever, the GPULoader payload is downloaded in a x subfolder, thus it cannot be located in this folder. We don't know what is expected there
  • the GPULoader final payload is fetched in a zip archive, where the executable name might change, thus the whole Steam routine which expects a same executable name would not be correct
  • on the HighIL routine, the ScheduledTask routines run before the remote payload is fetched, therefore the folder will be empty
  • both the System and HighIL routines do the same thing, as they both create the same scheduled task with the same parameters. However the System does not fetch the remote payload

Consequently, for the Steam routine to be executed it would require another installation step beforehands, which would place other files in the LocalCache and Cache-XXXX folders. Nothing in the data we observed suggest this, and it would be quite illogic, as the stage1's purpose, as its decoy routine suggest, is to download and execute a payload in the most minimal possible way in order to avoid detection.

Therefore it results in a quite simple behaviour : an attempt of gaining HIGH IL privileges with a runas command, then a simple download/execute stream of a ZIP file using the EtherHiding host resolution.

FakeGuard

A binary named "SiteGuard" a7b829a5 is also present in most archives. We named it "FakeGuard" as it is a PyInstaller executable whose purpose is to carry out an AitM attack and code injection. To do so, it will:

  • generate a PC Site Guard Local CA CA and install it (PowerShell script)
  • install a system proxy via PAC (PowerShell script)
  • intercept and inject a JavaScript script into certain HTML pages
  • install a malicious Chrome MV3 extension Site Guard · Режим родителя ("parent mode") with proxy permission and access to https[:]//45.59.122.85/* only, allowing it to force the proxy installation
  • block access to certain sites
  • install Run-key persistence

This server allows executing commands on the infected system through basic cmd /c commands.

The C2 server is hardcoded: 45.59.122.85 but FakeGuard also uses the same EtherHiding mechanism to find these servers, polling the 0xc6a3 contract funded by 0x3695 (same wallet than the VMLoader one). This contract holds cleartext values:

Date (UTC) Value
2026-10-13 14:13 https[:]//167.88.172.111
2026-10-13 21:37 https[:]//153.92.223.113
2026-10-22 08:55 https[:]//72.60.20.149
2026-10-22 14:21 https[:]//191.96.1.36
2026-10-23 15:45 https[:]//72.60.20.149

The Python scripts carry Russian docstrings indicating the role of the JavaScript scripts fetched from the server:

  • passive sniffing of account balances (tied to the schwab_sid cookie and the schwab.com bank)
  • cookie theft for session replay
  • substitution of beneficiary IBAN/BTC/ETH/etc. during banking operations
Russian comments

Which can be translated as:

Intercept mode: full MITM of selected hosts with rewriting and reporting.

Domains from lab.json ("intercept") get the real site content with /__lab/inject.js injected instead of a block page; control and capture traffic (/__lab/*) goes to our panel. CA — the default SiteGuard (already trusted).

lab.json next to the client's data-dir:

Given the number of comments and their structure, this code may have been generated by an LLM in Russian.

This binary can also run basic remote commands (beaconing on the /api/device/commands endpoint, which can trigger execution via a call to cmd.exe /c). In the version studied, only schwab.com is targeted by the default configuration. However, the binary also fetches a remote configuration, and one of these — served from https[:]//45.59.122.85/routing/ — was recovered. It is much broader:

{"enabled":true,"domains":["akamaiedge.net","ally.com","americanexpress.com","avast.com","avcdn.net","bankofamerica.com","binance.com","bingx.com","bitdefender.com","bitfinex.com","bitget.com","bitmart.com","bitstamp.net","blob.core.windows.net","blockchain.com","broadcom.com","bybit.com","capitalone.com","cex.io","chase.com","checkappexec.microsoft.com","chime.com","citi.com","coinbase.com","core.windows.net","crl.microsoft.com","crypto.com","ctldl.windowsupdate.com","cwfservice.net","data.microsoft.com","definitionupdates.microsoft.com","delivery.mp.microsoft.com","discover.com","download.microsoft.com","download.windowsupdate.com","ecs.office.com","endpoint.security.microsoft.com","eset.com","events.data.microsoft.com","fe3cr.delivery.mp.microsoft.com","fidelity.com","gate.io","gemini.com","github.com","go.microsoft.com","htx.com","intuit.com","kaspersky-labs.com","kaspersky.com","kraken.com","kucoin.com","lbank.info","malwarebytes.com","mb-cosmos.com","mb-internal.com","mexc.com","mp.microsoft.com","mwbsys.com","navyfederal.org","norton.com","okx.com","paypal.com","pnc.com","poloniex.com","robinhood.com","schwab.com","settings-win.data.microsoft.com","siteguard.test","smartscreen-prod.microsoft.com","smartscreen.microsoft.com","sofi.com","symantec.com","symantecliveupdate.com","td.com","truist.com","update.microsoft.com","uphold.com","urs.microsoft.com","usaa.com","usbank.com","virustotal.com","vortex-win.data.microsoft.com","wd.microsoft.com","wdcp.microsoft.com","wdcpalt.microsoft.com","wellsfargo.com","windows.net","windowsupdate.com","wise.com"],"include_subdomains":true,"proxy":"PROXY 127.0.0.1:8877"};

A more recent one has the following values:

{"targets":[{"host":"ally.com"},{"host":"americanexpress.com"},{"host":"bankofamerica.com"},{"host":"binance.com"},{"host":"bingx.com"},{"host":"bitfinex.com"},{"host":"bitget.com"},{"host":"bitmart.com"},{"host":"bitstamp.net"},{"host":"blockchain.com"},{"host":"bybit.com"},{"host":"capitalone.com"},{"host":"cex.io"},{"host":"chase.com"},{"host":"chime.com"},{"host":"citi.com"},{"host":"coinbase.com"},{"host":"crypto.com"},{"host":"discover.com"},{"host":"fidelity.com"},{"host":"gate.io"},{"host":"gemini.com"},{"host":"github.com","quiet":true},{"host":"htx.com"},{"host":"intuit.com"},{"host":"kraken.com"},{"host":"kucoin.com"},{"host":"lbank.info"},{"host":"mexc.com"},{"host":"navyfederal.org"},{"host":"okx.com"},{"host":"paypal.com","watch":true},{"host":"pnc.com"},{"host":"poloniex.com"},{"host":"robinhood.com"},{"host":"schwab.com"},{"host":"sofi.com"},{"host":"td.com"},{"host":"truist.com"},{"host":"uphold.com"},{"host":"usaa.com"},{"host":"usbank.com"},{"host":"wellsfargo.com"},{"host":"wise.com"},{"host":"drive.google.com","quiet":true},{"host":"photos.google.com","quiet":true},{"host":"docs.google.com","quiet":true},{"host":"myaccount.google.com","quiet":true},{"host":"accounts.google.com"},{"host":"clients6.google.com","quiet":true},{"host":"etrade.com"}],"catchall":false,"exclusions":[],"swap":{},"gateCodes":false,"quietHosts":["github.com","drive.google.com","photos.google.com","docs.google.com","myaccount.google.com","clients6.google.com"],"watchHosts":["paypal.com"]}

The domains listed here mix two different functional groups: interception targets (banking and cryptocurrency) and blocking/tampering targets (system and antivirus updates).

The intercept.py docstrings mention 216.126.227.160 as a C2 server. This IP address could not be found in the smart contracts addresses nor in hardcoded values. It does not belong to the other C2s subnets.

Back in October, this website hosted a schwab.com phishing page, also LLM-generated, with an interesting comment:

Schwab phishing

Unfortunately, the website has been down since then, so we could not test the backend panel link displayed in the comment. In any case, this example shows that the propention of LLMs to put comments everywhere can lead to quite big opsec fails.

GPULoader

The binary masquerades as tempdir.dll, a utility component of IBM SPSS Statistics. It is loaded via sideloading by a legitimate IBM executable (sslconf.exe).

When loaded, it first runs the same checks as VMLoader, namely:

  • rejection of vendor IDs 0x1414 (Microsoft Basic Render), 0x15AD (VMware), 0x1234 (QEMU);
  • rejection of software adapters (DXGI_ADAPTER_FLAG_SOFTWARE flag);
  • at least 256 MB of dedicated VRAM or 1 GB of shared VRAM;
  • a card description longer than 11 characters.

Additional checks are also present:

  • a blacklist of FNV-1a hashes of graphics-card descriptions;
  • creation of a D3D11 device, then 16 operations executed with a performance measurement via QueryPerformanceCounter: if the measurement exceeds 30 ms, the check fails.

It then proceeds to read the companion file. The following files were identified:

  • license.dat
  • cwise.dat
  • spssaux.dat
  • uistate.bin
  • appcfg.dat
  • clientdat.bin
  • modules.dat
  • sslconfig.dat
  • settings.bin

The companion file size is hard-coded in the GPULoader binary, and a check is performed to make sure it is correct.

The malware then performs the decryption:

  • it uses the created D3D11 device to create GPU resources (decryption key, nonce, mask, size, input buffer, output buffer) via CreateBuffer, CreateShaderResourceView, CreateUnorderedAccessView
  • it creates a compute shader from a DXBC blob embedded in the DLL via CreateComputeShader
  • it maps the resources into the shader via CopyResource, CSSetShaderResources, CSSetUnorderedAccessViews, CSSetShader, CSSetConstantBuffers
  • it calls the shader's Dispatch method
  • it securely wipes the keys and shaders from memory

The shader is a compute shader implementing a standard AES-256-CTR algorithm, with a modification of the MixColumns matrix (3,1,1,3 instead of 3,1,1,2 on the 4th row). A key derivation is performed via an XOR with the mask parameter.

The decrypted payload carries a magic number 0xE85A8827 followed by a header defining several sections. This magic number changes between samples and therefore appears to be generated at build time for each version. There are 10 sections, each carrying a type.

Type Size Content
A 0x21D VM bytecode: AMSI bypass
B, D, E, F, G, I 8 each 0xC3 followed by 7 bytes, unknown role
C 0xDC VM bytecode: .NET bootstrap
H 0x432 VM bytecode: Run persistence
P 0x66E00 PE32+ .NET

The code runs the VM bytecodes A and C:

  • bytecode A is an AMSI bypass that hooks AmsiScanBuffer by creating a VectoredExceptionHandler and setting a hardware breakpoint on that function.
  • bytecode C is a .NET bootstrap that executes the .NET PE in memory. It uses mscoree.dll.CorBindToRuntime to instantiate the CLR v4.0.30319. The data is copied into a SAFEARRAY, then an Assembly.Load is performed, and the EntryPoint is finally called. This is a SectopRat binary.

This is the same VMP1 bytecode as in VMLoader.

Finally, a thread is created to install the malware:

  • it copies the 3 files (sslconf, tempdir and the companion file) into the \AppData\Roaming\Cisco AnyConnect Secure Mobility Client\Profile folder
  • it creates a scheduled task via the Task Scheduler COM API (ITaskService) named MicrosoftCompatibilityAppraiser
  • it runs bytecode H, which installs a TaskSchedulerHelperSvc Run key

The Run keys vary between samples:

  • TaskSchedulerHelperSvc
  • WindowsConfigurationService
  • DeviceCensusBackup
  • WlanExtensibilityProvider
  • UserNotificationListener
  • AppReadinessTrigger

The tasks also change, but are all located at the root:

  • MicrosoftCompatibilityAppraiser
  • AppxManifestRecoveryService
  • WindowsActivationTechnology
  • MicrosoftSearchIndexerHelper
  • DiagnosticsHubStandardCollectorWatcher
  • WerSvcRollbackTask
  • WindowsDefenderTaskExclude
  • BackgroundTaskInfrastructureHelper

GPULoader standalone

Using ExaLyze, we were able to determine that 10 functions are shared between GPULoader and the binary 925ad6253e84a28e0e2538b7492a991b0224a88f334f586880ade9ef6bbc59f2. These are notably functions used to load .NET payloads.

.Net loader diffing

See on ExaLyze

This is another version of GPULoader that does not load a companion file but embeds it directly.

SectopRat/ArechClient2 payload

The payload is a SectopRat sample similar to the one documented by Fortinet in the article https://www.fortinet.com/blog/threat-research/uncovering-a-sectoprat-variant-embedded-in-legitimate-software . Among other things, it enables:

  • Browser data theft: Chromium (Login Data, Web Data, cookies, app_bound_encrypted_key, payment cards) and Gecko (cookies.sqlite, logins), as well as Battle.net, Steam (ssfn), FileZilla, Discord, Telegram (tdata) and Opera GX.
  • Wallets and VPNs: about thirty wallet extensions (Metamask, Coinbase, Binance, Ronin, TronLink), NordVPN, OpenVPN and Proton.
  • Profiling: WMI (SecurityCenter2, Win32_Processor, VideoController, PhysicalMemory, DiskDrive, Process).
  • RAT: about 35 Receive* commands, including InitStealer, ShellJoinCommand, FileManager, ProcessManager, CaptureRequest, FullscreenRequest, DeployBrowserKey, GetBrowserKeys, SendCookieFile, RestartBot, RestartPC, UnInstall and LocalPluginInitModule (the RLib module).
  • Hidden desktop and keylogger: DesktopSwitch, NewKeyLog, ScreenFloat and BigDataToViewer messages.
  • Self-deletion: cmd /C choice /C Y /N /D Y /T 6 & Del "…".

Here again the C2 is obtained through the BSC blockchain, via contract 0xe012d0f34cde9b870e9d9ed566ea5f8fd9b92228, created on 2025-05-30 07:30:23 UTC in wallet 0xb57daeb4aa10f6a79e520218ec3c455f58c5fa12. The values are in the format START<base64 of 32 bytes>FINISH, with an AES IV and a block indicating the C2 address. The decrypted history is as follows:

Date (UTC) Block C2 set tx
2025-05-30 07:30 50564264 107.189.24.67 0xbee67ef3254b0a03…
2025-07-13 06:16 53852731 104.194.133.210 0x53af31e2137525cf…
2025-07-26 23:07 55431008 107.189.26.86 0x3971623905995eac…
2025-08-11 07:13 57197751 107.189.21.86 0x28fff2e04f81ebbe…
2025-08-22 06:54 58463287 45.59.124.17 0xe7304eea8a8f358b…
2025-09-05 08:08 60081583 45.59.125.228 0xe9df8a8f11e2eaaf…
2025-09-14 19:35 61173108 45.59.122.82 0xce76487c2b82ed42…
2025-09-24 09:27 62276165 107.189.17.143 0x1d49f1ac60244789…
2025-11-23 21:28 69242587 45.59.122.134 0xe7fec73e598b8318…
2025-12-03 12:03 70349146 45.59.122.235 0x3babd13ca56c89a9…
2025-12-09 08:17 71022045 107.189.22.118 0x30f84d5c829574e0…
2025-12-16 12:33 71848720 107.189.20.32 0x2aa22b8832edfbc9…
2025-12-29 06:20 73316071 107.189.20.95 0x9bdf94a2185ad705…
2026-01-10 18:21 74755980 107.189.24.255 0xd260eed320386091…
2026-01-28 11:37 77899791 45.59.117.145 0xf7c4e0109986438a…
2026-03-13 23:12 86438425 45.59.114.190 0x7991788b0612c371…
2026-04-03 21:32 90449755 45.59.123.122 0xe161379051eb0517…
2026-04-14 12:06 92483607 45.59.117.67 0x0eed829a935a19ed…
2026-04-20 11:21 93628000 195.110.58.222 0x790298a88f5c6a46…
2026-05-12 23:35 97944022 191.101.80.211 0xa8fa97fd38349ae9…
2026-06-12 17:09 103835922 2.24.131.246 0x2af54e35c71bd4f2…
2026-07-25 09:58 112030502 2.24.128.29 0x65906fa052ae592c…

A second contract 0xfdf3acb71c52889e5bb38e77512a7a18d292fe10 published by this wallet can also be found. It likewise holds values in the format START<base64 of 32 bytes>FINISH (an AES-encrypted block for SectopRat), and these are generally published a few minutes after updates to contract 0xe012d0f34cde9b870e9d9ed566ea5f8fd9b92228.

The oldest samples (compiled in May 2026) additionally include a browser-targeting module that modifies preferences and bundles a malicious extension titled "Google Docs" that logs every URL contacted and every "input"-type field change.

Blockchain pivot

Note: for readability, we have truncated wallet, contract and transaction identifiers here, but they can be viewed by clicking on them.

Each set transaction costs money, and wallet 0xb57d was funded by the gas hub 0x2a0d.

That hub has a very distinctive behavior: it only makes very small BNB transfers (0.015 to 0.027 BNB each) to 67 wallets since May 2025, which together published a total of 163 contracts. All of these contracts have identical bytecode, and 161 of them follow the START<base64 of 32 bytes>FINISH structure. Only one of them can be decrypted by the SectopRat payloads we extracted, which suggests the same holds for the other contracts, and that keys are used for other SectopRat campaigns.

The hub 0x2a0d created two test wallets, each holding a single contract:

  • 0x5914 created on 2025-05-07, holding TestBlabla
  • 0x21f8 created on 2025-05-07, holding dsfdsfsdfsdfsdfsdfsdfsdf

Pushing the investigation further, the hub 0xa6ab funds 0x2a0d, and we note that:

  • the overall provisioning of the gas hubs used is about 1.6 BNB
  • the total cost (publication and updates) comes to roughly 0.2 BNB, which represents about 10% of the allocated amounts
  • the funding comes mostly from the anonymous ChangeNOW and FixedFloat providers, but also from a wallet 0x39a9

Wallet 0x39a9 is particularly interesting:

Therefore:

  • it was initially funded by the Binance platform
  • it issued standard transactions between 2022 and 2023 and was then unused until 2025
  • it directly funds the SectopRat funnel
  • it created a SectopRat test contract

Note: for the uninitiated, a BSC wallet is provisioned via Hot Wallets. These act as cryptocurrency brokers and deliver funds to a wallet. Some perform KYC (Know Your Customer) and require the person to be identified (ID document, etc.). Others do not, and allow anonymous transactions. ChangeNOW, for instance, applies no KYC policy.

This wallet is particularly interesting because Binance enforces a KYC policy and therefore holds the identity of the person who performed the funding transactions for wallet 0x39a9.

It is therefore possible that this is a personal wallet belonging to the person providing SectopRat instances via EtherHiding, who may have forgotten they had credited it non-anonymously two years earlier, and used it for testing while developing the code.

Note: it is also possible that wallet 0x39a9 was stolen or handed over and then reused by the author. However, the fact that it was not used after the first test does not really fit that scenario, nor does the fact that the currency used to originally create the account and during the initial SectopRat deployment is identical.

The observed deposits (about $1,140) are as follows:

Amount (USD at the then-current rate) Date Platform used Wallet
55.55 2022-05-08 Binance 0x39a9
109.91 2025-04-04 ChangeNOW 0x39a9
28.51 2025-05-07 ChangeNOW 0x39a9
251.50 2025-04-05 ChangeNOW 0xa6AB
500.97 2025-05-07 FixedFloat 0xa6AB
31.79 2026-04-22 FixedFloat 0x2a0d
54.49 2026-07-13 FixedFloat 0x2a0d
107.14 2026-08-12 FixedFloat 0x2a0d

Detection

Despite the attacker's efforts, detection is fairly straightforward. First, it is possible to monitor the Ethereum smart contracts created by the identified wallets, then decode the various identified values when they are in cleartext.

Beyond the IOCs, it is also possible to identify:

  • a tempdir.dll / sslconf.exe / companion file triplet in a Cisco AnyConnect Secure Mobility Client folder
  • an %APPDATA%\EdgeUpdate- folder with a suffix
  • a %LOCALAPPDATA%\SiteGuard\ folder
  • jcef_helper.exe renamed and outside its JetBrains location
  • resolution of / traffic to bsc-dataseed*.binance.org from a host with no crypto context
  • the local CA PC Site Guard Local CA
  • installation of a local proxy on port 8877
  • Cyrillic homoglyphs in standard executable names such as Chrome.exe

Campaign

This VMLoader/GPULoader campaign has been running since April 2026, although the C2s of the SectopRat payloads have been present since May 2025. The identified ZIP archives target installations of the following software:

  • Claude Desktop
  • Google Chrome
  • Exodus
  • Docker Desktop

Crimeware operations like this one usually split across several distinct actors — stealer developer, loader/dropper developer, MaaS broker, operators, money-laundering — which do not necessarily overlap, so we cannot strongly tie every brick together.

That said, several observations point to a single self-contained operation rather than a kit resold to many customers:

  • we did not find any other VMLoader/SteamLoader/GPULoader configuration contract
  • the FakeGuard C2 hub is pinned in a smart contract deployed by the same wallet that manages the VMLoader/SteamLoader contracts
  • across all FakeGuard samples, none uses a different contract
  • every payload we recovered resolves to a single SectopRat C2 channel

We therefore assess that, for now, these loaders are not sold to third parties beyond the actor described here.

Given the workflow and commands, it is clear that the SteamLoader and VMLoader were built by the same entity: it uses the same contract, the same workflow, commands and strings to download, extract and execute the payload it downloads. However, if it is not shipped with any other files (which we believe), the SteamLoader is clearly poorly made. The FakeGuard malware and C2 being very probably vibecoded, we believe that the SteamLoader malware was too. And as it was used operationnaly besides the program being quite illogical, we think that the VMLoader and GPULoader might also have been vibecoded too. However we do not have any proof to attest it.

Now, if we focus on these TTPs, they appear to be very similar to the elements described by Arctic Wolf in their GPUGate article :

  • download of a ZIP archive from a "zip.php" URL and execution of the contained executables, which include a sideload
  • GPU-based decryption of the payload
  • addition of Windows Defender exclusions for a folder
  • execution gating based on the system's graphics specifics, in particular the length of the card name
  • C2 servers located in highly similar network ranges (107.189/16, 45.59/16, 104.194/16)
  • propagation via malvertising targeting IT-related software

When looking at the other SectopRat smart contracts, we found that 135 newer contracts were emitted since the creation of the one linked to this campaign. The one used by the payload was created on the first activity month (May 2025) and lots of SectopRat related samples to the same contract can be found on VirusTotal since then. For instance, one of them was delivered with the 6832faa4f ZIP archive. It embeds the payload in a XOR-encrypted file.

Conclusion

GPULoader and VMLoader are the product of a deliberate engineering effort. Rather than piling on packers, their author reached for mechanisms that are genuinely hard for defenders to replay at scale: a decryption routine that only runs correctly on a real GPU, a custom stack-based virtual machine that hides the sensitive logic (anti-analysis, EDR unhooking, persistence, C2 retrieval) behind an opcode dispatcher, and hardware fingerprinting that filters out emulators, software renderers and under-specified sandboxes before any malicious behavior is exposed. The GPU step is the centerpiece: a sandbox without a non-blacklisted GPU/emulator would never see the payload decryption, and the modified AES MixColumns matrix means even a correct key fails against a stock AES implementation.

For now, we assess that the VMLoader/GPULoader/FakeGuard toolset is developed and maintained by a single threat actor, very likely the same one behind the GPUGate toolset described by Arctic Wolf in 2025. Whether these campaigns are operated by that actor directly or by one or more customers, and whether the same operator is behind both GPUGate and this campaign remains unclear.

The SectopRat analysis was not expected as we first wanted to focus only on the loaders because of their technical aspect. By analyzing the Etherhiding C2 chain, we quickly focused on this mechanism, and identified the old 0x39a9 wallet which seemed to be an operational secrurity mistake by one of the SectopRat operators, as it was once topped up from a KYC-enforcing Binance hot wallet years before being repurposed for SectopRat.

Finally, the fact that a test C2 IP address was retrieved in the FakeGuard docstrings highlights the fact that generating malware with LLMs can lead to such leaks. We do not know how many tools were crafted using such techniques: both the FakeGuard and its C2 counterpart are very probably generated as such, and we think that the SteamLoader is also AI-generated. However we do not know wether the VMLoader and GPULoader are, but it would not be suprising at all if they were.

IOCs

Sha256

REMARK THIS SECTION IS NOT EXHAUSTIVE, ONLY A SUBSET IS PROVIDED

VMLoader phishing ZIP
  • e44f3dfc256c31747b2987c577a562ec934646b2a7836c719855842c9d4dc3f7
  • 3b7846908b421681ad1c3a04203f869a3bdb5226300ae0924be549b55cd9ca96
  • 8d1a8317c635854145960b608756b048ed787ecc91daff5e1ec4117563ddc2d2
  • 03d7e03ffd380044a13228eeee22c11f8bd2d20f1880105a3a87bf721fdcb595
  • 197b6c515cbb9696f3ba1b8a40857189e9de8fc9fa7787fa3e154c9fcf3ea31c
VMLoader stage 2 ZIP
  • 5bd4654b855f853691ff4d21ab0e22b596ce909d8ae779cb685c810b6b3f0275
  • 6c2b73e3974c81280c0d0ad31db612401ed8137c0f35dc6d67c2bc61e6614c67
  • 80e4fa61a03c5aa06fa1fc5cdb19b47a77efdc52d476d26a4b4d1c1e2cae4a7b
  • bce2def5c8f11e4458df143cad0dcff9b817b89ffed3a0aae812ad6da23eced5
  • 7d71219b61cbfa5a251df9a185e4abb7aaeb15e76b23529e5d2ebfd2a30c0f73
GPULoader Companion files
  • 6dfecc6121ebf2d31bcf0f227574c905229a42cee9b05cd811f94a8e91f5734c
  • 4cf82033e30ba3cbab82433ff5e5985be0ad3ed4406e0c5ca8766b8b3728fcca
  • c1f474069c0bb9d81f60c8f83da0915158501d54db54f7a9b18c1a62067bc923
  • 1a8f050df20359e675f80e140cf48f5be1f0659c8a98450c43d255254fb53b97
  • 62f7c0fdf2fbfd0e517a39c313bfe0245139617ef226b4fc01a0eb6054880fd3
VMLoader DLL
GPULoader DLL

Paths

  • %LOCALAPPDATA%\SiteGuard\browser-extension
  • %LOCALAPPDATA%\SiteGuard\
  • %APPDATA%\EdgeUpdate-<8hex>\
  • %APPDATA%\Cisco AnyConnect Secure Mobility Client\Profile\

Mutex

  • Global\DefenderHydrationGate
  • Global\OneDriveStandaloneCache
  • Global\MicrosoftEdgeRolloutSync
  • Global\TaskHostSchedulerGate
  • Global\WindowsTelemetryDataAcq

Commands

Note: in the commands below, <MALWAREPATH> is replaced by the path of the malicious code:

  • powershell -NoProfile -Command Add-MpPreference -ExclusionPath 'C:\Users'
  • schtasks /create /tn "MicrosoftEdgeUpdate" /tr "<MALWAREPATH>" /sc onlogon /rl highest /f
  • cmd /c cd /d "\u" && tar.exe -xf "<MALWAREPATH>\update.bin"
  • cmd /c for /r "\u" %f in (*.exe) do @start "" /d "%~dpf" "%~f"
  • cmd /C choice /C Y /N /D Y /T 6 & Del <MALWAREPATH>

Run keys

  • DefenderTelemetryService
  • MicrosoftEdgeUpdateTaskMachine
  • TaskSchedulerHelperSvc
  • WindowsConfigurationService
  • WindowsTempCleanupSvc
  • OneDriveStandaloneUpdater
  • TaskSchedulerHelperSvc
  • WindowsConfigurationService
  • DeviceCensusBackup
  • WlanExtensibilityProvider
  • UserNotificationListener
  • AppReadinessTrigger

Scheduled tasks

  • Task MicrosoftEdgeUpdate running a program in a folder prefixed with EdgeUpdate-.

The following tasks have legitimate-looking names, but unlike the malicious ones, legitimate tasks are never located at the root:

  • MicrosoftCompatibilityAppraiser
  • AppxManifestRecoveryService
  • WindowsActivationTechnology
  • MicrosoftSearchIndexerHelper
  • DiagnosticsHubStandardCollectorWatcher
  • WerSvcRollbackTask
  • WindowsDefenderTaskExclude
  • BackgroundTaskInfrastructureHelper

C2

VMLoader
  • neeitoerw[.]my
  • legsotier[.]us
  • neeitoerw[.]my
  • apisue[.]click
  • zippis[.]xyz
  • faceitzip[.]xyz
  • arzipi[.]xyz
FakeGuard
  • 45.59.122.85
  • 216.126.227.160 (mentioned)
  • 167.88.172.111
  • 153.92.223.113
  • 72.60.20.149
  • 191.96.1.36
SectopRat
  • 2.24.131.246
  • 2.24.128.29
  • 45.59.114.190
  • 45.59.117.67
  • 45.59.117.145
  • 45.59.122.82
  • 45.59.123.122
  • 45.59.122.134
  • 45.59.122.235
  • 45.59.124.17
  • 45.59.125.228
  • 104.194.133.210
  • 107.189.17.143
  • 107.189.24.67
  • 107.189.26.86
  • 107.189.21.86
  • 107.189.22.118
  • 107.189.20.32
  • 107.189.20.95
  • 107.189.24.255
  • 195.110.58.222
  • 191.101.80.211