Payload in PE Resources
Hiding an encrypted second-stage payload inside the PE .rsrc section, loaded at runtime via FindResource/LoadResource and decrypted before execution.
Storing the real payload in the PE resource (.rsrc) section is one of the
simplest packing patterns. The dropper looks like an ordinary application — icons,
version info, dialogs — but one resource entry is actually an encrypted
second-stage blob. At runtime the loader calls FindResource and LoadResource
to obtain a pointer to that blob, decrypts it, and either runs it in memory or
drops it to disk. Because resources are a legitimate part of every PE, a quick
triage that only inspects code sections can miss the payload entirely.
The blob is usually placed under a custom resource type or a high numeric ID and encrypted with a trivial scheme (XOR or RC4) to keep the file's overall entropy unremarkable. Commodity families such as Remcos, NanoCore, and FormBook have all shipped builder-generated loaders that conceal the next stage this way.
How it works
The loader resolves the resource by type/name, maps it, and decrypts the bytes into a buffer before transferring control:
HRSRC h = FindResourceA(NULL, MAKEINTRESOURCE(101), "BIN");
HGLOBAL g = LoadResource(NULL, h);
DWORD n = SizeofResource(NULL, h);
BYTE *res = (BYTE *)LockResource(g); /* pointer into .rsrc */
BYTE *buf = (BYTE *)VirtualAlloc(NULL, n, MEM_COMMIT, PAGE_READWRITE);
for (DWORD i = 0; i < n; i++)
buf[i] = res[i] ^ key[i % keylen]; /* XOR / RC4 decrypt */
/* buf now holds the real stage: run in memory or write to disk */
VirtualProtect(buf, n, PAGE_EXECUTE_READ, &old);
((void(*)(void))buf)();The decrypted buffer is frequently a complete PE that the loader then maps and
runs (often via process hollowing), so the resource blob is effectively the
packed payload and the .rsrc entry is its container on disk.
Detection & analysis
Static analysis: Walk the resource directory and look for an entry that is
not a normal icon, manifest, or version block — an oversized custom-type or
high-ID resource with entropy noticeably higher than the rest of the file is the
tell. The import table will show FindResource/LoadResource/LockResource
alongside VirtualAlloc and a decrypt loop. Tools like Resource Hacker or
PE-bear let you extract the blob; XOR/RC4 brute or known-key decryption then
reveals an MZ header if it is a PE.
Dynamic analysis: Breakpoint on LoadResource/LockResource to get the blob
pointer, then on the decrypt loop's exit (or on VirtualProtect flipping the
buffer to executable) and dump the decrypted region — that is the unpacked stage.
If it is a PE, dump with pe-sieve/Scylla, rebuild the IAT, and continue
analysis on the recovered stage; watch for a subsequent hollowing sequence
(CreateProcess suspended + WriteProcessMemory).
Detection rule hint: Flag images that read a custom/large resource via
FindResource+LoadResource, decrypt it, and then allocate or inject executable
memory — a resource access immediately feeding a decrypt loop and a control
transfer (or WriteProcessMemory) distinguishes a payload-in-resources loader
from a program merely reading its own assets.