Skip to content

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:

c
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.

Votes

Comments(0)