Weaponizing Process Ghosting for Stealthy Payload Execution

When executing unbacked code or launching custom binaries on Windows endpoints, traditional process injection techniques often trigger endpoint detection mechanisms. Memory scanners flag unbacked executable memory regions, while storage minifilters inspect binaries written to disk before they can execute. To bypass static analysis on disk without triggering file-creation alerts, offensive operators often turn to techniques like Process Doppelgänging or Process Herpaderping.
Process Ghosting offers a cleaner alternative. By leveraging how the Windows kernel handles pending file deletions, Process Ghosting lets you create a process from an executable file, delete the file on disk before process initialization finishes, and execute code from an image section that technically points to a removed file.
Understanding the Mechanics of Process Ghosting
Traditional executable loading relies on the Windows subsystem reading a file from disk, verifying its existence, and creating a section object (NtCreateSection) backed by that binary.
Process Ghosting manipulates this sequence by setting the file’s disposition state to pending deletion before mapping the section into memory.
The exact execution sequence follows these steps:
- Create a target file: Open a write-access handle to a temporary file path on disk using
NtCreateFile. - Set disposition for deletion: Call
NtSetInformationFilewithFILE_DISPOSITION_INFORMATION, settingDeleteFile = TRUE. The kernel marks the file as pending deletion, but keeps the handle valid. - Write the payload: Write the raw executable byte stream into the opened handle using
NtWriteFile. - Create an image section: Call
NtCreateSectionwith theSEC_IMAGEflag using the file handle. The kernel maps the payload into an image section despite its pending deletion status. - Close the file handle: Close the file handle via
NtClose. Because the disposition was set to delete on close, the operating system removes the file from the disk immediately. - Instantiate process and thread: Invoke
NtCreateProcessExusing the created section handle, populate the process parameters, and create the main execution thread viaNtCreateThreadEx.
Because the underlying file vanishes from the file system before NtCreateProcessEx executes, security agents that attempt to open or scan the disk path associated with the process handle will receive a file-not-found error.
Code Execution and Implementation Nuances
Implementing Process Ghosting requires direct native API calls (ntdll.dll). High-level Win32 functions like CreateProcess wrap process creation with mandatory file validation checks that fail when targeted against files pending deletion.
Below is a simplified native execution flow in C:
// 1. Create temporary file on disk
NtCreateFile(&hFile, FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE,
&objAttr, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SUPERSEDE, FILE_NON_DIRECTORY_FILE, NULL, 0);
// 2. Mark handle for pending deletion
FILE_DISPOSITION_INFORMATION disposition = { .DeleteFile = TRUE };
NtSetInformationFile(hFile, &ioStatus, &disposition,
sizeof(disposition), FileDispositionInformation);
// 3. Write binary bytes and map image section
NtWriteFile(hFile, NULL, NULL, NULL, &ioStatus, payloadBuffer, payloadSize, NULL, NULL);
NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL, PAGE_READONLY, SEC_IMAGE, hFile);
// 4. Close handle to trigger physical file deletion
NtClose(hFile);
// 5. Instantiate process from unlinked section
NtCreateProcessEx(&hProcess, PROCESS_ALL_ACCESS, NULL, NtCurrentProcess(),
PROCESS_CREATE_FLAGS_INHERIT_HANDLES, hSection, NULL, NULL, 0);
After process creation, you must manually allocate and write Process Environment Block (PEB) parameters into the remote process using RtlCreateProcessParametersEx and VirtualAllocEx before executing the primary thread.
Telemetry Gaps and Defensive Realities
Process Ghosting primary bypasses minifilter file-system drivers that perform on-write or on-open file scanning. When defensive tooling attempts to inspect the file backed by the newly spawned process, the kernel returns STATUS_FILE_DELETED (0xC0000123).
However, operators must understand the telemetry leftovers:
- Kernel Process Callbacks:
PspCreateProcessNotifyRoutinestill triggers whenNtCreateProcessExruns. Kernel telemetry drivers receive the notification and capture execution events. - Memory Forensics: The allocated memory region retains valid
SEC_IMAGEcharacteristics. Memory inspection tools parsing the virtual address space will still identify PE headers in memory. - Parent-Child Relationships: Without explicitly spoofing the parent process ID (PPID) in the process parameters, the ghosted process shares an obvious lineage with the originating loader.
Process Ghosting remains an essential technique when operating against strict disk-centric static analysis controls, highlighting how low-level Windows kernel handle semantics can be leveraged to execute code without leaving binary artifacts on storage devices.