Module Stomping (or Module Overloading or DLL Hollowing) is a shellcode injection (although can be used for injecting full DLLs) technique that at a high level works as follows:
Injects some benign Windows DLL into a remote (target) process
Overwrites DLL's, loaded in step 1, AddressOfEntryPoint point with shellcode
Starts a new thread in the target process at the benign DLL's entry point, where the shellcode has been written to, during step 2
In this lab, I will inject amsi.dll into a notepad.exe process, but this of course could be done with any other DLL and process.
Pros
Does not allocate RWX memory pages or change their permissions in the target process at any point
Shellcode is injected into a legitimate Windows DLL, so detections looking for DLLs loaded from weird places like c:\temp\ would not work
Remote thread that executes the shellcode is associated with a legitimate Windows module
Cons
ReadProcessMemory/WriteProcessMemory API calls are usually used by debuggers rather than "normal" programs.
ReadProcessMemory is used to read remote process injected module's image headers, meaning we could ditch the ReadProcessMemory call and read those headers from the DLL on the disk.
We could also use NtMapViewOfSection to inject shellcode into the remote process, reducing the need for WriteProcessMemory.
Below shows the technique in action - amsi.dll gets loaded into notepad and a reverse shell is spawned by the shellcode injected into amsi.dll AddressOfEntryPoint:
Observation
Note how powershell window shows that amsi.dll is loaded at 00007FFF20E60000 and it's DLL AddressOfEntryPoint point is at 00007FFF20E67E00.
If we look at the stack trace of the cmd.exe process creation event in procmon, we see that frame 9 originates from inside amsi!AmsiUacScan+0x5675 (00007fff20e67f95) before the code transitions to kernelbase.dll where CreateProcessA is called:
If we inspect notepad.exe threads, we can see thread 7372 with a start address of Amsi!AmsiUacScan+0x54e0.
If we inspect that memory location with a debugger, we see it resolves to Amsi!DLLMainCRTStartup and it contains our shellcode as expected: