Process hollowing is a technique used by some malware in which a legitimate process is loaded on the system solely to act as a container for hostile code. At launch, the legitimate code is deallocated and replaced with malicious code.
![]() |
Process Hollowing (from here) |
// This function is used to run a new program. It creates a new process // and its primary thread. The new process runs the specified executable // file.
BOOL CreateProcess(
LPCWSTR pszImageName,
LPCWSTR pszCmdLine,
LPSECURITY_ATTRIBUTES psaProcess,
LPSECURITY_ATTRIBUTES psaThread,
BOOL fInheritHandles,
DWORD fdwCreate,
LPVOID pvEnvironment,
LPWSTR pszCurDir,
LPSTARTUPINFOW psiStartInfo,
LPPROCESS_INFORMATION pProcInfo
);
// [in] Specifies additional flags that control the priority
// and the creation of the process.
//
// CREATE_SUSPENDED fdwCreate flag
// The primary thread of the new process is created in a suspended state,
// and does not run until the ResumeThread function is called.
Step2.
The process has been created and it’s in suspended state. Now it’s time to hollow the legitimate code from memory in the hosted process. We might use the following API (ZwUnmapViewOfSection).
// the same Windows Native System Services routine.
// The ZwUnmapViewOfSection routine unmaps a view of a section from
// the virtual address space of a subject process.
// a view can be a whole or partial mapping of a section object in
// the virtual address space of a process.
__in HANDLE ProcessHandle,
__in_opt PVOID BaseAddress
);
// space of a specified process.
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess,
__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect
);
// Memory Protection Constant PAGE_EXECUTE_READWRITE = 0x40
// Enables execute, read-only, or read/write access to the committed
// region of pages.
Step4.
// area to be written to must be accessible or the operation fails.
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesWritten
);
Step5.
in order to camouflage the Malware, the author should re-set the normal pagination schema by setting Read/Execute protections like any other normal process by using VirtualProtectEx.
// address space of a specified process.
BOOL WINAPI VirtualProtectEx(
__in HANDLE hProcess,
__in LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flNewProtect,
__out PDWORD lpflOldProtect
);
BOOL WINAPI SetThreadContext(
__in HANDLE hThread,
__in const CONTEXT *lpContext
);
Step6.
It’s time to resume the suspended thread (ResumeThread) and “game over” !
// decremented to zero, the execution of the thread is resumed.
DWORD WINAPI ResumeThread(
__in HANDLE hThread
);
We’ve just fired up a brand new (and potentially malicious) process!
Focusing on detection, it is going to be hard if using static signatures (such as AntiVirus romantic signatures) but having the possibility to dynamically analyse system calls (such as a sandboxed environment) the detection rate will increase drastically.