typetechniqueconfidencehighcreated2026-07-21updated2026-07-21packerobfuscationevasionpemsvcdata-sectionpayload-loader

MSVC Stub Data-Section Payload Loader

Malware build pattern: a small MSVC C++ outer PE carries an encrypted threat payload inside its .data section. At runtime the stub hides the console, delays execution via a PRNG-derived Sleep, allocates RWX memory, copies the ciphertext from .data, decrypts it with a rolling key stream, and transfers control to the decrypted code. The outer binary imports only benign CRT and memory APIs, leaving no socket or registry strings in static analysis.

Detection / Fingerprint

  • .data section is disproportionately large relative to .text (often >90% of file size) and has entropy >7.0^[pefile.txt:131]
  • .text section is small (~57 KB) and contains only CRT init + loader logic^[pefile.txt:83]
  • Minimal IAT: KERNEL32.dll (heap, sleep, virtual-protect, console) only^[pefile.txt:import-table]
  • No WinInet, WinHTTP, WS2_32, or crypt32 imports in the outer binary
  • Absence of .rsrc section or icon resources is common but not mandatory

Implementation Patterns Observed

Stage 1 — Console detachment

The loader calls FreeConsole() immediately on process start to hide the console window.^[r2:main]

Stage 2 — PRNG timing gate

A linear congruential generator (seed = seed * 0x343fd + 0x269ec3) derives two pseudo-random Sleep() durations (observed range 1500–5500 ms) before payload allocation.^[r2:fcn.140004470]^[r2:fcn.1400044b4] The gate is also checked against a build-time hardcoded timestamp (GetSystemTimeAsFileTime delta). This defeats emulators that fast-forward sleep calls without updating the system clock.

Stage 3 — RWX allocation

VirtualAlloc(NULL, payload_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) allocates executable memory for the decrypted payload.^[r2:main]

Stage 4 — Section copy + decryption

The encrypted payload is copied from .data (image base + section VA) into the allocated buffer. A rolling 16-byte key stream decrypts the buffer byte-by-byte using XOR against a position-dependent key table.^[r2:main:0x14000113c]

// Observed in d4b6905ef14c — main @ 0x14000113c
for (i = 2; i < payload_size + 2; i += 4) {
    buf[i-2] ^= key_table[ (i-2) & 0xf ];
    buf[i-1] ^= key_table[ (i-1) & 0xf ];
    buf[i]   ^= key_table[ i & 0xf ];
    buf[i+1] ^= key_table[ (i+1) & 0xf ];
}

Stage 5 — Transfer of control

After decryption, the loader makes an indirect call into the payload entry point (rbx() in the decompile). The inner payload then resolves its own imports and performs the actual malicious work.

Defensive Countermeasures

  • Entropy-based hunting: Flag PE files where .data exceeds 500 KB with entropy >7.0 while .text remains <100 KB.
  • API hooking: Monitor FreeConsoleSleepVirtualAlloc with PAGE_EXECUTE_READWRITE in processes with minimal IAT.
  • Emulation tuning: Ensure sandbox Sleep fast-forward does not also freeze GetSystemTimeAsFileTime; the PRNG gate checks clock delta.
  • Memory scanning: Scan freshly allocated RWX regions for PE headers or known infostealer signatures shortly after VirtualAlloc.

Related Techniques

  • rdata-encrypted-payload-loader — similar pattern but uses MinGW-w64 with .rdata and a clock()/Sleep gate instead of MSVC with .data and FreeConsole.
  • xor-pe-payload-staging — disk-staging variant where the encrypted PE is written to %TEMP% before in-memory decryption.

Pages Where Observed

  • /intel/analyses/d4b6905ef14c2c13a69b31585be4a6a8e49f0918f1ef1406936b7f6f7ecc37b3.html — MSVC 14.41 x64 stealer loader, 1.1 MB .data payload, PRNG Sleep gate, rolling 16-byte XOR decryption.