Pixels to Payload: Dissecting a Four-Stage Bitmap-Steganography Dropper Delivering AsyncRAT
Note: The bulk of this analysis and write-up was produced with the Kimi K3 large language model.
Summary#
The sample analysed here is a four-stage .NET delivery chain that deploys AsyncRAT version 0.5.8. The outer binary poses as an Armenian-language water-cycle simulation, complete with a functioning particle engine, control panel, and live charts. Its two bitmap resources are not artwork. They are payload carriers, and the code that reads them uses Bitmap.GetPixel as a steganographic carving tool.
The chain is notable for three reasons. First, it uses two different pixel-encoding schemes across the two carrier bitmaps, each with anti-carving countermeasures. Second, its third stage is an Eazfuscator-wrapped loader built around a complete academic epidemiology simulator, which performs persistence, Microsoft Defender tampering, and process hollowing into signed .NET framework utilities. Third, the final payload is an essentially unmodified AsyncRAT client whose operator deliberately disabled its built-in installation and anti-analysis features, because the loader already provides them.
Every stage was extracted and decrypted statically, without executing the sample. The analysis also produced pixelchain, a keyless end-to-end extractor that recovers all four stages and the final RAT configuration from the dropper alone. Let us walk through the analysis.
Sample Information#
| Field | Value |
|---|---|
| Filename | 938a9136aa1f128c6462899bac6ab7a6a7cfd3a1bcc79fb38bfb207032d8515b.exe (assembly title “WaterCycle”; referred to below as WaterCycle.exe) |
| File Type | PE32 executable (.NET assembly) |
| Architecture | x86 (IL-only) |
| Framework/Platform | .NET Framework 4.5, WinForms |
| File Size | 778,240 bytes |
| SHA256 | 938a9136aa1f128c6462899bac6ab7a6a7cfd3a1bcc79fb38bfb207032d8515b |
| MD5 | 81961b2997cdf859ab8b96c3dd0afb07 |
| Entry Point | 0x000BF5DE |
| Compilation Timestamp | Not recovered (assembly claims copyright 2026) |
| Campaign/Family | AsyncRAT delivery chain |
Attack Chain Overview#
The stages unfold as follows:
- Stage 1: WaterCycle.exe: ConfuserEx-obfuscated decoy application. During form initialisation it carves stage 2 out of the RGB channels of the bitmap resource
Fecand reflectively loads it. - Stage 2: ToolBelt.dll: A second decoy (a puzzle game) hiding the second loader. It crops the
Ozcibitmap, reads four bytes per pixel, XOR-decrypts, and reflectively loads stage 3. - Stage 3: WinTune.exe: An Eazfuscator-obfuscated loader wrapped around a legitimate HIV-transmission simulator. It persists, tampers with Defender, and decrypts the embedded
4T86dNvresource into stage 4, executing it in memory or via process hollowing. - Stage 4: AsyncRAT 0.5.8: The final RAT client. TLS with a pinned self-signed certificate to a dynamic-DNS C2, with all intrusive capability delivered as post-compromise plugins.
Stage 1: The Water-Cycle Decoy and the Fec Bitmap#
The dropper opens three windows: a particle simulation titled Simulyatsia, a control panel with Armenian labels, and a pie chart. The decoy is complete enough to survive both a casual user and a screenshot-driven sandbox verdict. The malicious work happens in the main form’s initialiser, Bm.Bt.bu(), wedged between button-setup code:
| |
jZh.lZG walks the 142x142 bitmap Fec pixel by pixel, x-outer, y-inner, and appends the R, G, and B channel of each pixel to a byte stream, keeping the first 59,392 bytes. Notably, the pixel accessors are not called directly: the code builds them by compiling LINQ expression trees into Func<Bitmap,int,int,byte> delegates at runtime, a small JIT-level flourish that keeps static analysis tools honest. The delimiter string decodes to the constructor arguments 4F7A6369, 6A727A, and WaterCycle.

The carved bytes are a valid PE: stage 2, a 59,392-byte .NET DLL (SHA256 dd4ddcb93d369da8437b8f8f1386fec6a5b18251c94e0911c38540bb9a9fa280).
Stage 2: Crop, Read, XOR#
Stage 2 is ConfuserEx-obfuscated with Georgian-script identifiers and fronted by a puzzle-game form. Its constructor hex-decodes the stage-1 arguments into a resource name (Ozci) and key material (jrz), then runs the real loader:
- Retrieves the 584x632
Ozcibitmap from the host process resources. - Crops it to 407x407, discarding 177 columns and 225 rows of noise padding.
- Reads four bytes per pixel (the little-endian bytes of
Color.ToArgb(): B, G, R, A), taking a 4-byte little-endian length prefix: 659,969 bytes of ciphertext. - Decrypts with
Mist:
| |
The key folds into a constant, so the effective keystream is the repeating three-byte sequence 82 E8 82. Two anti-carving details are worth calling out: the crop defeats naive full-image extraction, and the four-channel layout defeats RGB-only carvers. An RGB extraction of the same bitmap produces garbage, which is exactly the kind of trap that wastes an analyst’s afternoon.

The plaintext is stage 3, a 659,969-byte .NET executable (SHA256 f444c732baf179d7b6fb560fc3ec4ae5758696eb5cce06c6fb5f78f82cac6408).
Stage 3: The Eazfuscator Workhorse#
Stage 3, internally named WinTune, embeds an entire legitimate application: an epidemiological simulator titled “Simulation Models for the Control of the Dynamics of HIV Infection Through Vaccination”. The malicious logic hides under three Eazfuscator layers: encrypted strings, delegate-based call indirection, and invisible Unicode identifiers.
Recovering 638 encrypted strings#
Encrypted strings live in the resource HiddenEvent.CommonEvent and are resolved by five global generic methods of the form <Module>.?????<string>(uint key). Because the decryptors are pure functions, all 638 referenced strings were recovered by invoking them through reflection in a 32-bit PowerShell process. The haul reads like a capability manifest: registry Run-key persistence, Add-MpPreference -ExclusionPath, DisableAntiSpyware, the full process-hollowing API set (ZwUnmapViewOfSection, VirtualAllocEx, WriteProcessMemory, thread-context APIs), the hollowing targets vbc.exe, MSBuild.exe, and RegSvcs.exe, a CMSTP UAC-bypass INF, and its cleanup command taskkill /IM cmstp.exe /F.
The loader’s behaviour is governed by a pipe-delimited configuration string encoding a 17,743 ms startup delay, persistence and Defender-tamper flags, and injection mode auto. Critically for the “what does it drop” question: the string table contains no URLs and no download logic. The loader fetches nothing. Everything it needs is already inside it.
Persistence and Defender tampering#
The loader copies itself to %AppData%\ZGXPuDHEmsWfAQ.exe and registers a Run key. When elevated, it adds a Defender path exclusion through hidden PowerShell and sets HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\DisableAntiSpyware = 1.

The 4T86dNv cipher#
The final payload occupies the resource 4T86dNv as a 46,081-byte encrypted blob; decryption discards the final byte, yielding 46,080 bytes of plaintext. The cipher is a chained XOR-subtract construction keyed on the string uJrxHaj:
| |
Each output byte depends on the next ciphertext byte, which defeats single-byte known-plaintext recovery and keeps entropy high even over zero-filled PE regions. A subtle implementation detail, the loop runs n+1 iterations and double-processes byte 0 against the already-decrypted byte 1, must be replicated exactly, or decryption fails silently. This detail later became the difference between a working extractor and a broken one.
Execution: reflective load or process hollowing#
With stage 4 in hand, the loader picks one of two paths. The primary path is Assembly.Load plus EntryPoint.Invoke. The alternative is classic process hollowing into a signed Microsoft .NET utility (vbc.exe, MSBuild.exe, or RegSvcs.exe): spawn suspended, unmap, allocate, write, set context, resume. The hollowed compiler process then originates the C2 traffic, which looks considerably less suspicious than a random unsigned binary making TLS connections.
Stage 4: AsyncRAT 0.5.8#
The final payload (SHA256 4518eb287a5d1f7b5001b103d7e905e24d87148eaecb7972546d53f206e0e175) is a stock AsyncRAT client. Its configuration strings are AES-256-CBC encrypted, keyed by PBKDF2 (SHA-1, 50,000 iterations, fixed 32-byte salt) over a double-base64-encoded master key, each blob authenticated with HMAC-SHA256. An RSA signature over the key hash, verified against the embedded server certificate, binds the binary to its C2 certificate.
Decrypted configuration:
| Setting | Value |
|---|---|
| Hosts | ratsales.duckdns[.]org |
| Ports | 6606, 7707, 8808 |
| Version | 0.5.8 |
| Install / Anti / BDOS | false / false / false |
| Pastebin | null |
| Group | Default |
| Mutex | V3cyXIlQHKxp |
| Startup delay | 3 s |
The client picks a random host/port pair, negotiates TLS pinned to the embedded self-signed certificate (CN=AsyncRAT Server, thumbprint 62CD77BEFFE28BE7AD8BFFE401163D99B7BB5DE2, issued 2026-07-12), and speaks MessagePack. The stub implements only three commands: pong, plugin, and savePlugin. Everything else, including remote desktop, keylogging, and credential theft, arrives as plugins cached DEFLATE-compressed under HKCU\Software\[HWID].

Building pixelchain: A Keyless Chain Extractor#
Existing tooling stops at individual layers. AsyncRAT config parsers (rat_king_parser and friends) expect you to hand them the RAT. Eazfuscator deobfuscators (de4dot, EazFixer) expect you to hand them the loader. Nothing walked the chain. So the analysis produced pixelchain, which takes only the dropper and emits all four stages plus the decrypted configuration.
The design principle is no hardcoded secrets:
- The stage-2 XOR keystream is solved from DOS-header known-plaintext (
MZplus theThis programstub text), not recovered from the key string. - The stage-3 cipher key is recovered algebraically from the same known-plaintext, accounting for the double-processed first byte.
- Bitmap geometry is brute-forced, and the discriminator between the ~120 candidates that share a valid-looking header is the
BSJBCLR metadata signature deep in the file. - dnfile handles .NET metadata; self-contained minimal PNG/BMP decoders handle the carrier images (dnfile will not deserialise BinaryFormatter-embedded bitmaps).
Verified against the reference sample, it reproduces every stage hash byte-for-byte:
| |
Network indicator defanged for publication; pixelchain prints the live value.
pixelchain ships with this post: pixelchain. Its only dependencies are dnfile, pefile, and pycryptodome.
MITRE ATT&CK Mapping#
| Tactic | Technique | ID | Observation |
|---|---|---|---|
| Defense Evasion | Steganography | T1027.003 | Payloads encoded in bitmap pixel channels (Fec, Ozci) |
| Defense Evasion | Obfuscated Files or Information | T1027 | ConfuserEx, Eazfuscator, AES-encrypted configuration |
| Execution | Reflective Code Loading | T1620 | Assembly.Load at every stage transition |
| Defense Evasion | Process Hollowing | T1055.012 | vbc.exe / MSBuild.exe / RegSvcs.exe via ZwUnmapViewOfSection |
| Persistence | Registry Run Keys | T1547.001 | Run-key entry for %AppData%\ZGXPuDHEmsWfAQ.exe |
| Defense Evasion | Disable or Modify Tools | T1562.001 | Add-MpPreference exclusion; DisableAntiSpyware |
| Privilege Escalation | Abuse Elevation Control Mechanism | T1548.002 | INF artefact used to bypass UAC (CMMGR32.EXE App Paths abuse) |
| Defense Evasion | System Binary Proxy Execution: CMSTP | T1218.003 | Malicious INF executed through c:\windows\system32\cmstp.exe, cleaned up with taskkill |
| Defense Evasion | Masquerading | T1036 | Decoy GUIs; compiler processes as injection hosts |
| Command and Control | Asymmetric Cryptography | T1573.002 | TLS with pinned self-signed certificate |
| Command and Control | Non-Standard Port | T1571 | TCP 6606, 7707, 8808 |
| Command and Control | Dynamic DNS | T1568.001 | duckdns[.]org C2 hostname |
| Defense Evasion | Time-Based Sandbox Evasion | T1497.003 | 17.7 s and 3 s startup delays |
Threat Intelligence and Attribution#
AsyncRAT is an open-source RAT available on GitHub since 2019, operated by commodity actors through crypter services. Three external checks anchor this attribution. The stage-1 hash is indexed on ThreatFox and MalwareBazaar, tagged AsyncRAT, first seen 2026-07-17. NICTER’s published AsyncRAT analysis documents the identical hardcoded Aes256.Salt byte array recovered from stage 4. Malpedia’s family entry matches the observed capability set.
Decoy provenance#
The stage-3 decoy is a complete academic epidemiology simulator. Automated analysis platforms (unpac.me, FileScan.IO) host sibling samples built from the same crypter chain with the identical decoy, which indicates mass-produced packing output rather than a bespoke build. The certificate was minted 2026-07-12, five days before the sample surfaced.
Attribution confidence#
High confidence on family (AsyncRAT 0.5.8, NYAN-x-CAT lineage). No actor attribution: the infrastructure (dynamic DNS, per-build certificate, unreported mutex V3cyXIlQHKxp) is consistent with a commodity operator, and a MalwareBazaar community tag “Grim” attached to the sample is uncorroborated in public reporting. The Armenian-language stage-1 decoy is suggestive of regional targeting, but this remains speculation without further evidence.
Detection Engineering and Recommendations#
- Block and sinkhole ratsales.duckdns[.]org; alert on TLS to TCP 6606/7707/8808 and hunt for the pinned certificate thumbprint
62CD77BEFFE28BE7AD8BFFE401163D99B7BB5DE2. The operator’s secrecy mechanism is also their loudest signal. - Alert on managed processes that enumerate an entire bitmap resource via
Bitmap.GetPixeland immediately callAssembly.Load, which is the stage-transition signature. - Alert on vbc.exe, MSBuild.exe, or RegSvcs.exe with no build context, suspended-child spawn patterns, or outbound TLS.
- Audit
Add-MpPreference -ExclusionPathin PowerShell script-block logs (event 4104) and writes to the DisableAntiSpyware policy value. - Sweep for the mutex
V3cyXIlQHKxp,%AppData%\ZGXPuDHEmsWfAQ.exe, and the four stage hashes; deploy the YARA rule in Appendix A.
Conclusion#
Nothing in this chain is individually novel. The value is in the layering: two polished decoys, two distinct pixel encodings, an Eazfuscator loader that absorbs persistence and evasion duties, and a stock RAT kept deliberately thin. The operator disabled the client’s own install and anti-analysis features because the crypter already does that work, which is the signature of a packing service rather than a hands-on actor. Defenders should aim at the transitions (the pixel carving, the string decryptors, the hollowed compiler processes, and that very huntable pinned certificate) rather than the well-signatured final payload.
Indicators of Compromise#
File Hashes (SHA256)#
| |
Host-Based Indicators#
| |
Network Indicators#
| |
References#
- ThreatFox IOC database (abuse.ch)
- MalwareBazaar (abuse.ch)
- NICTER: AsyncRAT analysis (Japanese)
- Malpedia: AsyncRAT
- rat_king_parser: multi-family RAT config parser
- de4dot: .NET deobfuscator
- EazFixer: Eazfuscator deobfuscation tool
- AsyncRAT source (NYAN-x-CAT)
Appendix A: Detection Rules#
YARA Rule#
| |
This post was brought to you by Kimi K3 — the bulk of this analysis and write-up was produced with the Kimi K3 large language model.