Process relationships

About 14 min read

On this page
03 of 06

Operating systems have predictable process lineages. Deviations from those patterns are highly informative. Mapping parent-child chains turns isolated alerts into narratives.

Normal patterns

These are the lineages that should not surprise you. On Windows:

Expectedexplorer.exe → winword.exe

User-launched document activity.

Expectedservices.exe → svchost.exe

Normal Windows service initiation.

Expectedsvchost.exe (Schedule) → <scheduled binary>

Scheduled task execution: on modern Windows, tasks spawn from svchost.exe running the Schedule service, sometimes via taskhostw.exe. (taskeng.exe was retired in Windows 10 1511; on Windows 10/11 or Server 2016+ it does not exist, so seeing it there is a masquerading red flag.)

And on macOS, where Case B in the Alert worked example (a macOS developer workstation running the Cursor IDE) lives:

Expectedlaunchd → <almost everything>

launchd is PID 1: macOS’s init process, service manager, and scheduler in one. Daemons, agents, and user-launched apps all ultimately descend from it, so “parent is launchd” carries far less signal than “parent is services.exe” does on Windows.

ExpectedCursor → Cursor Helper (Plugin) → child

Electron apps launch their core helpers (Renderer, GPU, network, utility) from the main app process. In VS Code-family editors such as Cursor, the extension-host helper then legitimately launches processes of its own: language servers, indexers, shells, git, language runtimes. The anomaly is a helper whose ancestry leads outside the app, or a helper binary running from outside the signed app bundle.

ExpectedTerminal.app → zsh → <tool>

Interactive shell work descends from a terminal. The suspicious mirror image is a GUI app with no business shelling out (a PDF viewer, a chat client) spawning bash or osascript.


Reading a macOS tree: signatures and notarization

Case B hands you this tree. Here is how to parse it:

launchd (PID 1)                         Apple platform binary
  └─ Cursor                             Developer ID: Anysphere, notarized
       ├─ Cursor Helper                 Developer ID: Anysphere, notarized
       └─ Cursor Helper (Plugin)        extension host, no sandbox
            └─ Cursor Helper (Plugin)   child: runs a script from inside Cursor.app

The alerted edge is the last one: the extension host launching a child that opened the outbound connections. It is vendor-documented behavior when the child’s script lives inside the signed bundle, and the question to ask when it does not.

On macOS the tree gives you two extra parse targets that Windows lineage does not: the code-signing chain and notarization status. Together with the install path, they are strong evidence about provenance, not about behavior. Apple has notarized malware more than once (OSX.Shlayer payloads in 2020; a MacSync Stealer dropper in December 2025, whose certificate Apple later revoked). Notarization checks what was submitted, not what the app downloads after launch. So read signed-and-notarized as “who published it,” and corroborate with path, Team ID reputation, peer baseline and behavior before clearing.

Signing identity

Apple’s own platform binaries (launchd, the system daemons) are signed by Apple’s Software Signing certificate. Third-party software is signed with a Developer ID certificate that names the vendor. The parse question is not “is it signed” but “who signed it, and does that match what the binary claims to be.” Ad-hoc or missing signatures inside a tree of properly signed processes are the standout. Parse the Team ID, not just the name: it is the stable identifier, it is what intel reports and Apple revocations cite, and a lookalike vendor name with a different Team ID is a red flag. Mac App Store apps carry Apple’s signature instead of a Developer ID.

Notarization

Notarization is Apple’s automated malware scan for third-party software distributed outside the App Store; Gatekeeper checks the ticket at first launch. Apple’s own OS binaries are not notarized (they do not need to be), so “launchd is not notarized” is expected, while “this vendor app is not notarized” is a real flag on a managed fleet.

Install path

A signed binary running from /Applications where the MDM (mobile device management) system installed it is baseline. The same binary name running out of ~/Library, /tmp, or a mounted DMG is staging. Signature says who built it; path says who put it there. /Applications is admin-writable, so the path counts only with the MDM record of what was installed there. Neither covers code the signed app loads at runtime: extensions, plugins, MCP servers.

Where does this telemetry come from? EDR agents on macOS consume the Endpoint Security framework for process and signing events; the formats and normalization page covers the per-platform sources. The tells transfer directly: a hollowed-svchost equivalent does not exist on macOS, but “helper whose ancestry leads outside its app,” “signed binary in the wrong path,” and “unsigned process in a signed tree” are the same lineage-plus-trust reasoning this page teaches for Windows.


What to flag

Suspicious lineage signals

  • Unexpected origins. notepad.exe spawning cmd.exe or powershell.exe. Notepad should not be spawning anything.
  • Compressed timing. Multiple processes launching within sub-second intervals suggests scripted automation. Installers and build systems produce the same burst legitimately, so weigh the parent process and the host’s role before reading the burst as hostile.
  • Office spawning shells. winword.exe → cmd.exe → powershell.exe is the classic macro-execution chain (rarer since Office began blocking macros in internet-sourced files by default in 2022).
  • Paste-and-run (ClickFix). explorer.exe → powershell.exe or mshta.exe (or Windows Terminal → PowerShell in newer variants), with flags such as -w h and iex(irm ...), seconds after a browser visit. Run-dialog variants leave the pasted command in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU. The user ran it themselves, so no exploit or attachment appears in the tree.
  • Other post-macro delivery. A shortcut (.lnk) or script launched from a mounted ISO or an extracted archive (wscript.exe, mshta.exe, cmd.exe under explorer.exe), or msiexec.exe installing a package straight from a browser download.
  • System binaries in the wrong context. A system binary (lsass.exe, services.exe, svchost.exe) running as a standard user, or from outside System32, or with an unexpected parent.

A direct spawn of msdt.exe by winword.exe strongly suggests exploitation of Follina CVE-2022-30190. A vulnerability in the Microsoft Support Diagnostic Tool that allowed a malicious Office document to trigger remote code execution via a crafted URL handler. , where a malicious document triggers the Microsoft Support Diagnostic Tool to run attacker-controlled code. (Microsoft patched Follina in the June 2022 cumulative updates and has deprecated MSDT itself, so on a patched host the chain is rare. Any Office process spawning msdt.exe is still worth investigating on its own.)


Common malicious chains

Five chains an analyst should recognize on sight. Each one has a characteristic shape, a typical purpose, and a recognizable telltale that distinguishes it from look-alike legitimate activity.

Rogue script execution

powershell.exedownloadsscript.ps1suspiciousruns from%TEMP%suspicious

PowerShell (ATT&CK T1059.001) downloads a script from a remote location and runs it from a user-writable directory (the per-user %TEMP%, or the shared %PUBLIC% at C:\Users\Public). In this row the labeled arrows are actions (download, execute-from), not parent-child spawns; the boxes are a process, an artifact, and a location. Path alone is weak evidence: installers and management agents stage scripts there, and PowerShell itself writes _PSScriptPolicyTest*.ps1 probe files to %TEMP% at startup (written, never run). The telltale is the sequence: a network fetch by PowerShell, then execution of that same file from that path.

Registry manipulation for persistence

cmd.exespawnsreg.exewritesRun key (autorun)suspicious

A shell spawns a trusted binary (reg.exe here; PowerShell and WMI offer parallel routes) to write a registry value that survives reboot (ATT&CK T1547.001). The spawn itself is ordinary; the destination key is what gives it away. Watch for writes to the Run and RunOnce keys (HKLM and HKCU \Software\Microsoft\Windows\CurrentVersion\Run and \RunOnce, which execute at user logon), Winlogon Shell/Userinit values, or service ImagePath values. Sysmon Event 13 (registry value set) is the usual source; Security 4657 appears only if a SACL is set on the key.

Unauthorized service creation

cmd.exespawnssc.exe createcreatesnew servicesuspicious

sc.exe create registers a new Windows service (ATT&CK T1543.003). With start= auto (or delayed-auto) it survives reboots; the default is manual (demand). Read the service binary path in System Event 7045 (logged by default) or Security Event 4697 (needs the Audit Security System Extension subcategory). Legitimate software installs services at install time; adversaries do it post-compromise. Watch for service creation outside an installer process or from an unusual user context. Remote creation via PsExec or Impacket shows no sc.exe at all: just a new service, often randomly named, whose binary runs as a child of services.exe.

Process hollowing

svchost.execode swappedstill ✓

A legitimate process (svchost.exe is a favorite) is created suspended (ATT&CK T1055.012), its executable memory is replaced with attacker code, and it resumes under the original name and digital signature. The tree looks normal at a glance, but lineage still betrays it: real svchost.exe is spawned by services.exe, so an svchost whose parent is anything else deserves immediate scrutiny. The parent check has a known blind spot: the reported parent can be forged (see parent PID spoofing below). Memory and behavioral telemetry are how the code swap itself is caught; signature checks will not.

Token theft and impersonation

alice (user)token stolensuspiciousruns as alice

A new process is launched under another user’s security context using a stolen authentication Token A Windows credential object that represents an authenticated user session. Tokens let processes run with the rights of the user who started them. Stealing one lets a process behave as that user without ever needing their password. (ATT&CK T1134.001). The activity looks like the impersonated user. Detection depends on lineage plus logon data: a child running as a different user than its parent with no matching 4624/4648 logon, a LogonId that belongs to another session, or Logon Type 9 (NewCredentials) from runas /netonly-style token creation.

Case study

Reconstructing a macro-borne intrusion

An EDR alert reports anomalous child processes spawned by Microsoft Word on a finance team workstation.

Process tree investigation reveals:

winword.exe (PID 6120)
  └─ cmd.exe (PID 6188)
       └─ powershell.exe (PID 6204)
            └─ outbound TLS connection to a recently registered domain

The chain alone is enough to recognize the pattern: macro execution from a document, shell launch, scripted download cradle, command-and-control establishment. The exact IP is not the point. The shape of the chain is. Case A reaches the same cradle with no document at all: the user pastes a command into the Run dialog, so the whole tree is explorer.exe → powershell.exe, and the evidence of delivery is the RunMRU value and the browser’s visit to the lure page instead of an attachment.

What an analyst checks next
  • The originating email and attachment in the user’s mailbox.
  • Other recipients of the same email (lateral exposure).
  • The PowerShell Microsoft's shell and scripting language: Windows PowerShell 5.1 on .NET Framework, cross-platform PowerShell 7 on .NET. The most abused interpreter on Windows (ATT&CK T1059.001). Triage tells: -EncodedCommand or -enc (Base64 of UTF-16LE text), -NoProfile, -WindowStyle Hidden, IEX with a download cradle, and an Office or browser parent. Script Block Logging (Event ID 4104) records de-obfuscated script content. Command Line In SOC analysis, the argument string a process was launched with. Often the load-bearing forensic field on an EDR alert because it reveals what the process was actually told to do. for download cradle patterns.
  • DNS queries from the host in the relevant window.
  • File system creates in %TEMP% and %APPDATA% correlated to the PowerShell process (its ProcessGuid, not the PID alone).
  • How the macro got permission to run: whether the user clicked Enable Content or unblocked the file, whether the file carried a Mark of the Web, and whether it arrived inside a container or archive (an ISO/IMG/VHD, or a ZIP extracted with a tool that does not propagate the Mark of the Web) that left it unmarked. Macros do not run in the preview pane or Protected View.

Reconstructing the tree

A tree in a console is a reconstruction, stitched together from individual process-creation events. Four mechanics decide whether the stitching is right:

  • Join on unique IDs, never on PID alone. Windows reuses PIDs, and so do macOS and Linux. Join on Sysmon’s ProcessGuid / ParentProcessGuid or the EDR’s unique process ID, plus start time. A PID join can attach a child to an unrelated process that later got the same number.
  • Exited and orphaned parents. A child keeps its parent’s PID after the parent exits, and live tools then show it with no parent at all, or with a new process that inherited the number. Rebuild from the historical creation events, not from what is running now.
  • Creator versus parent. Usually the same process. They differ when a broker launches something on another process’s behalf (wmiprvse.exe for WMI, services.exe for a service, a COM server, the Secondary Logon service for runas) and when the parent was deliberately forged (see parent PID spoofing below). When the parent is a broker, look one hop further back for who asked.
  • Missing links. A parent with no creation event of its own is a visibility gap. Record it as one rather than filling it with the most likely story.
Annotated sample: why a PID join goes wrong

Three Sysmon Event ID 1 records from one laptop on one day, trimmed to the join fields. The samples are fictional; the field names are real.

UtcTime                  ProcessGuid                             ProcessId  Image
2026-03-10 09:02:17.114  {6a1f0c3e-1a02-65f0-2210-000000001a00}  7500       OneDrive.exe     (exited 09:40)
2026-03-10 14:20:51.302  {6a1f0c3e-2b7c-65f0-3b19-000000001a00}  7500       WINWORD.EXE
2026-03-10 14:22:04.871  {6a1f0c3e-2b7d-65f0-4c1a-000000001a00}  8128       powershell.exe
                         ParentProcessGuid={6a1f0c3e-2b7c-65f0-3b19-000000001a00}  ParentProcessId=7500
  • PID 7500 was used twice that day. A join on ParentProcessId alone returns both OneDrive and Word as candidate parents, and a query that keeps the first match puts PowerShell under OneDrive.
  • ParentProcessGuid matches exactly one record, Word’s. The GUID is unique per process start, which is the whole point of it.
  • Without Sysmon, use the EDR’s own unique process ID, or join on host plus PID plus a start time that falls inside the parent’s lifetime, and record the join as weaker.

Visualization tools

Process tree visualization makes anomalies obvious. Triage usually needs the tree as it was when the alert fired, not as it is now, so three categories of tooling matter:

Historical reconstruction

EDR consoles (CrowdStrike Falcon, SentinelOne, Microsoft Defender XDR) with historical playback at scale, and Sysmon in your SIEM joined on ProcessGuid / ParentProcessGuid. This is where most triage trees come from.

Live host inspection

Sysinternals Process Explorer and System Informer (formerly Process Hacker; renamed in 2022 and still actively developed) for detailed tree and thread inspection on a single host. They show current state only: a process that has exited is gone.

Fleet collection

Velociraptor and osquery to ask the same question of every host at once: which machines are running this binary, this parent-child pair, or this launch item right now.


Evasion to know about

Adversaries who understand process tree analysis design their tradecraft to look normal in the tree. The five techniques below are ones an analyst will meet in real intrusions, each defeating a different layer of tree analysis (process hollowing, covered above, is a sixth). Recognizing them by name accelerates the moment of “wait, that is not what it looks like.”

DLL hijacking and side-loading (T1574.001)

A DLL Dynamic Link Library. A shared library that Windows loads into a process at runtime to provide functions the process uses. Programs name the DLLs they need; Windows finds them by searching a defined order of directories. is loaded by a legitimate binary from one of several search paths in a defined order. An adversary places a malicious DLL earlier in that order than the real one. The legitimate, signed binary loads the malicious DLL instead of the real one, executing attacker code under the trust of the original program. The most common variant today is side-loading: a signed vendor EXE copied into a user-writable folder next to a malicious DLL with the name it expects.

The telltale: a process tree that looks normal at the binary level, but with a DLL that was loaded from an unusual location (a writable directory, the user profile, a removable drive). EDRs that track DLL loads can flag this. Tree views that only show processes cannot.

Fileless execution

fileless An execution model that runs the malicious payload entirely from memory, without ever writing it to disk. Common techniques include PowerShell loading code via reflection, WMI event subscriptions whose consumers execute script payloads (created through the WMI API, for example from PowerShell, or by compiling a MOF file with mofcomp; stored in the WMI repository; Sysmon events 19-21 record them), and .NET assemblies loaded straight into memory. attacks run their payload from memory, never landing on disk. Disk-based detections (file hashes, AV scans, file integrity monitoring) see nothing. The process tree shows only legitimate parents (often PowerShell or WMI).

The telltale: a long-running PowerShell or WMI process with a command line that decodes a base64 blob and executes it, or a WMI event subscription that fires at boot. Memory analysis and command-line decoding catch this; surface process inspection does not.

Alternate data streams (ADS, T1564.004; legacy)

NTFS supports multiple data streams per file. The default stream is what most tools and users see. An alternate data stream A secondary data stream attached to an NTFS file. The primary stream is what you see in Explorer. The alternate stream is invisible to most tools but can be opened and executed directly. Used historically to hide payloads inside otherwise innocuous files. can hide a payload inside a normal-looking file, and the malicious code can be invoked directly from the stream.

The telltale: a process whose image path has a second colon after the filename (C:\Users\victim\readme.txt:hidden.exe). Sysmon Event 15 (FileCreateStreamHash) records stream creation. Most modern EDRs flag ADS execution, but the technique is still seen in older or under-instrumented environments.

LOLBin-only chains (T1218)

The adversary uses only trusted system binaries ( LOLBins Living Off the Land Binaries: trusted, signed system executables (certutil, rundll32, mshta) weaponized so the malicious part is the argument line, not the file on disk. The evasion face of the Living Off The Land technique covered under Execution. such as certutil, regsvr32, mshta, rundll32) to download, decode, and execute attacker code. Payload files may land on disk (certutil -urlcache -f writes the target file, and certutil can leave a copy under CryptnetUrlCache, which is where file telemetry catches them), but no unsigned attacker executable runs, and no signature on any running binary is wrong.

The telltale: common system binaries being invoked with command-line flags they almost never use in legitimate operations (certutil -urlcache -split -f, regsvr32 /s /u /n /i:http://…). Command-line parsing is what catches this; the process names alone look harmless.

Parent PID Spoofing Spawns processes that appear to be launched by trusted executables (like explorer.exe), misleading analysts and EDR that rely on the process tree. (T1134.004)

The creating process asks Windows to record a different parent (CreateProcess with an explicit parent-process attribute, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS), naming any process it has a handle to. A payload launched by Word then appears as a child of explorer.exe, and the tree tells a plausible story that never happened.

The telltale: the reported parent disagrees with the actual creator recorded by EDR or kernel ETW process telemetry, or the reported parent was not running interactively at the child’s start time. Sysmon and Security 4688 record only the reported parent, so tools that show only it cannot see the spoof.

Under all of these sits one more layer: if the EDR agent itself is silenced (for example, by bring-your-own-vulnerable-driver tooling that kills it), the tree simply stops. A host that goes quiet in the middle of an incident is a finding, not a clean bill.

Check yourself

An EDR tree shows explorer.exe → rundll32.exe on a finance workstation, with rundll32.exe loading a DLL from %LOCALAPPDATA%\Temp. The EDR’s creator field for rundll32.exe names excel.exe, and Excel had a spreadsheet from an email open at the time. Parse it before you open the answer.

One way to answer

The reported parent (explorer.exe) disagrees with the creator the EDR recorded (excel.exe), which is the parent PID spoofing telltale: the real lineage is Excel spawning rundll32, an Office-spawns-a-LOLBin chain dressed up as a user double-click. The DLL path is a user-writable temp directory, so the loaded module is the payload to hash and pivot on. Next: how the spreadsheet’s macro got permission to run (Mark of the Web, Enable Content, container), the DLL’s creation event and its source, and the network activity of the rundll32 process by its unique process ID.

Key takeaway

Process relationship analysis bridges single-alert detection and full kill-chain reconstruction. Combined with command-line Parsing Breaking a raw alert, log line, or command string into its component fields so each can be examined on its own: the user, the host, the action, the time. In triage, parsing the alert is the first move; the details that decide a verdict live in the fields, not in the alert name. Alert parsing and log parsing are the same move applied to different inputs. , it is the foundation for confidently mapping what an adversary did and what they are trying to do next.

Next up

Network correlation

Tie host activity to network traffic, outbound and east-west. C2 detection through timing, TLS, DNS, and exfiltration indicators.

Read network correlation

Technical details verified . Product names, defaults and retention change; check your own tenant.

Edit this page on GitHub Report a correction