Module 2: PE Tampering Techniques Overview
The evolution of PE image tampering — from Process Hollowing to Ghosting, each technique exploiting a different gap in the process creation chain.
Module Objective
Survey the four major PE tampering techniques — Process Hollowing, Process Doppelgänging, Process Herpaderping, and Process Ghosting — understanding how each one manipulates a different stage of the file → section → process pipeline, what weaknesses each addresses, and the evolutionary progression that led to Ghosting.
1. The Core Problem All Techniques Share
All PE tampering techniques try to solve the same problem: execute malicious code in a process that appears legitimate to security tools. The Windows process creation chain (file → section → process → thread) gives security tools multiple inspection points. Each tampering technique targets a different gap between these inspection points.
Inspection Points in Process Creation
AV scans file
Kernel callback
PsSetCreateProcessNotifyRoutineEx fires
Execution begins
The trick is to ensure that at each inspection point, security tools either see a clean file, see no file at all, or cannot access the file to scan it.
2. Process Hollowing (2004+)
Process Hollowing is the oldest and most well-known technique. It creates a legitimate process in a suspended state, then replaces its memory contents with malicious code before resuming.
Hollowing Flow
- Create a legitimate process (e.g.,
svchost.exe) in a suspended state usingCreateProcessWwithCREATE_SUSPENDED - Unmap the original executable image using
NtUnmapViewOfSection - Allocate new memory in the target process with
VirtualAllocEx - Write the malicious PE into the allocated memory with
WriteProcessMemory - Update the PEB image base and thread context (entry point in
EAX/RCX) to point to the new image - Resume the main thread with
ResumeThread
// Simplified Process Hollowing pseudocode
CreateProcessW(L"svchost.exe", ..., CREATE_SUSPENDED, ..., &pi);
// Unmap the original image
NtUnmapViewOfSection(pi.hProcess, pImageBase);
// Allocate and write malicious PE
LPVOID pNewBase = VirtualAllocEx(pi.hProcess,
pPreferredBase, imageSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, pNewBase, maliciousPE, imageSize, NULL);
// Fix up PEB and thread context
// ... update ImageBaseAddress in PEB ...
// ... set thread context RCX to new entry point ...
ResumeThread(pi.hThread);
Why Hollowing Is Detected
- Memory mismatch: The in-memory image does not match the file on disk. Memory scanning tools compare mapped sections to their backing files.
- Unmapped original: The original image is unmapped, which is highly unusual and detectable.
- RWX memory: The new allocation often uses
PAGE_EXECUTE_READWRITE, a red flag. - PEB modification: Changing the image base in the PEB is detectable.
- No file change: The original file on disk is untouched — the mismatch between file and memory is easy to spot.
3. Process Doppelgänging (2017)
Presented by Tal Liberman and Eugene Kogan of enSilo at Black Hat Europe 2017, Process Doppelgänging uses NTFS transactions (TxF) to create a process from a file that never actually exists on disk in its malicious form.
Doppelgänging Flow
- Create an NTFS transaction using
NtCreateTransaction - Open a file within the transaction using
NtCreateFile— this file is transacted, meaning changes are only visible within the transaction context - Write the malicious PE content to the transacted file
- Create a
SEC_IMAGEsection from the transacted file handle usingNtCreateSection - Rollback the transaction using
NtRollbackTransaction— the file reverts to its original state (or never existed), but the section object persists - Create a process from the section using
NtCreateProcessEx
// Process Doppelganging key steps
HANDLE hTransaction, hFile, hSection;
// 1. Create NTFS transaction
NtCreateTransaction(&hTransaction, ...);
// 2. Create file within transaction
NtCreateFile(&hFile, ...,
hTransaction, // transacted operation
FILE_SUPERSEDE, ...);
// 3. Write malicious PE to transacted file
NtWriteFile(hFile, ..., maliciousPE, peSize, ...);
// 4. Create image section from transacted file
NtCreateSection(&hSection, ..., SEC_IMAGE, hFile);
// 5. Rollback - file disappears, section remains
NtRollbackTransaction(hTransaction, TRUE);
// 6. Create process from the persisted section
NtCreateProcessEx(&hProcess, ..., hSection, ...);
Doppelgänging Advantages
- The malicious file never exists on disk in a committed state — it only exists within the rolled-back transaction
- No process is created in a suspended state and then modified
- No
NtUnmapViewOfSectioncalls - The process image appears file-backed with a valid path
Doppelgänging Limitations
- TxF is deprecated: Microsoft deprecated NTFS transactions starting in Windows 10, and monitoring for TxF API usage became a strong detection signal
- Kernel callbacks:
PsSetCreateProcessNotifyRoutineExfires when the first thread is inserted (viaNtCreateThreadEx), providing theFileObjectfor inspection of the transacted file - Stability issues: TxF interactions with antivirus minifilter drivers can cause BSODs on some systems
4. Process Herpaderping (2020)
Created by Johnny Shaw (jxy-s), Process Herpaderping exploits the gap between when the section is created from a file and when AV/EDR gets around to scanning that file in response to process creation notifications.
Herpaderping Flow
- Create a new file on disk using
NtCreateFile - Write the malicious PE content to the file
- Create a
SEC_IMAGEsection from the file usingNtCreateSection— the section now contains the malicious image - Overwrite the file on disk with benign content (e.g., a clean copy of
notepad.exe) - Close the file handle
- Create a process from the section — process runs malicious code, but the file on disk is now benign
// Process Herpaderping key steps
HANDLE hFile, hSection;
// 1. Create file, write malicious PE
NtCreateFile(&hFile, ..., FILE_SUPERSEDE, ...);
NtWriteFile(hFile, ..., maliciousPE, peSize, ...);
// 2. Create section while file has malicious content
NtCreateSection(&hSection, ..., SEC_IMAGE, hFile);
// 3. Overwrite file with benign content AFTER section creation
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
NtWriteFile(hFile, ..., benignPE, benignSize, ...);
// 4. Close file - on-disk content is now benign
NtClose(hFile);
// 5. Process runs from the malicious section
NtCreateProcessEx(&hProcess, ..., hSection, ...);
The key insight is that the section captures the file’s content at creation time. Modifying the file afterward does not change the section. When AV scans the file in response to the process creation callback, it sees benign content.
Herpaderping Limitations
- File still exists on disk: The file is present and scannable — the AV just sees benign content. But sophisticated EDR can detect the mismatch between the section’s content and the current file content by comparing the section’s
CONTROL_AREAto the file. - Minifilter detection: NTFS minifilter drivers that intercept
IRP_MJ_WRITEcan detect the overwrite of an image file after section creation. - File on disk is evidence: Even though the file contains benign content, its presence, creation time, and metadata may be suspicious.
5. Process Ghosting (2021)
Process Ghosting, discovered by Gabriel Landau of Elastic Security and implemented as a proof-of-concept by hasherezade (process_ghosting on GitHub), takes the evolution one step further. Instead of modifying the file after section creation (Herpaderping), it deletes the file entirely. The process runs from a section whose backing file no longer exists.
Ghosting Flow
- Create a new file on disk using
NtCreateFile - Put the file into the delete-pending state using
NtSetInformationFilewithFileDispositionInformation - Write the malicious PE content to the file (the file is delete-pending but the handle is still valid for writes)
- Create a
SEC_IMAGEsection from the delete-pending file handle - Close the file handle — the file is deleted from disk because it was marked delete-pending
- Create a process from the section using
NtCreateProcessEx
Why Ghosting Beats Herpaderping
In Herpaderping, the file on disk still exists (with benign content). A sophisticated scanner could notice the discrepancy between the section’s content and the file, or flag the overwrite pattern. In Ghosting, there is no file on disk at all. When AV tries to open the file for scanning, it either gets STATUS_FILE_DELETED (if the delete has completed) or STATUS_DELETE_PENDING (if the file is still in the delete-pending state). Either way, the scan cannot proceed.
6. Evolution Comparison
| Technique | Year | File State at Process Creation | What AV Sees | Key Weakness |
|---|---|---|---|---|
| Hollowing | ~2004 | Original file intact on disk | Memory/file mismatch | Unmapped sections, PEB mods, RWX |
| Doppelgänging | 2017 | Transaction rolled back; file reverted | Clean file (original or non-existent) | TxF deprecated, driver conflicts |
| Herpaderping | 2020 | File overwritten with benign content | Benign file content | File still exists, overwrite detectable |
| Ghosting | 2021 | File deleted (or delete-pending) | No file to scan at all | Delete-pending state detectable by kernel drivers |
7. The Technique Family Tree
Each technique builds on the lessons of the previous one:
Evolutionary Progression
| Problem | Solution | Next Problem |
|---|---|---|
| Need to run malicious code in a process | Hollowing: Replace process memory | Memory/file mismatch is obvious |
| File and memory must match | Doppelgänging: Use TxF so file never commits | TxF is deprecated, driver issues |
| Need non-TxF approach | Herpaderping: Overwrite file after section creation | File still on disk, overwrite detectable |
| File on disk is still evidence | Ghosting: Delete file after section creation | Delete-pending state can be detected at kernel level |
8. What They All Have in Common
Despite their differences, all four techniques share core principles:
- They all exploit the separation between
NtCreateSectionandNtCreateProcessEx - They all rely on the fact that sections persist independently of their backing files
- They all use native NT APIs (
NtCreateFile,NtCreateSection,NtCreateProcessEx,NtCreateThreadEx) rather than the higher-level Win32 API - They all require setting up process parameters and the PEB manually
- They all target the gap between when the kernel captures the image content and when security tools inspect the file
Process Ghosting represents the current state of the art in this family, eliminating the backing file entirely rather than modifying it.
Knowledge Check
Q1: Which technique uses NTFS transactions (TxF) to create a process from a file that was never committed to disk?
Q2: What is the key difference between Herpaderping and Ghosting?
Q3: What is the main weakness of Process Hollowing that all later techniques sought to address?