Module Stomping (DLL Hollowing)
Loading a benign signed DLL into a target process and overwriting its code section with shellcode, so the malicious memory is backed by a legitimate module and evades unbacked-memory scanners.
Module stomping (also called DLL hollowing) sidesteps the biggest tell of most
injection techniques — private, executable, unbacked memory. Instead of
allocating fresh RWX memory, the injector loads a real, signed, otherwise-unused
DLL into the target, then overwrites that module's .text section with shellcode
via WriteProcessMemory. The malicious code now lives inside a legitimately
mapped, image-backed, signed module, so scanners that hunt for unbacked
executable regions see nothing unusual.
How it works
The attacker picks a benign DLL the target does not actually use, forces it to
load (locally or remotely, e.g. via LoadLibrary in the target), locates the
module's .text region, makes it writable, and stomps shellcode over the
original code. Execution is then directed at the stomped code (remote thread, APC,
or a hijacked thread pointed at the overwritten offset).
LoadLibrary("benign_signed.dll") // map a real signed module in target
base = GetModuleHandle("benign_signed.dll")
VirtualProtectEx(hProc, base+textRVA, len, PAGE_EXECUTE_READWRITE, &old)
WriteProcessMemory(hProc, base+textRVA, shellcode, len) // stomp .text
VirtualProtectEx(hProc, base+textRVA, len, PAGE_EXECUTE_READ, &old)
CreateRemoteThread(hProc, NULL, 0, base+textRVA, arg, 0, NULL) // run stomped codeDetection & bypass
- Static — The injector still imports
WriteProcessMemoryandVirtualProtectExalongsideLoadLibrary/GetModuleHandle. The distinguishing static cue is the absence ofVirtualAllocExfor the code region — the shellcode target is an existing module base rather than fresh allocation. Hardcoded benign-DLL names that the process has no reason to use can hint at the chosen stomp host. - Dynamic — Watch for
WriteProcessMemorywhose destination falls inside a mapped module's image range (not private memory), frequently bracketed byVirtualProtectExflipping that module's code to writable then back to executable. A remote thread or APC starting inside a signed module but at a non-export, mid-.textoffset is suspicious. - Memory forensics — The region is image-backed and signed, so unbacked-memory
scans miss it; the giveaway is an image/disk byte mismatch. Moneta and
pe-sieve compare in-memory module pages against the on-disk DLL and flag
modified code / hash mismatch in the
.textof the stomped module. Look for private+executable or modified pages within an otherwise mapped, named module. - Tools — pe-sieve (
/imp, modified-code detection), Moneta (modified image / private-in-mapped flags), Process Hacker (module memory inspection), API Monitor (WriteProcessMemory/VirtualProtectExtargets), Sysmon/ETW, and Volatility (ldrmodules+ page-hash comparison against disk).