Skip to content

PureLogs: Reverse Engineering a .NET RAT From the PureCoder Ecosystem

Kirk
24 min read
malwarerat.netincident-responsepurelogspurecoder
On this page

We recovered a ConfuserEx-protected .NET assembly from a multi-stage intrusion. At the time of recovery it had zero detections on VirusTotal and zero public intelligence. No OSINT, no vendor reports. After first submission, 26 of 72 engines flagged it as trojan.tedy/msil, a generic label with no family attribution. As of 2026-02-26, the sample is 37 of 76 with the same generic naming and no family-level label. Everything below comes from static analysis and string decryption of the binary itself.

Update: Subsequent investigation identified this sample as PureLogs (internally "Plog"), a component of the PureCoder malware-as-a-service ecosystem. The campaign has been publicly tracked by Securonix as SERPENTINE#CLOUD, with additional reporting from Check Point Research, Fortinet, and eSentire. The C2 infrastructure is shared with other PureCoder tools including PureHVNC. The original analysis below remains unchanged. Attribution details are in the attribution section.


Tria.ge refresh (2026-02-26)

A Tria.ge refresh was run across seven campaign artifacts recovered during this case. Results:

Artifact SHA256 Tria.ge ID Score Family Key signatures
Mvfsxog.dll (core DLL) 046d0e83c1e6dcaf526127b81b962042e495f5ae3a748f3a9452be62f905acf8 260226-mszn4sbx2b 3 - Unsigned PE
Qdjlj.dll (Oct05 inner assembly) cdf87d68885caa3e94713ded9dd5e51c39b7bc7ef9bf7d63a4ff5ab917a96b36 260226-mszzwabx2c 3 - Unsigned PE
Fviwknzr.exe (Oct05 outer loader) dcd22d338a0bc4cf615d126b84dfcda149a34cf18bc43b85f16142dfb019e608 260226-na81hacs3e 7 - Unsigned PE, AddClipboardFormatListener, AdjustPrivilegeToken, SetWindowsHookEx
Nov19 extracted assembly 60bea9b2f30f77785cc1c12a0436123330a36847ac427a3accf73da02241b04b 260226-ms1amsbx2d 10 donutloader Detects DonutLoader, Donutloader family, NtCreateUserProcessOtherParentProcess
Nov19 extracted .NET payload 7040fe9721b7ed070f84c47280b6659aaec1eea0fa110af74ba2093d6e20d237 260226-ms1leabx2e 10 donutloader Detects DonutLoader, Donutloader family
Nov10 campaign executable 0ab09a4787ea9cb259cadd3f811a56f7bd0058287634bbaf0388b2cd40464505 260226-mt3gdsbx4g 3 - Unsigned PE, AdjustPrivilegeToken
Nov19 campaign executable b1c6659ee4ee35540f5ed043b611ac88a7fce9dc2f564168e7d47c43683163f6 260226-mt3r6abx4h 3 - Unsigned PE, AdjustPrivilegeToken

The two Nov19 extracted artifacts were classified as donutloader at score 10. The core PureLogs DLL (Mvfsxog.dll) and Oct05 fat client (Qdjlj.dll) remained unclassified in this refresh run (score 3, unsigned-PE signatures only). The Oct05 outer loader (Fviwknzr.exe) scored 7 with loader-stage behavioural signatures. This is also the same hash reused in the Nov19 phvnc slot. In this batch, Tria.ge family attribution tracked loader-stage behaviour, not the inner PureLogs family name used in this report.


Sample overview

Field Value
Internal name Mvfsxog.dll
SHA256 046d0e83c1e6dcaf526127b81b962042e495f5ae3a748f3a9452be62f905acf8
MD5 27c8f921a28bea1f8ee73aaae49b8ddf
Type .NET assembly (DLL)
Framework .NET Framework 4.x
Obfuscator ConfuserEx v1.x (standard variant)
VT detections 0/72 at recovery, 26/72 after first submission, 37/76 as of 2026-02-26 (trojan.tedy/msil)
Family PureLogs (PureCoder MaaS ecosystem)
Campaign SERPENTINE#CLOUD (Securonix)

The assembly is the inner payload of a multi-stage loader chain. An outer crypter handles decryption and decompression before loading this DLL via Assembly.Load(). Python-based droppers handle delivery and persistence upstream. This DLL is the final stage.


Architecture: plugin-based stager

This is not a monolithic RAT. The DLL has no offensive capabilities. No keylogger. No screen capture. No file manager. No remote shell. No credential harvester. No persistence mechanism.

It is a stager. It does four things:

  1. Evade analysis environments
  2. Fingerprint the host
  3. Open an encrypted C2 channel
  4. Receive and execute .NET assemblies in memory

All offensive capabilities come from the C2 server at runtime as compiled .NET plugins. They load via Assembly.Load(byte[]), execute via reflection, and never touch disk. This is why it had zero detections at recovery - there is nothing malicious in the binary itself for signature engines to match.


Execution flow

Assembly Load
  -> Module static constructors (x4)
    -> Anti-tamper init (JIT compilation hook)
    -> String decryption table init
  -> Entry point
    -> Decrypt embedded config (protobuf binary, base64-encoded)
    -> Deserialize config into 12-field structure
    -> Set SecurityProtocolType.Tls12
    -> Mutex check (disabled in this build; config field is null)
    -> Sandbox/VM detection
      -> If detected: Environment.Exit(0)
    -> C2 connection loop
      -> TCP connect to C2 server
      -> Handshake: send 0x04, expect 0x04
      -> Start heartbeat timer (20-40 unit intervals)
      -> Enter receive loop:
        -> Receive 4-byte length prefix
        -> Receive encrypted payload
        -> Decrypt (AES-256-CBC)
        -> Decompress (GZip)
        -> Deserialize (protobuf)
        -> Extract plugin assembly bytes
        -> Assembly.Load(bytes)
        -> GetTypes()[0].GetMethods()[0]
        -> InvokeMember(BindingFlags.InvokeMethod)
      -> On error: disconnect, sleep 1000-5000ms (random), retry

Anti-analysis

The DLL runs five checks before it ever connects to C2.

Sandbox detection

The sandbox check evaluates multiple signals and exits silently if any match.

DLL presence checks:

  • SbieDll.dll (Sandboxie)
  • cuckoomon.dll (Cuckoo Sandbox)
  • vmGuestLib.dll (VMware Guest Additions)

WMI queries:

  • Win32_VideoController - regex match for VMware|VIRTUAL|A M I|Xen
  • Win32_DiskDrive - regex match for virtual disk vendor strings
  • Win32_ComputerSystem - BIOS fingerprinting
  • Win32_Process - parent process name check against known sandbox launchers

Screen resolution thresholds: checks against 768, 900, 1024, 1280, and 1440 pixel widths. Standard VM display sizes trigger detection.

Username blacklist:

  • john
  • anna
  • xxxxxxxx

These are default usernames in common automated analysis sandboxes.

System file check: looks for a specific file under Environment.SpecialFolder.System, likely a sandbox artifact.

ConfuserEx protections

Control flow flattening: every method in the assembly uses while(true) { switch(num) { case N: ... } } dispatch. About 120 opaque predicate fields (all initialized to zero) are referenced in branch conditions throughout the code to break static analysis tools.

String encryption: all strings are encrypted at rest and decrypted at runtime via a custom stream cipher. The cipher uses an 8x uint32 key with cyclic key usage and state propagation. 513 strings total.

Anti-tamper / JIT hook: the module initializer installs a JIT compilation hook via native API delegates (VirtualAlloc, WriteProcessMemory, VirtualProtect). Method bodies are stored encrypted in an embedded resource and decrypted at JIT time. Hash-based integrity verification prevents patching.

StackFrame caller check: the string decryption method verifies its call stack using System.Diagnostics.StackFrame. A counter field increments on each call; the check is bypassed only after the counter passes 75. This prevents direct reflection invocation of the decryption method without first understanding the bypass.


C2 protocol

Transport

Raw TCP socket over IPv4. No TLS at the transport layer. Encryption is application-layer.

Framing

4-byte little-endian length prefix followed by the encrypted payload. Max message size: 5,242,880 bytes (5 MB).

Encryption

AES-256-CBC with a hardcoded 32-byte key:

{82, 102, 104, 110, 32, 77, 24, 34,
 118, 181, 51, 17, 18, 51, 12, 109,
 10, 32, 77, 24, 34, 158, 161, 41,
 97, 28, 118, 181, 5, 25, 1, 88}

IV is computed at runtime with arithmetic obfuscation. Provider is AesCryptoServiceProvider with RijndaelManaged fallback. A custom MD5 implementation is used when FIPS policy prevents MD5CryptoServiceProvider.

Compression

GZip with a 4-byte length prefix (decompressed size prepended to the compressed stream).

Serialization

Protocol Buffers via protobuf-net. The full protobuf-net library (~480 classes) is embedded in the assembly.

Handshake

Single-byte exchange. The client sends 0x04. The server responds with 0x04. No certificate exchange, no challenge-response. Connection authentication relies on knowledge of the C2 address and the AES key.

Heartbeat

A timer-based keepalive sends an empty heartbeat protobuf message (type 18) at random intervals between 20 and 40 time units.

Reconnection

On connection failure, the client disconnects cleanly (SocketShutdown.Both), sleeps for a random 1000-5000ms, then retries. The loop runs forever.


Protobuf message protocol

All messages inherit from a single base class with 24 [ProtoInclude] subtypes. The type hierarchy is defined at compile time via attributes, not registered at runtime.

# Fields Purpose
1 12 lists of subtypes, byte[], string Aggregate data container
2 16 strings, byte[], bool, long System fingerprint (20 fields)
3 3 strings Key-value-extra triple
4 2 strings (Name, Value) Named key-value pair
5 5 strings Named entity with metadata
6 2 strings, 1 int Status/progress message
7 2 strings Simple key-value
8 3 strings, byte[] Resource data with binary payload
9 string, long, byte[], 2 bools Chunked transfer (path, offset, data, flags)
10 long, sysinfo, bool System info wrapper with ID
11 string, byte[], list, string Named binary data with path list
12 long, list, byte[], sysinfo File operation data
13 string, byte[], string Named binary payload
14 bool Boolean acknowledgment
15 3 strings Named entity
16 5 strings, list Group/collection with children
17 list, sysinfo Collection report with system info
18 (empty) Heartbeat/keepalive ping
19 5 lists, sysinfo Bulk response container
20 1 string Simple string message
21 list of strings String list (arguments/paths)
22 byte[], data, string, list Command wrapper (plugin bytes + context)
23 bool, string, int, 2 strings, bool, string, 4 bools, command Configuration
24 1 string Simple string message

Message type 22 is the command wrapper. Its first field carries the compiled .NET assembly bytes. The handler decrypts, decompresses, calls Assembly.Load(), and invokes the first method on the first exported type.


Configuration

The config is a 12-field protobuf message embedded in the assembly as a base64-encoded, encrypted blob. Decoded:

# Type Field Extracted value
1 bool Feature flag (sandbox check toggle)
2 string C2 host ydspwie.duckdns.org
3 int C2 port 9045
4 string Encryption key hyPfc/rn9B2SRQX5h45RMjojzyLIgIY9
5 string Group Default
6 bool Feature flag
7 string Mutex name (unused, null in config)
8 bool Feature flag
9 bool Feature flag
10 bool Feature flag
11 bool Feature flag
12 command Embedded initial plugin Auto-execute on first connect

Field 12 is interesting. It carries a command wrapper (type 22) inside the config itself. The operator can bake in a plugin that runs automatically on first C2 connection, before the server sends anything.


System fingerprint

On connection, the RAT sends a 20-field system profile:

# Type Likely content
1 string Hostname
2 string Username
3 string OS version
4 string Architecture
5 string Domain
6 string IP address
7 string CPU info
8 string GPU info
9 string RAM info
10 string Disk info
11 string .NET version
12 string Antivirus product
13 string Installed programs / running processes
14 string Webcam info
15 string Firewall status
16 string Geographic location / language
17 byte[] Screenshot thumbnail or icon
18 string Unique bot ID (HWID)
19 bool Admin privilege flag
20 long Timestamp or uptime

Plugin execution

The command handler shows the full plugin lifecycle:

  1. C2 server sends a command wrapper message (type 22) containing:

    • Plugin bytes: compiled .NET assembly
    • Context data (file lists, arguments, system info reference)
  2. The RAT processes the command:

// Deobfuscated command handler:
byte[] pluginBytes = Decrypt(Decompress(command.PluginBytes));
Assembly asm = Assembly.Load(pluginBytes);
Type entryType = asm.GetTypes()[0];
MethodInfo entryMethod = entryType.GetMethods()[0];
entryType.InvokeMember(
    entryMethod.Name,
    BindingFlags.InvokeMethod,
    null, null,
    new object[] { serializedContext }
);
  1. The plugin receives serialized context (config, connection state) and runs entirely in memory.

Plugins never touch disk. No file artifacts. The stager itself has no signatures because the offensive tools live on the server. Any .NET code the operator compiles can be pushed. And static analysis of the stager alone tells you nothing about what the operator actually did on the box.


Attribution

This sample is PureLogs, a component of the PureCoder malware-as-a-service ecosystem. The name "Plog" appears consistently in dropper filenames throughout the campaign: Ploggggggg, 1plog-obf.py, OBKSLazyNov20_plog.py. PureLogs is the full name; Plog is the operator's shorthand.

PureCoder is a MaaS operator selling a suite of .NET RATs. The toolkit includes PureLogs, PureHVNC, and repackaged commodity RATs (AsyncRAT, VenomRAT, DcRat, XWorm). The campaign was first publicly documented by Securonix in June 2025 under the codename SERPENTINE#CLOUD.

Infrastructure overlap

The C2 IP 45.58.143.254 (Sharktech, Amsterdam) hosts multiple PureCoder tools simultaneously:

RAT Domain Port
PureLogs (this sample) ydspwie.duckdns.org 9045
PureHVNC / PureLogs (Oct05 variant) nhvncpure.duckdns.org + variants 6757-6759, 8075-8076
Violet RAT v4.7 vijdklet.duckdns.org 7575

The nhvncpure* domain naming convention decodes to "PureHVNC" - the domains are shared SERPENTINE#CLOUD IOCs confirmed by Securonix.

Vendor reporting

Vendor Report Coverage
Securonix Analyzing SERPENTINE#CLOUD Campaign tracking, IOCs, delivery chain
Check Point Research Under the Pure Curtain PureCoder developer analysis, UTC+0300 timezone attribution
Fortinet PureHVNC Deployed via Python Multi-stage Loader Loader chain, PureHVNC component
eSentire Quartet of Trouble PureLogs delivery via TryCloudflare tunnels

Oct05 fat client (Qdjlj.dll)

The campaign deployed two distinct PureLogs builds. The analysis above covers Mvfsxog.dll -- the plugin stager. This section covers the other variant.

The Oct05 variant is a monolithic RAT with all capabilities compiled in. No plugins, no runtime downloads. Everything the operator needs is in the binary.

Field Value
Internal name Qdjlj.dll
SHA256 cdf87d68885caa3e94713ded9dd5e51c39b7bc7ef9bf7d63a4ff5ab917a96b36
Size 1,290,752 bytes
Type .NET assembly (DLL)
Framework .NET Framework 4.0
Obfuscator ConfuserEx (control flow flattening + string encryption + delegate indirection)
ProtoInclude types 86 (vs 24 for the stager)
Source files 1,747 C# files (decompiled)
Version 4.3.0
Campaign ID SEP04
Mutex 3ddc38f1ccff (15-second timeout)

The inner Qdjlj.dll sample (cdf87d68885caa3e94713ded9dd5e51c39b7bc7ef9bf7d63a4ff5ab917a96b36) first appeared on VirusTotal on 2026-02-26 during this refresh run and currently scores 17/76 with generic detections. The outer Oct05 loader (dcd22d338a0bc4cf615d126b84dfcda149a34cf18bc43b85f16142dfb019e608, Fviwknzr.exe) has been on VirusTotal since 2025-09-18 and currently scores 49/76. That same loader hash is reused in the Nov19 phvnc slot.

Oct05 C2 transport

The two variants handle encryption at different layers. Mvfsxog.dll uses raw TCP with AES-256-CBC at the application layer. The Oct05 variant uses TLS at the transport layer and has no application-layer crypto at all.

Parameter Oct05 (Qdjlj.dll) Stager (Mvfsxog.dll)
Transport TCP + TLS 1.0 (SslProtocols.Tls) Raw TCP
Encryption TLS (transport layer) AES-256-CBC (application layer)
Certificate Self-signed, CN=Zwfweayg, RSA 4096-bit None (no TLS)
Cert validation None (callback returns true) N/A
Framing Length-prefixed protobuf 4-byte little-endian length prefix
Read buffer 512 KB 5,242,880 bytes (5 MB max message)
Send buffer 64 KB --
Timeouts 5.0 seconds (read/write) --
Reconnect delay 5,000 ms 1,000-5,000 ms (random)
Heartbeat 20-60 second random interval 20-40 unit intervals
Handshake TLS handshake (standard) Single-byte: 0x04 send, 0x04 receive

The embedded TLS certificate:

Field Value
Subject CN Zwfweayg
Issuer Self-signed
Issued 2024-06-14 06:44:12 UTC
Expires 9999-12-31 23:59:59
Key RSA 4096-bit
SHA256 b1474a16875185cc69f41c8b545f591f4bc8a1c7cbdd1cb08924424d825cb6c0

The certificate is base64-encoded in the protobuf config (1,676 characters). The operator generated it a year before deployment.

Oct05 C2 infrastructure

The Oct05 variant has 10 C2 domains across 5 ports. The stager has one domain and one port.

Domain IP (Feb 2026) Status
nhvncpure.duckdns.org 45.58.143.254 Active (Sharktech Amsterdam)
nhvncpurekfl.duckdns.org 45.58.143.254 Active
nhvncpureybs.duckdns.org 45.58.143.254 Active
nhvncpureybv.duckdns.org 85.208.84.113 Dormant (DNS active, all ports closed)
nhvncpure.click NXDOMAIN Expired
nhvncpure.shop NXDOMAIN Expired
nhvncpure.sbs NXDOMAIN Expired
nhvncpure.twilightparadox.com NXDOMAIN Removed by provider
nhvncpure1.strangled.net NXDOMAIN Removed by provider
nhvncpure2.mooo.com NXDOMAIN Removed by provider

All 10 domains listen on ports 6757, 6758, 6759, 8075, and 8076. Three active DuckDNS domains resolve to 45.58.143.254 -- the same Sharktech Amsterdam IP hosting the stager (ydspwie:9045) and Violet RAT (vijdklet:7575).

One domain (nhvncpureybv) points to 85.208.84.113 (Pfcloud AS51396 / Online Connect Ltd / NELEEL, Russian allocation December 2025). As of February 2026 this IP is dormant -- DNS resolves but all C2 ports are closed. Standby infrastructure.

The DNS provider spread (DuckDNS, .click, .shop, .sbs, strangled.net, mooo.com, twilightparadox.com) mirrors the Remcos homoney infrastructure analyzed in the AutoIt persistence post -- identical fallback providers.

Oct05 configuration

The config is an 18-field protobuf message -- more complex than the stager's 12-field structure. Decoded from a base64-encoded, GZip-compressed protobuf blob in the application string table.

Field Type Value Purpose
1 repeated string 10 C2 domains Server pool
2 repeated varint 6759, 6758, 6757, 8075, 8076 C2 ports
3 string Base64 X.509 certificate (1,676 chars) TLS cert (CN=Zwfweayg)
4 string SEP04 Campaign ID
6 varint 1 SSL enabled
8 string APPDATA Install directory (%AppData%)
9 string 3ddc38f1ccff Mutex

The remaining fields cover beacon intervals, registry keys, fallback C2 endpoints, and module paths -- all runtime-decrypted from the ConfuserEx string table.

Oct05 capabilities

The binary's 1,747 source files cover the full tool suite.

Cryptocurrency stealer. The primary payload. Targets 50+ browser wallet extensions by Chromium extension ID, 30+ browser profile paths, and 10+ desktop wallet applications.

Browser wallet targets include MetaMask, Phantom, Coinbase Wallet, Trust Wallet, Exodus Web3, Keplr, Ronin, TronLink, Guarda, XDEFI, Binance Chain, Coin98, Math Wallet, Yoroi, BitKeep, and 35 more.

Targeted browsers: Chrome, Edge, Brave, Vivaldi, Opera, CocCoc, Amigo, Torch, Kometa, Orbitum, CentBrowser, 7Star, Sputnik, Chromodo, Chedot, QIP Surf, liebao, Uran, Epic Privacy, Comodo Dragon, K-Melon, Maxthon3, Nichrome, 360Browser, QQBrowser, ChromePlus, Iridium, Coowon, Citrio, Sleipnir5, Atom.

Desktop wallets: Bitcoin-Qt, Dash-Qt, Litecoin-Qt, Electrum, Ethereum (keystore), Atomic Wallet, Exodus, Jaxx Liberty, Ledger Live, Zcash.

Telegram and Foxmail theft. Targets the Telegram Desktop directory and Telegram.exe process for session data. Also harvests Foxmail email client data.

Process injection. Dynamic API resolution pipeline to avoid static import table entries:

LoadLibrary("kernel32.dll")
  -> GetProcAddress("OpenProcess")
  -> GetProcAddress("VirtualAlloc")
  -> GetProcAddress("WriteProcessMemory")
  -> GetProcAddress("VirtualProtect")
  -> GetProcAddress("CloseHandle")

Screen capture. Graphics.CopyFromScreen at 640x480 resolution, JPEG encoding with variable quality, using SRCCOPY + CAPTUREBLT raster operations.

Persistence. PowerShell scheduled task with 5-minute repeat interval:

Register-ScheduledTask -TaskName '<name>'
  -Action (New-ScheduledTaskAction -Execute '<path>')
  -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date)
    -RepetitionInterval (New-TimeSpan -Minutes 5))
  -User $env:UserName -RunLevel Highest -Force

Executed via powershell.exe -NoProfile -ExecutionPolicy Bypass -Enc <base64>. A second variant omits -RunLevel Highest for lower-privilege persistence.

WMI fingerprinting. Six queries for host profiling:

Query Purpose
Win32_PnPEntity WHERE PNPClass = 'Image' OR PNPClass = 'Camera' Camera detection
AntiVirusProduct (namespace: root\\SecurityCenter2) AV enumeration
Win32_OperatingSystem OS version
Win32_Processor / ProcessorId CPU fingerprint
Win32_DiskDrive / SerialNumber Disk serial
Win32_PhysicalMemory / SerialNumber Memory serial

Other capabilities include window title monitoring (GetForegroundWindow + GetWindowText), anti-idle (SetThreadExecutionState prevents system sleep), DPI awareness (SetProcessDPIAware for accurate screen capture), recursive file enumeration (Parallel.ForEach with wildcard matching), process execution (hidden windows), and registry Shell Folders enumeration.

What's absent: No SetWindowsHookEx, no WH_KEYBOARD, no GetAsyncKeyState -- there is no keylogger. No sandbox evasion, no VM detection, no debugger checks, no environment enumeration. The stager has extensive sandbox detection; this variant has none.

Oct05 string decryption

The Oct05 variant uses a two-tier string encryption architecture, unlike the stager's single table.

Table Resource Strings Method Content
Library AL2OceSywAAjnWdFqK (24,952 B) 506 IL opcode emulation protobuf-net serialization framework
Application yAmFdOUdhZalvLPjJS (15,891 B) 236 .NET reflection invoke C2 config, wallet IDs, browser paths, persistence commands

The library strings are protobuf-net framework internals -- wire-type handlers, serialization callbacks, schema generation strings. No operational content. They were cracked by emulating the ConfuserEx key builder's 2,876 IL instructions to recover the 32-byte cipher key.

The application strings are where everything operational lives. They were cracked by loading the assembly and invoking its own decryption method via .NET reflection (n7V5ZJSQosy6s1ljW6f.x9dSlJCWDO). The 236 decrypted strings yielded all 10 C2 domains, all 5 ports, the TLS certificate, the campaign ID, and the mutex. They also contained 50+ crypto wallet extension IDs, 30+ browser profile paths, desktop wallet targets, Telegram/Foxmail targeting strings, PowerShell persistence commands, and WMI fingerprinting queries.

By comparison, the stager stores all 513 strings in a single table cracked by the same reflection technique. The stager's strings are mostly sandbox detection indicators and protobuf-net framework strings, with one base64-encoded config blob containing the C2 endpoint.

Variant comparison

Feature Oct05 fat client (Qdjlj.dll) Plugin stager (Mvfsxog.dll)
Architecture Monolithic -- all capabilities compiled in Stager -- capabilities delivered via C2 plugins
ProtoInclude types 86 24
Target framework .NET Framework 4.0 .NET Framework 4.5
Config fields 18 ProtoMember 12 ProtoMember
C2 transport TCP + TLS 1.0 (self-signed cert) Raw TCP + AES-256-CBC (application layer)
C2 infrastructure 10 domains / 5 ports 1 domain / 1 port
Sandbox detection None Extensive (DLL checks, WMI, screen resolution, username blacklist)
Built-in capabilities Crypto stealer, Telegram/Foxmail theft, process injection, screen capture, persistence, WMI fingerprinting None -- all via in-memory plugins
String tables Two-tier: 506 library + 236 application Single: 513 strings
Campaign ID SEP04 Default
Mutex 3ddc38f1ccff (active, 15s timeout) Disabled (config field null)
Version 4.3.0 Unknown
Deployment Wave 1 (Oct 5) through Wave 6 (Dec 17) Wave 2 (Nov 10) through Wave 5 (Nov 19)

The fat client is the older variant. First deployed in October 2025 (campaign ID SEP04, PE timestamp September 4, 2025), it packs everything the operator needs into a single binary. The stager is newer -- stripped down, plugin-based, harder to detect. Moving from fat client to plugin stager means offensive capabilities leave disk entirely. They arrive through the C2 channel, run in memory, and leave no static signatures.

Oct05 indicators of compromise

Network

Indicator Type Context
nhvncpure.duckdns.org Domain Oct05 C2 (active)
nhvncpurekfl.duckdns.org Domain Oct05 C2 (active)
nhvncpureybs.duckdns.org Domain Oct05 C2 (active)
nhvncpureybv.duckdns.org Domain Oct05 C2 (dormant -- 85.208.84.113)
nhvncpure.click Domain Oct05 C2 (expired)
nhvncpure.shop Domain Oct05 C2 (expired)
nhvncpure.sbs Domain Oct05 C2 (expired)
nhvncpure.twilightparadox.com Domain Oct05 C2 (removed)
nhvncpure1.strangled.net Domain Oct05 C2 (removed)
nhvncpure2.mooo.com Domain Oct05 C2 (removed)
45.58.143.254 IPv4 Primary C2 IP (Sharktech, Amsterdam)
85.208.84.113 IPv4 Dormant C2 IP (Pfcloud AS51396 / NELEEL)
6757/tcp, 6758/tcp, 6759/tcp, 8075/tcp, 8076/tcp Ports Oct05 C2 ports

Host

Indicator Type Context
cdf87d68885caa3e94713ded9dd5e51c39b7bc7ef9bf7d63a4ff5ab917a96b36 SHA256 Qdjlj.dll (Oct05 inner RAT)
dcd22d338a0bc4cf615d126b84dfcda149a34cf18bc43b85f16142dfb019e608 SHA256 Fviwknzr.exe (Oct05 loader)
3ddc38f1ccff Mutex Oct05 mutex (15s timeout)
CN=Zwfweayg, RSA 4096-bit TLS cert Embedded self-signed certificate

Behavioral

  • TLS 1.0 connection to ports 6757-6759, 8075-8076 with self-signed certificate (CN=Zwfweayg)
  • Length-prefixed protobuf framing over TLS
  • PowerShell scheduled task creation with 5-minute interval and -RunLevel Highest
  • powershell.exe -NoProfile -ExecutionPolicy Bypass -Enc execution
  • Enumeration of Chromium browser extension directories for cryptocurrency wallet extension IDs
  • WMI queries to Win32_PnPEntity, AntiVirusProduct, Win32_OperatingSystem, Win32_Processor, Win32_DiskDrive, Win32_PhysicalMemory
  • Dynamic API resolution: LoadLibrary + GetProcAddress for injection-related APIs
  • Self-copy to %AppData% with scheduled task persistence

Encryption suite

The assembly has three independent crypto implementations:

AES-256-CBC for C2 communication. Hardcoded 32-byte key. IV computed with runtime arithmetic obfuscation. Uses AesCryptoServiceProvider with RijndaelManaged fallback.

3DES-ECB for configuration and data encryption. Key derived from MD5 hash of the encryption key config field (field 4).

Custom XOR stream cipher for ConfuserEx string encryption. 8x uint32 key with cyclic key usage and block-level state propagation. Covers all 513 embedded strings.


Indicators of compromise

Network

Indicator Type Context
ydspwie.duckdns.org Domain C2 server
45.58.143.254 IPv4 C2 IP (Sharktech, Amsterdam)
9045/tcp Port C2 port
hyPfc/rn9B2SRQX5h45RMjojzyLIgIY9 String C2 encryption key

Host

Indicator Type Context
046d0e83c1e6dcaf526127b81b962042e495f5ae3a748f3a9452be62f905acf8 SHA256 Plog RAT DLL (Mvfsxog.dll)
27c8f921a28bea1f8ee73aaae49b8ddf MD5 Plog RAT DLL (Mvfsxog.dll)
Mutex check (code present but disabled) Behavior Config field 7 is null; mutex logic not reached

Behavioral

  • Raw TCP connection to port 9045 with 4-byte length-prefix framing
  • Single-byte handshake: 0x04 send, 0x04 receive
  • AES-256-CBC encrypted + GZip compressed payloads over TCP
  • WMI queries to Win32_VideoController, Win32_DiskDrive, Win32_ComputerSystem, Win32_Process at startup
  • Enumeration of loaded process modules checking for SbieDll.dll, cuckoomon.dll, vmGuestLib.dll
  • In-memory .NET assembly loading via Assembly.Load(byte[])

String decryption

We recovered all 513 encrypted strings by invoking the assembly's own decryption method via .NET reflection. The ConfuserEx stream cipher was bypassed entirely, no key recovery needed. The decryption method's StackFrame caller check was defeated by setting the internal counter field past its threshold (75) via reflection before the first call.

String categories

Category Count Examples
Anti-sandbox/VM 16 SbieDll.dll, cuckoomon.dll, vmGuestLib.dll, VMware|VIRTUAL|A M I|Xen
C2 configuration 1 Base64-encoded protobuf config blob
System interaction 3 .dll, Load , whitespace separators
Error/debug 1 Unexpected WMI query failure
Internal identifiers 2 GUID fragment 1b24d7e1-0237, obfuscated class reference
Plugin loader ~10 Assembly loading prefixes and method references
protobuf-net library 476 Serialization framework strings

Conclusion

Two PureLogs variants, two architectures, one campaign.

The Oct05 fat client (Qdjlj.dll) is a monolithic crypto stealer -- 86 protobuf message types, 50+ wallet extension targets, built-in persistence, TLS transport, 10 C2 domains across 5 ports. The plugin stager (Mvfsxog.dll) is the opposite -- 24 message types, zero offensive capability, extensive sandbox evasion, a single C2 endpoint. All malicious actions come from plugins pushed in memory that never touch disk.

The shift from fat client to plugin stager is about reducing what touches disk. The fat client leaves signatures: wallet extension IDs, persistence commands, injection APIs. The stager leaves nothing. It had zero VirusTotal detections at recovery because there is nothing malicious in the binary for signature engines to match. After first submission, 26 of 72 engines flagged it with generic labels (trojan.tedy/msil). As of 2026-02-26, it is 37 of 76 and still generic. No engine identified it by family name.

This is PureLogs, sold as part of PureCoder's MaaS toolkit alongside PureHVNC and repackaged commodity RATs. The campaign infrastructure, delivery chain, and dropper naming conventions all tie back to SERPENTINE#CLOUD.

Share this article