ca6be0bf2f87f1998bfe4ba762d59bfa43a574fb011b4d19d587d83763c5c64fdolphin: ca6be0bf — Rust x64 polymorphic RAT/stealer with 80+ task types, WebSocket C2, masquerading as NVIDIA Display Container LS
Executive Summary
A 5.9 MB Rust x64 PE32+ GUI binary, internally self-identifying as dolphin. It is a builder-configurable polymorphic RAT/infostealer with a WebSocket-over-TLS C2 at dolphin.dark-matter-analytics.com:32768, an embedded AES-GCM encrypted configuration, and an extensive tasking surface (~80 distinct ServerMessage commands). It masquerades as "NVIDIA Display Container LS" (version 560.81), mashes browser credentials via DPAPI, injects JavaScript into Electron apps (Bitwarden, Exodus, Ledger, Atomic, Telegram, Discord), targets 200+ gaming clients, and runs a crypto-address clipper. Anti-analysis includes anti-VM, anti-debug, and self-morphing to a new PE in TEMP (poly / meta / ultra modes). Static-only: CAPE was unavailable for x64 Windows at time of analysis.^[dynamic-analysis.md]
What It Is
| Field | Value |
|---|---|
| SHA-256 | ca6be0bf2f87f1998bfe4ba762d59bfa43a574fb011b4d19d587d83763c5c64f |
| Size | 5,949,440 bytes |
| Type | PE32+ executable (GUI) x86-64, 7 sections^[file.txt] |
| Compiler | Rust — rustc 59807616e1fa2540724bfbac14d7976d7e4a3860, MSVC linker 14.44 (Visual Studio 2022)^[rabin2-info.txt]^[exiftool.json] |
| Crate stack | tokio 1.52.1, tokio-tungstenite 0.21.0, serde_json 1.0.149, chrono 0.4.44, zip 0.6.6, tracing-core 0.1.36, bcrypt (via bcryptprimitives.dll), gdiplus (screenshots)^[strings.txt:10513]^[strings.txt:10537]^[strings.txt:10571]^[strings.txt:10580] |
| PDB | java_update_scheduler_557655.pdb^[rabin2-info.txt] |
| VersionInfo | NVIDIA Display Container LS — product_name 560.81, FileDescription hstsvc, LegalCopyright (c) 2024 NVIDIA Corporation^[pefile.txt] |
| Signed | false^[rabin2-info.txt] |
| IAT | ~350 imports across KERNEL32, ADVAPI32, CRYPT32, WS2_32, NTDLL, USER32, GDI32, GDIPlus, OLE32, OLEAUT32, IPHLPAPI, MPR, SHELL32, SETUPAPI, MFPlat, MFReadWrite, WINMM, POWRPROF, SECUR32, NETAPI32, WTSAPI32, WEVTAPI, BCRYPT^pefile.txt |
| Packing | None — native Rust binary, no UPX/VMProtect/themida. Section entropies: .xdata3 6.33, .rdata3 5.93, .rsrc0 6.22, .datax 7.97^[pefile.txt] |
| Config | AES-GCM encrypted JSON blob; decrypts via CryptUnprotectData or BCrypt fallback. Hardcoded defaults embedded in binary include C2 host, port, TLS, auth token, morph mode, loot toggles^[strings.txt:14419]^[strings.txt:14455] |
The builder produces binaries with toggles for anti_analysis, morph_mode (Off / Poly / Meta / Ultra), melt, deferred_morph, critical_process, block_russian_egress, loot_gaming, loot_messengers, loot_email, loot_vpn, loot_webcam, loot_clipboard, persist, and ~12 UAC-bypass / privilege-escalation methods^[strings.txt:13819]^[strings.txt:13843].
How It Works
Boot & Decryption
On launch the binary attempts to decrypt an embedded config JSON. The decryption path tries CryptUnprotectData (DPAPI) first, then falls back to BCryptGenerateSymmetricKey / BCryptDecrypt with AES-GCM. If decryption fails, a set of plaintext hardcoded defaults is used as fallback^[strings.txt:12070]. The config schema fields are fully self-describing via Serde-derived JSON: server_host, server_port, use_tls, tls_fingerprint, install_path (e.g. appdata), product_name, tag, persistent, anti_analysis, morph_mode, melt, deferred_morph, reconnect_delay_secs, heartbeat_interval_secs, fallback_hosts, dead_drops, cdn_front_domain, asn_bypass_token, ws_auth_token, uac_method, anti_bot, block_russian_egress, and per-loot booleans^[strings.txt:10523]^[strings.txt:14419].
C2 & Tasking
After config decryption, the agent resolves its public IP via a hardcoded list of IP checkers (api.ipify.org, checkip.amazonaws.com, ifconfig.me, icanhazip.com), builds a Hello / TaskAssign handshake over a tokio-tungstenite WebSocket, and sends periodic heartbeats (default 5s). C2 messages are defined by a large ServerMessage adjacently-tagged enum with 80+ variants^[strings.txt:10775]^[strings.txt:18552].
Observable categories:
- Discovery & System Info:
GetSystemInfo,GetPublicIp,Ping,NetworkScan,GetDnsCache,EnvRecon,PrivescScan,ProcessList,ProcessStringScan,ProfilerStart/Stop - Credential & Data Theft:
BrowserSave,BrowserHttpInterceptStart/Stop,TokenStealAll,EnrichDiscordTokens,WalletInject,WalletExtract,WalletInjectAllExtensions,AppInject,ClipboardGet/Set,KeyloggerStart/Stop,KeyloggerDump,MicCapture,MicStreamStart/Stop,WebcamCapture,ScreenRecordStart/Stop,SmartScreenshotStart/Stop,WifiHarvest,CredManagerDump,FileHunt,HostsRead,HostsAdd,HostsRemove,ExportAll,ExportAllSelective - Remote Access & Surveillance:
VncStart/Stop,HiddenVncStart/Stop,ShellCommand,ShellInput,ShellClose,ReverseShellConnect,BindShellListen,TtsSpeak,ChatSend,ChatClose,OpenUrl,ScreenRecordStart,PlayAudioChunk - Lateral Movement & Propagation:
LateralWmi,LateralWinrm,LateralSmb,LateralDeploy,LateralDiscover,UsbSpreadNow,UsbSpreadMonitorStart/Stop - Persistence & Privilege Escalation:
AddStartupEntry,RemoveStartupEntry,CreateScheduledTask,DeleteScheduledTask,ToggleScheduledTask,ScheduledTaskModified,GetScheduledTasks,UacElevate,UacCheckStatus,UacDisablePolicy,PotatoEscalate - Defense Evasion & Anti-Forensics:
BotKill,CleanTraces,KillSwitch,WipeEventLogs,WipePrefetch,WipeRecent,WipeTemp,WipePsHist,WipeThumbs,DisableVss,BlockUpdates,UnblockUpdates,BlockDefenderSubmissions,KillDefenderServices,BlockAVUpdatesOnly,ChangeDns,RestoreDns,DefenderExcludePath,DefenderExcludeProcess,DefenderDisableRealtime,DefenderAutoExclude,DefenderListExclusions,DefenderResult - Network Pivoting & Proxy:
ProxyConnect,ProxyClose,PortForwardStart/Stop,PortForwardList,UPnpProxyStart/Stop,Socks5Start/Stop,RevSocksStart/Stop,RevSocksConnect,MeshRelay,MeshPing - Process Manipulation:
DllInject,ProcessHollow,ShellcodeInject,ProcessDump,KillProcess,KillProcessByName - Misc / Impact:
MinerStart/Stop,MinerDeploy,MinerGetStatus,StressStart/Stop,StressStopAll,DownloadTestStart/Stop,DiskSpam,VolumeMax,MessageBoxSpam,SetWallpaperColor,TaskbarToggle,InvertScreen,MouseJitter,SwapMouseButtons,SetMouseSpeed,HideCursor,RotateScreen,FakeFreeze,FakeUpdate,MatrixRain,EarRape,CdTrayTrigger,Bsod,MonitorPower,SelfUpdate,InstallUpdate,RemoveUser,CreateUser
Browser & Wallet Injection
Fully embedded JavaScript payloads hook Electron IPC for:
- Bitwarden — intercepts
login,unlock,masterPassword,setPassword; also hooks webRequest forapi.bitwarden.comandvault.bitwarden.comcalls^[strings.txt:10802]^[strings.txt:10837] - Exodus — hooks
exodus.sendTransaction,exodus.signMessage,exodus.unlockWallet,EXODUS_UNLOCK,EXODUS_SEED,EXODUS_EXPORT_PRIVATE_KEY; targetsexodus.wallet.seco.jsonseed files andpassphrase.json^[strings.txt:10940]^[strings.txt:10984] - Ledger Live — hooks
ledger-sign-transaction,ledger-sign-personal,sign-eth,sign-bitcoin; snares swap/buy endpoints and HID transport layer^[strings.txt:10858]^[strings.txt:10865] - Atomic Wallet — hooks
UNLOCK_WALLET,CREATE_WALLET,IMPORT_WALLET; targetsleveldbfor raw mnemonic extraction^[strings.txt:11013] - Telegram Desktop — extracts
tdatadirectory^[strings.txt:11000] - Discord — collects tokens from
tokens/discord_tokens.txt, injects into the client, and runs enrichment^[strings.txt:11119]^[strings.txt:13109]
The injection writes collected data to %TEMP%/.dolphin_app.dat, then relays it back to C2 as AppInjectResult / TokenStealResult messages^[strings.txt:10799]^[strings.txt:10854].
Gaming Loot
The binary enumerates 200+ gaming-related process names: every major title from Counter-Strike / Valorant / Apex / Fortnite / PUBG / Call of Duty / Rainbow Six / Destiny / Halo / Rust / DayZ / GTA V / League of Legends / Dota 2 to niche titles like Phasmophobia, Lethal Company, Palworld, Enshrouded, Wuthering Waves, plus launchers (Steam, Epic, GOG Galaxy, EA Desktop, Bethesda, Battle.net, GamePass, Xbox) and overlay/capture tools (Bandicam, Fraps, MSI Afterburner, GeForce Experience, Parsec, Moonlight). The intent is to harvest session tokens, saved credentials, and in-game inventory^[strings.txt:13637]^[strings.txt:13643].
Crypto Clipper
A ClipperStart / ClipperStop task monitors clipboard for cryptocurrency address patterns (BTC, ETH, LTC, XMR, SOL, TRX) and replaces them with attacker-controlled addresses^[strings.txt:10705]^[strings.txt:10780].
Polymorphic Morph / Melt
The svc\polymorph.rs module implements four morph modes^[strings.txt:13843]^[strings.txt:18144]:
- Poly — rewrites the running binary in-place with a polymorphic variant
- Meta — creates a morphed copy in TEMP and spawns a child
- Ultra — same as Meta but with additional anti-signature jitter
- Melt — deletes the original after child spawn
If deferred_morph is true, persistence is installed first and the morph happens afterward. The module also attempts to writeback a modified image with mismatched CRC to frustrate hash-based blocking^[strings.txt:18296]^[strings.txt:18304].
Anti-Analysis
- Anti-VM / anti-debug toggles referenced in builder strings; explicit warning strings: "WARNING: ANTI-VM IS ON -- will exit if VM/debugger detected"^[strings.txt:13819]
- Stack spoofing via
svc\stack_spoof.rs^[strings.txt:11078] CheckRemoteDebuggerPresentandIsDebuggerPresentimported^[pefile.txt]- Critical-process protection (
RtlSetProcessIsCritical,NtRaiseHardError)^[pefile.txt]
Decompiled Behavior
No Ghidra decompilation was performed because the binary is a large native Rust artifact with heavy async runtime boilerplate; capa signatures were also unavailable (signature path missing)^[capa.txt]. Analysis is therefore strings- and import-driven. XREF mapping was not pursued on the 5.9 MB image given the density of tokio/serde macro-generated code, which yields low signal-to-noise in pseudo-C.
C2 Infrastructure
| Indicator | Value |
|---|---|
| Primary C2 | dolphin.dark-matter-analytics.com:32768^[strings.txt:14455] |
| Protocol | WebSocket over TLS (use_tls: true)^[strings.txt:14460] |
| WS auth token | f58d15520b35a1c619914048470bf17cf262b61cc994b4b8347e71a26d15e729^[strings.txt:14462] |
| Heartbeat | 5 seconds^[strings.txt:14431] |
| Reconnect delay | 10 seconds^[strings.txt:14454] |
| IP checkers | api.ipify.org, checkip.amazonaws.com, ifconfig.me, icanhazip.com^[strings.txt:14455] |
| Fallback hosts | empty in this sample^[strings.txt:14455] |
| Dead drops | empty^[strings.txt:14455] |
| CDN front | empty^[strings.txt:14460] |
| E2E cipher | dolphin-e2e-aes256gcm-v1^[strings.txt:12069] |
| Named pipes | \\.\pipe\dolphin_http_hook_<pid> used for browser HTTP interception^[strings.txt:17469]^[strings.txt:17721] |
| Log files | %TEMP%/dolphin_agent.log, dolphin_agent_fallback.log, dolphin_protection.log^[strings.txt:13709]^[strings.txt:15763] |
| DLL inject helper | dolphin_http_hook.dll / dolphin_http_hook.pdb^[strings.txt:17612]^[strings.txt:17646] |
| Hardcoded user-agent / branding | mfa.svc\discord_token.rs (joke/reference), separator string dQw4w9WgXcQ (YouTube Rickroll ID)^[strings.txt:11119] |
No secondary C2 or DGA observed in this sample. The dead_drops and fallback_hosts fields are empty strings in the default config, suggesting a single-tenant builder deployment.
Interesting Tidbits
- The builder leaks internal project names:
hedgehog,pledge, anddolphinall appear as identifier strings^[strings.txt:11535]^[strings.txt:11758].dolphinis the dominant runtime branding. - The masquerade is deep: not just the
NVIDIA Display Container LSversion resource, but also service-host style log strings likeInitializing service configuration...Service started successfully...^[strings.txt:14398] and a fabricatedWindows Service Host Runtime v10.0.22621banner. - The builder includes a geographic block toggle:
block_russian_egress: trueby default^[strings.txt:14421]. This is an OPSEC / localization gate, not an anti-VM check. - E2E key exchange uses a custom
dolphin-e2e-aes256gcm-v1protocol, likely a builder-specific handshake to encrypt task traffic inside the already-TLS WebSocket^[strings.txt:12069]. - The Discord token module path is literally
dQw4w9WgXcQ:mfa.svc\discord_token.rs, mixing a Rickroll YouTube ID with the Microsoft MFA service name. Author humour or deliberately misleading string for analysts^[strings.txt:11119]. - Browser DPI awareness and screen-capture use
SetThreadDpiAwarenessContext,EnumDisplayMonitors,GetDeviceCaps, and GDI+GdipSaveImageToStreamfor high-resolution screenshots^[pefile.txt]. - Clipboard monitoring and crypto-address replacement are modular tasks rather than hardcoded loops, implying the builder can ship clipper-only or stealer-only variants.
How To Mess With It (Homelab Replication)
Toolchain: Rust nightly ~2024 (rustc hash 59807616e1fa2540724bfbac14d7976d7e4a3860), Windows x64 target, tokio 1.52, tokio-tungstenite 0.21, serde_json, chrono, bcrypt, gdiplus-sys.
- Create a Rust binary crate with
tokio::main,tokio-tungsteniteWebSocket client,serde_jsonconfig struct matching the builder schema. - Embed a JSON config as an AES-GCM ciphertext blob. Decrypt at startup via
windows::Win32::Security::Cryptography::CryptUnprotectData(DPAPI) orBCryptDecrypt. - Use
winapi/windows-rsfor IAT imports: registry, service, process/thread, named pipes, DPAPI, BCrypt. - For browser injection: ship an Electron preload script as a string constant, inject it via
CreateRemoteThreadorSetWindowsHookExinto the target renderer process. - Enumerate gaming processes by name via
CreateToolhelp32Snapshot. - Clipper: monitor
WM_CLIPBOARDUPDATE/GetClipboardData, regex-match(bc1|[13])[a-zA-Z0-9]{25,62}for BTC,0x[a-fA-F0-9]{40}for ETH, etc, and replace with attacker addresses viaSetClipboardData.
Verification step: Build a minimal variant with morph_mode: "Off", anti_analysis: false, loot_gaming: true, and run strings on the output. You should see the same tokio-1.52.1, tokio-tungstenite-0.21.0, serde_json-1.0.149 registry paths and the dolphin task enum variants.
Deployable Signatures
YARA Rule
rule dolphin_rust_stealer {
meta:
author = "pp-hermes"
date = "2026-05-30"
description = "Dolphin Rust RAT/stealer — polymorphic, WebSocket C2, browser/wallet injector"
family = "dolphin"
hash = "ca6be0bf2f87f1998bfe4ba762d59bfa43a574fb011b4d19d587d83763c5c64f"
confidence = "high"
strings:
$s1 = "dolphin.dark-matter-analytics.com" ascii wide
$s2 = "svc\\polymorph.rs" ascii wide
$s3 = "dolphin_agent.log" ascii wide
$s4 = "dolphin-e2e-aes256gcm-v1" ascii wide
$s5 = "java_update_scheduler_557655::" ascii wide
$s6 = "dolphin_app.dat" ascii wide
$s7 = "dolphin_http_hook.dll" ascii wide
$s8 = "\\.\\pipe\\dolphin_http_hook_" ascii wide
$s9 = "ServerMessage::BrowserHttpIntercept" ascii wide
$s10 = "ServerMessage::TokenStealAll" ascii wide
$m1 = { 4D 5A } // MZ
condition:
$m1 at 0 and
(2 of ($s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10))
}
Sigma Rule
title: Dolphin Rust RAT Process Spawn and Network Connection
status: stable
description: Detects a process masquerading as NVIDIA Display Container LS spawned from a non-canonical path, or network connections to *.dark-matter-analytics.com
logsource:
category: process_creation
product: windows
detection:
selection_process:
- Image|endswith: 'NVIDIA Display Container LS.exe'
- CommandLine|contains: 'RuntimeBroker.alive'
selection_path:
Image|contains:
- '\AppData\'
- '\Temp\'
- '\ProgramData\'
selection_network:
DestinationHostname|endswith: '.dark-matter-analytics.com'
condition: (selection_process and selection_path) or selection_network
falsepositives:
- None expected for .dark-matter-analytics.com
- Very low for RuntimeBroker.alive masquerade
level: critical
IOC List
| Category | Indicator |
|---|---|
| C2 domain | dolphin.dark-matter-analytics.com |
| C2 port | 32768 |
| WebSocket auth token | f58d15520b35a1c619914048470bf17cf262b61cc994b4b8347e71a26d15e729 |
| Named pipe prefix | \\.\pipe\dolphin_http_hook_ |
| Temp data files | %TEMP%\.dolphin_app.dat, %TEMP%\.dolphin_dc.dat, %TEMP%\.dolphin_wl.dat |
| Log files | %TEMP%\dolphin_agent.log, %TEMP%\dolphin_agent_fallback.log, %TEMP%\dolphin_protection.log |
| Injector DLL | dolphin_http_hook.dll |
| Registry run | Matches NVIDIA Display Container LS in non-System32 path |
| Masquerade image name | NVIDIA Display Container LS with parent /AppData/Local/ or /Temp/ |
Behavioral Fingerprint
This binary is a large (5–6 MB) x64 Rust executable with no packing but extremely rich imports (350+, spanning crypto, networking, media, registry, services, and WMI/SMB). It spawns from a user-writable directory while claiming the image name "NVIDIA Display Container LS". Within 5–10 seconds it resolves public IP via well-known checkers, then opens a TLS WebSocket to a hardcoded host. It creates named pipes with prefix dolphin_http_hook_, writes small .dolphin_*.dat files to TEMP, and may inject JavaScript into Electron renderer processes if Bitwarden, Exodus, Ledger, Telegram, or Discord are running. Network traffic is WebSocket-framed JSON with serialized ServerMessage enums.
References
- dolphin — family entity page (capabilities, build stack, TTPs)
- rust-async-rat-framework — technique page documenting the Rust/tokio/tungstenite builder pattern observed here
- Sample source: MalwareBazaar via OpenCTI connector, label
dropped-by-gcleaner^[triage.json]
Provenance
file.txt— PE32+ x64, 7 sections^[file.txt]exiftool.json— linker version 14.44, subsystem GUI^[exiftool.json]pefile.txt— full import table, version resource, section entropy^[pefile.txt]rabin2-info.txt— PDB path, Rust language marker, no signing^[rabin2-info.txt]strings.txt— builder config, task enums, C2 host, embedded JS, internal module paths (ca. 21,422 lines of output)^[strings.txt]binwalk.txt— no embedded archive or packer detected; header-only PE at offset 0^[binwalk.txt]capa.txt— capa signature directory missing; no capability extraction performed^[capa.txt]dynamic-analysis.md— CAPE skipped; no Windows x64 guest available^[dynamic-analysis.md]