Process Hollowing demonstration & explanation
PsForge is a simple example of process hollowing, an attack used by various malware and other malicious software that attempts to hide itself and its activities on the system to make it less suspicious.
Process hollowing, sometimes called RunPE, is a technique used by (usually) malicious software that allows a specific program to execute as if it was another program. As the screenshot above shows, cmd.exe
is actually running from manage-bde.exe
, which appears as a valid process, signed and verified by Microsoft.
Process hollowing works by mapping another executable into the address space of another process, and then executing the newly mapped image after removing the original image from the remote address space. This allows you to retain the various information and attributes from the remote process, while you're actually executing something completely different.
This is different from code injection into processes. Code injection is basically allocating memory and injecting shellcode into another process which is already running its appropriate executable, whereas process hollowing modifies the process and replaces its executable image before the process even starts execution; no shellcode is necessary.
There are different ways to hollow a process. I followed these steps:
CreateFileMappingW
)ImageBase
valueRCX
register to the address of the new executable image's entry point.Detecting hollowed processes is relatively easy. All you need to do is compare the main module of the victim process to its module path. If they're almost the same, the process is not hollowed. If they are significantly different, the process is hollowed and the appropriate actions can be taken.
.sln
solution file in Visual Studiox64|Release
RCX
contains the address of the entry point to be executed after initialization is completeRDX
contains the address of the PEB. I use this instead of querying for the PEB via NtQueryInformationProcess
MapViewOfFile/UnmapViewOfFile
can't be used as they perform the operation on the calling process
-- I'm using the internal NtMapViewOfSection/NtUnmapViewOfSection
to overcome this limitation, as they let you specify a process HANDLE
to perform the operation on