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:
// 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/rolover 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/VirtualProtectand 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 thecall/jmpinto 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.