typeanalysisfamilyunclassified-dotnet-bitmap-stego-loaderconfidencelowcreated2026-07-26updated2026-07-26dotnetloaderbitmap-steganographyobfuscationmasqueradereflective-loading
SHA-256: 9ac1c1dba1be97cd28dd88c4c8b33a7cb08d7601157278e49433eb9b1c283cf0

unclassified-dotnet-bitmap-stego-loader: 9ac1c1db — 283 embedded BMPs, clinical-trial masquerade

Executive Summary

PE32 .NET Framework GUI executable carrying 283 embedded 76×76×24 BMP bitmaps in its .text section — an order of magnitude more carriers than any prior sibling in the unclassified-dotnet-bitmap-stego-loader cluster. The outer binary masquerades as a Spanish-language purchase-order document (Especificaciones del presupuesto _ PO-20260525048166 E2S A105N.pdf(783KB).lha.exe) but its internal strings describe a full clinical-trial / lab-equipment management WinForms application (protocol tracking, consent forms, IRB documentation, equipment calibration, service history, usage logs). No malicious payload is recoverable statically; threat logic lives inside the encrypted bitmap carrier stream. Static-only analysis.

What It Is

  • File: Especificaciones del presupuesto _ PO-20260525048166 E2S A105N.pdf(783KB).lha.exe ^[file.txt]
  • Format: PE32 executable (GUI), Intel 80386, Mono/.NET assembly, 3 sections (.text, .rsrc, .reloc) ^[file.txt] ^[pefile.txt:1-40]
  • Size: 5,972,992 bytes (5.97 MB) ^[triage.json]
  • Compiled: Mon May 20 12:54:06 2019 UTC ^[pefile.txt:34]
  • Linker: 80.0 (Visual Studio 2017/2019 toolset) ^[pefile.txt:45-46]
  • Assembly Version: 1.0.0.0 ^[exiftool.json:45]
  • Namespace: 5axYeC3eL4 (random alphanumeric, cluster-typical name mangling) ^[strings.txt:7275] ^[strings.txt:11415-11419]
  • Resources: 5axYeC3eL4.g.resources, 5axYeC3eL4.6XorbmM51Fdbn.resources, 6c8dee92fcc294.Resources.resources ^[strings.txt:11416-11419]
  • No packing. PE sections have normal entropy; .text entropy 6.41. ^[pefile.txt:92]
  • No Authenticode signature. signed: false in rabin2. ^[rabin2-info.txt:27]
  • VS_VERSIONINFO garbled: CompanyName ;IC;B?8J;<@7F?:G=57E6, FileDescription C@2I<??>8:29E299ID, InternalName Cbz cc.exe — obfuscated/nonsense masquerade typical of the cluster. ^[exiftool.json:36-43]

How It Works

This sample is the ninth confirmed sibling of the unclassified-dotnet-bitmap-stego-loader cluster. It shares the family's core pattern: encrypted payload distributed across multiple System.Drawing.Bitmap objects, extracted at runtime, decrypted, and reflectively loaded via Assembly.Load. ^[capa.txt:15] ^[capa.txt:66-69]

What is new in this sibling

Feature Prior siblings (max) This sample (9ac1c1db)
Bitmap count 24 (f74d8a51) 283
Bitmap dimensions 76×76×24 or 88×88×24 or 136×136×24 76×76×24 (uniform)
Bitmap placement .rsrc or .text .text section
GUI masquerade Banking, OBD2/service, event-registration, maritime Clinical-trial / lab-equipment management
Compression layer Some siblings use DeflateStream None observed (AES-only chain)
SoapHttpClientProtocol Present in most siblings Present ^[strings.txt:12223]

The 283 BMP carriers are packed contiguously starting at offset 0xB375C inside .text. Each is a valid Windows 3.x BMP (magic BM, 17,382 bytes, 76×76 pixels, 24 bpp). ^[binwalk.txt] Python verification of sampled offsets confirms uniform dimensions and valid headers. ^[pefile.txt:79-96]

The outer application's WinForms shell is unusually elaborate — not a minimal stub but a full multi-tab GUI with controls for:

  • Protocol overview (title, PI, protocol ID, version, study dates, status, type, funding source)
  • Consent forms (templates, editor, PDF generation)
  • Data collection (visit scheduling, data elements, collection methods)
  • IRB documentation (submission dates, review status, attachments)
  • Equipment management (calibration records, service history, usage logs, compliance reports)
  • Participant tracking (enrollment, consent status)

All control names are conventionally named (LabelProtocolTitle, TextBoxPrincipalInvestigator, DataGridViewEquipment, DateTimePickerCalibrationDate, etc.) — this is a repurposed or cloned legitimate application shell, not auto-generated placeholder controls. ^[strings.txt:12266-12475]

BackgroundWorker async staging is present (BackgroundWorkerValidation, RunWorkerCompleted, DoWork event handlers), consistent with the cluster's use of BackgroundWorker-driven payload extraction. ^[strings.txt:11266] ^[strings.txt:11437-11442]

Decompiled Behavior

This is a .NET CIL binary with 3,074 methods. radare2's CIL backend (lang: cil) produces function lists but no meaningful decompiled pseudo-C; the IL metadata is too dense for r2's current CIL plugin. dnSpy or ILSpy would be required for meaningful decompilation. No Ghidra MCP analysis was performed — the pyghidra MCP was not invoked because the binary's threat logic is known to be ciphertext inside bitmaps, and static .NET decompilation is better served by dnSpy.

Static indicators of the extraction chain:

  • System.Resources.ResourceReader / RuntimeResourceSet strings confirm manifest resource access. ^[strings.txt:5] ^[strings.txt:701-705]
  • System.Drawing.Bitmap appears 284 times in strings (one per carrier plus framework references). ^[strings.txt:706-1240]
  • Assembly.Load, GetMethod, Invoke, Activator, Delegate.CreateDelegate, and System.Reflection.Emit strings confirm reflective execution scaffolding. ^[strings.txt:9687-11634]
  • SoapHttpClientProtocol suggests the inner payload may use SOAP-over-HTTP for C2, as observed in earlier siblings. ^[strings.txt:12223]

No decryption key, no plaintext inner assembly metadata, and no C2 endpoint strings are recoverable from the outer binary.

C2 Infrastructure

None recovered statically. The outer binary contains no hardcoded IPs, domains, URLs, mutex names, or named pipes. Network indicators, if any, are encrypted inside the 283 bitmap carriers and only resolvable at runtime. The presence of SoapHttpClientProtocol suggests SOAP HTTP C2 is plausible, matching earlier siblings in this cluster. ^[strings.txt:12223]

Interesting Tidbits

  1. 283 bitmaps — a record. Prior siblings peaked at 24 bitmaps. At 17,382 bytes each, the carrier stream occupies ~4.9 MB (82% of the 5.97 MB file). This is payload-staging at industrial scale; either the inner payload is unusually large, or the builder fragments it into tiny slices to evade static signature detection. ^[binwalk.txt]

  2. Clinical-trial masquerade — novel theme. Unlike the banking / purchase-order / OBD2 / maritime lures of prior siblings, this sample cloaks itself as a lab-equipment and clinical-protocol management system. The Spanish filename (Especificaciones del presupuesto ...) is decoupled from the internal GUI theme, suggesting the builder randomizes lure filenames independently of the shell application. ^[triage.json] ^[strings.txt:12266-12475]

  3. SettingsSingleFileGenerator 17.12.0.0 anomaly. A Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator string with version 17.12.0.0 appears in the binary. ^[strings.txt:12228] VS 17.12 corresponds to Visual Studio 2022 17.12 (released Nov 2024), yet the PE timestamp is May 2019. This is inconsistent — either the resources were rebuilt with a modern VS toolchain after initial compilation, or the string is inherited from a template/project file used during build. The .g.resources and .My.Resources streams are auto-generated by VS designers.

  4. No compression layer. Unlike siblings f230118d and f31920ba which added DeflateStream or mixed PNG carriers, this sample uses the simplest observed chain: BMP → pixel extraction → AES decryption → reflective load. No System.IO.Compression strings. ^[strings.txt]

  5. Debugger attribute noise. DebuggerNonUserCodeAttribute, DebuggerBrowsableAttribute, DebuggerStepThroughAttribute, DebuggerHiddenAttribute, and DebuggerDisplayAttribute appear in strings. ^[strings.txt:9937-9954] These are standard VB.NET compiler outputs and trigger capa's check for debugger via API MBC hit — a false positive for Release builds with My Project templates. No genuine anti-debug logic is visible.

  6. Microsoft.VisualBasic runtime presence. NewLateBinding, Microsoft.VisualBasic.ApplicationServices, Microsoft.VisualBasic.Devices, and Microsoft.VisualBasic.CompilerServices confirm VB.NET compilation or heavy VB runtime interop. ^[strings.txt:9542] ^[strings.txt:10179] ^[strings.txt:11409-11412]

How To Mess With It (Homelab Replication)

This binary is not a good replication target for offensive technique study — the threat logic is ciphertext in bitmaps and requires the decryption key. However, the carrier technique itself is reproducible:

Toolchain: Visual Studio 2022, C# or VB.NET, .NET Framework 4.0+ Steps:

  1. Create a .NET WinForms application with a legitimate-looking GUI shell (the more elaborate, the better for masquerade).
  2. Encrypt your payload assembly with AES-CBC.
  3. Split the ciphertext into N chunks.
  4. For each chunk, create a 76×76×24 BMP, write the chunk into the pixel data region after the 54-byte BMP header.
  5. Embed each BMP as an embedded resource (Build Action = Embedded Resource).
  6. At runtime: ResourceManager.GetObject(name) → Bitmap → LockBits → read pixel bytes → concatenate all chunks → AES decrypt → Assembly.Load(bytes) → MethodInfo.Invoke.

Verification: Run capa on your reproducer; expect hits on access .NET resource, find data using regex in .NET, generate method via reflection in .NET, and invoke .NET assembly method.

What you'll learn: How to build a .NET reflective loader that evades static string extraction by hiding its payload in image pixel data. Pair with SoapHttpClientProtocol for C2 to match this cluster's observable behavior.

Deployable Signatures

YARA rule

rule UnclassifiedDotnetBitmapStegoLoader_9ac1c1db
{
    meta:
        description = "Unclassified .NET bitmap-stego loader cluster — 76x76x24 BMP carriers, reflective load"
        author = "PacketPursuit"
        reference = "/intel/analyses/9ac1c1dba1be97cd28dd88c4c8b33a7cb08d7601157278e49433eb9b1c283cf0.html"
        date = "2026-07-26"
        hash = "9ac1c1dba1be97cd28dd88c4c8b33a7cb08d7601157278e49433eb9b1c283cf0"

    strings:
        $res1 = "System.Resources.ResourceReader" ascii wide
        $res2 = "System.Resources.RuntimeResourceSet" ascii wide
        $bmp  = "System.Drawing.Bitmap" ascii wide
        $load = "Assembly.Load" ascii wide
        $getm = "GetMethod" ascii wide
        $invk = "Invoke" ascii wide
        $soap = "SoapHttpClientProtocol" ascii wide
        $bmp_hdr = { 42 4D E6 43 00 00 00 00 00 00 36 00 00 00 28 00 00 00 4C 00 00 00 4C 00 00 00 01 00 18 00 }

    condition:
        uint16(0) == 0x5A4D
        and pe.number_of_sections >= 3
        and all of ($res*, $bmp, $load, $getm, $invk)
        and #bmp_hdr >= 5
        and filesize > 2MB
}

Behavioral hunt query (Sigma-like)

title: .NET Bitmap-Stego Loader Reflective Execution
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    - ImageLoaded|contains:
        - 'System.Drawing.dll'
        - 'System.Drawing.ni.dll'
    - CommandLine|contains:
        - 'SoapHttpClientProtocol'
  condition: selection
  # NOTE: Post-load behavior requires ETW/.NET runtime tracing:
  # Monitor for Assembly.Load(byte[]) followed by MethodInfo.Invoke
  # within processes that load >5 distinct Bitmap resources from embedded
  # manifest streams and exhibit no legitimate image-editing behavior.

IOC list

Indicator Value Notes
SHA-256 9ac1c1dba1be97cd28dd88c4c8b33a7cb08d7601157278e49433eb9b1c283cf0 Outer PE
SHA-1 6d7c3c4be6fc4d4c47341edb9e097d9745a829e6 Outer PE (capa) ^[capa.txt:4]
MD5 6828d778a57df3285cde194e271c5e5a Outer PE (capa) ^[capa.txt:3]
Filename Especificaciones del presupuesto _ PO-20260525048166 E2S A105N.pdf(783KB).lha.exe Spanish PO lure ^[triage.json]
Internal name Cbz cc.exe VS_VERSIONINFO ^[exiftool.json:40]
Version 17.28.43.78 / 1.0.0.0 VS_VERSIONINFO / Assembly ^[exiftool.json:39,45]
Bitmap carrier count 283 All 76×76×24 BMP in .text ^[binwalk.txt]
Namespace 5axYeC3eL4 Random alphanumeric ^[strings.txt:7275]
C2 Unknown No hardcoded endpoints; inferred SOAP HTTP

Behavioral fingerprint statement

This binary is a .NET Framework PE32 GUI executable with a minimal IAT (mscoree.dll!_CorExeMain only) and a large .text section containing 283 valid Windows BMP structures at 76×76×24. On execution, the CLR loads System.Drawing and System.Resources, iterates through embedded bitmap resources, extracts pixel data, concatenates and AES-decrypts the result into a byte array, and reflectively loads an inner assembly via Assembly.Load → GetMethod → Invoke. Post-load network behavior, if any, is expected over SOAP HTTP (SoapHttpClientProtocol). No anti-VM or anti-debug logic is present in the outer binary; capa debugger-detection hits are false positives from standard VB.NET compiler attributes.

Detection Signatures

Tactic Technique Evidence
DEFENSE EVASION T1620 Reflective Code Loading Assembly.Load, GetMethod, Invoke, Activator, Delegate.CreateDelegate strings; capa confirms. ^[capa.txt:15] ^[strings.txt:9687-11634]
DISCOVERY T1087 Account Discovery capa match. ^[capa.txt:16]
DISCOVERY T1083 File and Directory Discovery capa match (file existence, extension checks, enumerate files). ^[capa.txt:17]
DISCOVERY T1082 System Information Discovery capa match (hostname, session user). ^[capa.txt:18]
DISCOVERY T1033 System Owner/User Discovery capa match (7 get session user name hits). ^[capa.txt:19]
DEFENSE EVASION T1497.001 Virtualization/Sandbox Evasion capa anti-debug MBC hits (CheckRemoteDebuggerPresent, WudfIsAnyDebuggerPresent) — likely false positives from VB.NET compiler attributes. No genuine anti-VM strings found. ^[capa.txt:24-27]

References

  • SHA-256: 9ac1c1dba1be97cd28dd88c4c8b33a7cb08d7601157278e49433eb9b1c283cf0
  • MalwareBazaar: https://bazaar.abuse.ch/sample/9ac1c1dba1be97cd28dd88c4c8b33a7cb08d7601157278e49433eb9b1c283cf0/
  • Wiki cluster page: unclassified-dotnet-bitmap-stego-loader
  • Wiki concept page: bitmap-steganography-payload-delivery
  • Sibling analyses in this cluster: 4bf14434, db0d6bc0, f74d8a51, f6b5bdd5, f230118d, d4d106f8, a497a066, f31920ba

Provenance

Analysis based on static artifacts: file.txt (file(1)), exiftool.json (ExifTool 12.76), pefile.txt (pefile), strings.txt (strings), floss.txt (flare-floss — errored on CLI flags, no decoded output), capa.txt (Mandiant capa v7), binwalk.txt (binwalk), rabin2-info.txt (radare2), triage.json (internal pipeline), dynamic-analysis.md (CAPE — skipped, no Windows guest). All claims cite file and line number where applicable. No runtime behavior was observed.