Process Doppelgänging
Exploiting Transactional NTFS to create a process from a transient file that is never committed to disk — evading file-based AV scanning and hash-based detection
A payload is never written to disk in a normal sense. Instead, it's written inside a TxF transaction that is immediately rolled back after the section object is created. The section holds the payload image, but there's no on-disk file for AV to scan — the transaction rollback ensures the file never appears in the filesystem. A process is created from this transient section. The process image path in kernel structures points to a file that doesn't exist by the time the AV tries to read it.
Transactional NTFS (TxF)
Transactional NTFS, introduced in Windows Vista, allows file system operations to be grouped into ACID transactions. Using the Kernel Transaction Manager (KTM), you can open a transaction handle, perform file reads and writes within it, and then either commit (make changes permanent) or rollback (discard all changes).
Key TxF functions:
CreateTransaction— creates a KTM transaction handleCreateFileTransactedW— opens/creates a file within a transactionWriteFile— writes to the transacted file (changes visible only within the transaction)RollbackTransaction— discards all changes (file as if never written)CommitTransaction— makes changes permanent (file appears on disk)
Microsoft deprecated TxF in Windows 8 but did not remove it. The APIs still work on Windows 10 and 11. Deprecation means Microsoft may remove it in a future version and discourages new use — but for attack techniques, it remains functional. Windows Server 2022 still supports TxF.
The Doppelgänging Technique
Process Doppelganging Steps:
1. CreateTransaction() ────────────────────────────── Get TxF handle
2. CreateFileTransactedW(
"C:\Windows\System32\svchost.exe",
GENERIC_WRITE, ..., hTxn) ─────────────────── Open svchost.exe
inside transaction
3. WriteFile(hTransactedFile, payload) ────────────── Write payload over
svchost.exe content
(only visible inside txn)
4. NtCreateSection(
&hSection, ...,
SEC_IMAGE, hTransactedFile) ──────────────────── Create image section
from the transacted
(modified) file
5. RollbackTransaction(hTxn) ─────────────────────── Discard file changes!
svchost.exe on disk
is UNCHANGED.
Section still holds
the payload image.
6. NtCreateProcessEx(
&hProcess, ..., hSection) ────────────────────── Create process from
the section (payload!)
process path = svchost
7. Create thread, set entry point, resume ──────────── Process runs payload
Image path shows svchost
No payload on disk
Why It Evades File-Based Scanning
| Detection method | Result | Reason |
|---|---|---|
| On-access AV scan (file scan) | Scans real svchost.exe — clean | Transaction was rolled back; payload never committed to disk |
| Hash-based detection on process image file | Hash matches real svchost.exe | File on disk is the real svchost; hash is computed from disk, not from process memory |
| Process image path | Shows C:\Windows\System32\svchost.exe | Process was created from a section backed by that path |
Process Herpaderping Variant
Process Herpaderping (discovered 2020) is related but different: it creates a legitimate-looking process and then replaces the backing file on disk with an innocuous file after the section is mapped. The sequence:
- Write payload to a temp file on disk
- Create a section (SEC_IMAGE) from the payload file — the section holds the payload image
- Overwrite the file on disk with a decoy (benign .exe or garbage) while the section is open
- Create a process from the section
- Resume the process
Now: the process runs the payload, but if AV scans the file backing the process, it reads the decoy (benign) file. Windows holds the section in memory based on the original mapping — it doesn't re-read the file. The file on disk no longer matches the process memory.
Detection
# Detection approaches for Doppelganging and Herpaderping:
# 1. ETW-TI (Threat Intelligence provider):
# NtCreateSection with SEC_IMAGE flag, followed by NtCreateProcessEx
# without going through the normal CreateProcess path.
# Stack walk shows non-standard call path.
# 2. Process creation with unusual lineage:
# Sysmon Event ID 1 — svchost.exe spawned by unexpected parent
# (not services.exe, not svchost -k)
# 3. Kernel callback (PsSetCreateProcessNotifyRoutineEx):
# ImageFileName from callback does NOT match the in-memory PE.
# EDR kernel component: at process creation callback, read the
# process's image section and hash it; compare against the file
# reported in the callback. Mismatch = doppelganging/herpaderping.
# 4. Memory forensics:
# The process's image section is backed by a section that no longer
# matches any on-disk file, OR the file-backed content doesn't match
# the in-memory content. PE-sieve: read .text from process, read
# .text from the file on disk. Mismatch detected.
# Sigma (approximate — requires kernel telemetry):
title: Process Created from Transacted File Section (Doppelganging)
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith:
- '\svchost.exe'
- '\explorer.exe'
filter:
ParentImage|endswith:
- '\services.exe'
- '\wininit.exe'
condition: selection and not filter
Both Doppelgänging and Herpaderping defeat file-based scanning because the payload is never stably on disk at the time AV scans it. Effective detection requires: (1) The PsSetCreateProcessNotifyRoutineEx kernel callback, which fires at process creation and provides the section handle — from which the EDR can read the actual image being loaded. (2) ETW-TI, which records NtCreateSection + NtCreateProcessEx events with call stacks, making the unusual API sequence visible even when the file content has been replaced. Neither is available to user-mode-only security tools.
Q & A
Can Process Doppelgänging be defended against without EDR kernel components?
Not fully. A purely user-mode security tool cannot intercept NtCreateSection with a transacted file handle before the section object is created in the kernel. Once the section object exists (backed by the rolled-back transaction), a user-mode tool has no way to see the original file content — the transaction was rolled back, so the file on disk shows the original legitimate binary. The closest a user-mode tool can get: monitor for unusual TxF API usage (CreateTransaction followed by CreateFileTransacted followed by RollbackTransaction in quick succession), which is detectable via API hooking in specific processes. But if the malware avoids ntdll hooks (via direct syscalls for the TxF operations), this doesn't work either. The reliable defense layers are: (1) EDR kernel driver with PsSetCreateProcessNotifyRoutineEx that reads the actual image section at process creation time. (2) ETW-TI telemetry fed to a security analytics platform. (3) WDAC code integrity: SEC_IMAGE sections can only be created from signed files when WDAC is enforced — an attacker writing a payload to a TxF file would need to sign it. (4) Restricting TxF entirely via AppLocker file rule restrictions on processes that can call TxF APIs — though this affects legitimate backup software. There is no pure user-mode mitigation that stops a motivated attacker using Doppelgänging.
Why did Microsoft deprecate TxF but not remove it, and does that mean the technique will eventually stop working?
Microsoft deprecated TxF because it was enormously complex to implement correctly, and the use cases it was designed for (database-style transactional file operations) were better served by application-level transaction managers. The deprecation means: Microsoft will not add new features to TxF, will not fix bugs in TxF (unless they're security vulnerabilities), and developers should not use it in new code. It does NOT mean imminent removal. The reasons it hasn't been removed: (1) Legacy compatibility — some enterprise backup software (SQL Server with TDE, some SAP components) uses TxF. Removing it would break those workloads. (2) The security community has demonstrated that TxF removal breaks legitimate software, making it politically difficult. (3) Removal of an API this deeply embedded in NTFS internals is risky and testing-intensive. HVCI (Hypervisor Protected Code Integrity) is the more effective long-term countermeasure: even if TxF is used to create a section with unsigned payload bytes, HVCI's code integrity check will refuse to execute unsigned code from that section in protected processes. HVCI doesn't prevent the process from being created — it prevents execution of unsigned code, which is the actual harm. On Windows 11 with HVCI enabled by default (hardware requirements permitting), Doppelgänging's effectiveness is significantly reduced because the payload must be signed, which essentially forces attackers to use legitimate or stolen code signing certificates.