Skip to content
Packing & Cryptersintermediate

Runtime Crypter Stub

A crypter wraps an encrypted payload and a small stub that, at runtime, decrypts the original code in memory and transfers execution to it, so static AV sees only the stub and a high-entropy blob.

A crypter is a packer whose goal is signature evasion rather than compression. It glues together two parts: an encrypted copy of the real payload (RC4, AES, or a rolling XOR) and a tiny loader stub. When the file runs, the stub decrypts the payload entirely in memory and either executes it in place or injects it into a freshly created process. On disk an antivirus engine sees only benign-looking stub code followed by an opaque high-entropy block, so byte signatures of the original malware never match.

How it works

The stub embeds (or derives) the key, walks the ciphertext, decrypts it into a newly allocated RWX region, and transfers control. A typical RC4 flavour:

c
// stub: decrypt the embedded payload in memory, then run it
BYTE  *blob = payload_rva;          // encrypted payload appended to the stub
SIZE_T len  = payload_size;
BYTE   key[16] = { 0x9A, 0x3C, /* ... */ };  // hard-coded or runtime-derived

void *mem = VirtualAlloc(NULL, len, 0x3000 /*COMMIT|RESERVE*/, 0x40 /*RWX*/);
memcpy(mem, blob, len);
rc4(mem, len, key, sizeof key);     // in-place decrypt of the real payload

// run in place (call OEP) ... or hollow a fresh process and write it there
((void(*)())mem)();

The decrypted bytes are a full PE (mapped manually) or position-independent shellcode. Many crypters wrap this in process hollowing: spawn a suspended legitimate process, NtUnmapViewOfSection, write the decrypted image, fix the entry point, and resume.

Detection & bypass

  • Static — A small, ordinary import table next to a large section whose entropy sits near 7.9 bits/byte is the tell. Detect It Easy and a manual entropy histogram flag the encrypted blob. A short loop with xor/rol over a counter, or an embedded 256-byte permutation being shuffled (the RC4 KSA), pinpoints the cipher. The hard-coded key is frequently a contiguous constant near the loop.
  • Dynamic — Set a breakpoint on VirtualAlloc/VirtualProtect and on the transition to the new region. Let the decrypt loop finish, then read the freshly written buffer: the plaintext payload (MZ header, readable strings) appears right before the call/jmp into it. Hardware-breakpoint the first byte of the allocation to catch the exact hand-off.
  • Rebuild — If you recovered the key and algorithm, decrypt the blob offline (CyberChef RC4/XOR recipe) to get a clean payload without running it. Otherwise dump the in-memory plaintext with pe-sieve or Scylla once the stub has decrypted it, then rebuild the IAT and fix the PE header to get a runnable sample.
  • Tools — x64dbg (breakpoints on the alloc/transition), pe-sieve and Scylla (memory dump of the decrypted payload), CyberChef (offline cipher recovery), and YARA run against the decrypted image rather than the packed file.
Votes

Comments(0)