PPID spoofing is a technique that allows attackers to start programs with arbitrary parent process set. This helps attackers make it look as if their programs were spawned by another process (instead of the one that would have spawned it if no spoofing was done) and it may help evade detections, that are based on parent/child process relationships.
For example, by default, most programs that an interactive user launches, will be spawned by explorer.exe:
However, with the below code, we can make it look as if the notepad.exe was spawned by igfxTray.exe (PID 6200):
Now, let's execute our notepad.exe with a spoofed parent again and let's look at where the log files from our ETW tracing session are saved to:
Open the C:\ppid-spoofing.etl in Windows Event Viewer:
We can find an event with ID 1, saying that notepad was started by a process with PID 6200 (that's our spoofed PPID of the process igfxTray.exe):
If we look at the same data in an XML view (the details tab) and cross check it with our processes tree in Process Explorer, we see:
in blue - the notepad we started with a spoofed process PID
in red - notepad's spoofed parent process and its PID
in black - our malicious program that started notepad with a spoofed PPID!
From the above, we can conclude that when ParentProcessId (red, PID 6200) != Execution Process ID (black, PID 11076), we may be looking at a PPID spoofing.
Now that confirmed we have the required telemetry for detection, we can write a simple C# consumer to do real time PPID spoofing detection:
ppid-spoofing-detection.cs
# based on https://github.com/zodiacon/DotNextSP2019/blob/master/SimpleConsumer/Program.csusing Microsoft.Diagnostics.Tracing.Parsers;usingMicrosoft.Diagnostics.Tracing.Session;usingSystem;usingSystem.Collections.Generic;usingSystem.Diagnostics;usingSystem.Linq;usingSystem.Linq.Expressions;usingSystem.Text;usingSystem.Text.RegularExpressions;usingSystem.Threading.Tasks;namespacePPIDSpoofingDetection{staticclassProgram {staticvoidMain(string[] args) {using (var session =newTraceEventSession("spotless-ppid-spoofing")) {Console.CancelKeyPress+=delegate {session.Source.StopProcessing();session.Dispose(); }; session.EnableProvider("Microsoft-Windows-Kernel-Process", Microsoft.Diagnostics.Tracing.TraceEventLevel.Always, 0x10);
var parser =session.Source.Dynamic;parser.All+= e => {if (e.OpcodeName=="Start"&&Regex.IsMatch(e.FormattedMessage.ToLower(),"werfault") ==false) {string[] messageBits =e.FormattedMessage.Replace(",",string.Empty).Split(' ');int PID =int.Parse(messageBits[1]);int PPID =int.Parse(messageBits[10]);int realPPID =e.ProcessID; // if ParentProcessId (red, PID 6200) != Execution Process ID (black, PID 11076)if (PPID != realPPID) { // this may fail if the process is already gone.string processName =Process.GetProcessById(PID).ProcessName; Console.WriteLine($"{e.TimeStamp} PPID Spoofing detected: {processName} (PID={PID}) started by PPID={realPPID} rather than PPID={PPID}");
} } };session.Source.Process(); } } }}
If we compile and run the code, and then attempt to launch notepad with a spoofed PPID again, it will get flagged: