Security Notes
Detection Engineering

Known-Good Processes — Baselines for Windows, Linux & macOS

You can't spot evil if you don't know what good looks like. This is the "know normal, find evil" reference — the legitimate core processes on each OS, their expected parent, path, user, and count, and the red flags that mean something is impersonating or abusing them. Use it during enumeration, triage, and threat hunting.

12 min read 6 sections 6 model answers verified 2026-06

Last verified2026-06 See also: Endpoint Detection · Digital Forensics · Windows Registry


The Core Principle

Malware constantly masquerades as legitimate system processes (MITRE T1036) — naming itself svchost.exe, hiding in [kworker], or pretending to be mdworker. Signature-based detection misses novel malware, but anomaly-against-baseline catches the masquerade, because the impostor almost always gets one of these wrong:

   ┌─ Is it the RIGHT NAME?       (svchost.exe vs scvhost.exe / svhost.exe — typosquats)
   ├─ in the RIGHT PATH?          (C:\Windows\System32\svchost.exe — not %TEMP%\svchost.exe)
   ├─ with the RIGHT PARENT?      (svchost's parent must be services.exe — not winword.exe)
   ├─ as the RIGHT USER?          (lsass runs as SYSTEM — not as 'bob')
   ├─ the RIGHT COUNT?            (exactly ONE lsass.exe — not three)
   └─ doing the RIGHT THING?      (lsass should have NO children; explorer shouldn't beacon)
Memory hook

"right name, path, parent, user, count, behavior." Impersonation is hard to get perfect. A malicious svchost.exe might nail the name but run from the wrong folder, lack the -k flag, or be spawned by Word instead of services.exe. Detection is just checking those six attributes against the known baseline — get fluent in the baseline and the anomalies jump out. This is the entire premise of the SANS Hunt Evil process-tree approach.


Windows — Core Processes & The Boot Tree

Windows has a rigid, predictable process tree at boot. Memorizing it is the single highest-value Windows detection skill.

System Idle Process (PID 0)
└─ System (PID 4)                         kernel; no real parent, no disk image
   └─ smss.exe                            Session Manager — System32, parent=System(4)
      ├─ csrss.exe                        one per session (usually 2); parent (smss) EXITS
      ├─ wininit.exe   (session 0)        parent (smss) exits
      │  ├─ services.exe                  the service control manager
      │  │  ├─ svchost.exe  (many)        ALWAYS launched with  -k <group>
      │  │  ├─ spoolsv.exe                print spooler
      │  │  └─ (other service hosts)
      │  ├─ lsass.exe                      ★ ONE instance, NO children, SYSTEM
      │  └─ lsm.exe / fontdrvhost.exe
      └─ winlogon.exe  (session 1)         handles interactive logon
         └─ userinit.exe                   launches the shell, then EXITS
            └─ explorer.exe                ★ runs as the USER, from C:\Windows\ (not System32)
               └─ (user apps: browsers, Office, etc.)
ProcessExpected pathExpected parentRuns asNormal countRed flags
System(none — kernel)— (PID 0)SYSTEM1 (PID 4)A "System" not at PID 4; an image path
smss.exeSystem32System (4)SYSTEM1 masterWrong path; wrong parent; multiple persistent
csrss.exeSystem32smss (exited)SYSTEM1 per session (~2)Misspelled (csrsss); from %TEMP%; has odd children
wininit.exeSystem32smss (exited)SYSTEM1 (session 0)More than one; wrong path
services.exeSystem32wininitSYSTEM1Not parented by wininit; wrong path
lsass.exeSystem32wininitSYSTEM1Multiple; ANY child process; not from wininit; wrong path; misspelled (lsas/lsass1) — classic credential-dump masquerade
svchost.exeSystem32services.exeSYSTEM / NETWORK / LOCAL SERVICEmanyNo -k flag; parent NOT services.exe; wrong path; running as a normal user
winlogon.exeSystem32smss (exited)SYSTEM1 per interactive sessionWrong path; spawning cmd/powershell
explorer.exeC:\Windows\userinit (exited)the logged-on user1 per logged-on userIn System32 or %TEMP%; running as SYSTEM; making network beacons
taskhostw.exeSystem32svchostuser/SYSTEMvariesWrong parent/path
Memory hook

the four facts that catch most Windows masquerade:

lsass.exe is a lone wolf

exactly one, parented by wininit, and it spawns no children. lsass.exe → cmd.exe or two lsass.exe = credential theft / masquerade. (And watch for lsasss.exe, lsas.exe.)

svchost.exe always has -k

and its parent is always services.exe. A svchost with no -k, or spawned by anything else, is malware wearing a costume.

explorer.exe runs as the user, from C:\Windows\

not System32, not as SYSTEM.

Most Win32 processes live in System32

a system-named process running from %TEMP%, %APPDATA%, C:\Users\Public, or a user profile is the loudest signal there is.

Also classic-suspicious regardless of nameOffice apps (winword.exe, excel.exe) or w3wp.exe/mssql spawning cmd.exe/powershell.exe/wscript.exe (macro/webshell), and powershell.exe -enc <base64> or -nop -w hidden.

:: Quick Windows triage — verify the six attributes
tasklist /v                                   :: processes + user
wmic process get Name,ProcessId,ParentProcessId,ExecutablePath,CommandLine
:: PowerShell — show parent + path together
Get-CimInstance Win32_Process | Select Name,ProcessId,ParentProcessId,Path,CommandLine
Get-Process lsass | Select-Object Path        :: should be C:\Windows\System32\lsass.exe, count = 1
:: Sysinternals — the go-to, verifies signatures + shows the tree
:: procexp.exe (Process Explorer) ; pslist ; autorunsc -s

Linux — Core Processes & Kernel Threads

Linux is more varied (distro/role-dependent), but the skeleton is consistent.

PID 1   systemd  (or init on older systems)   ← ancestor of all userland; reaps orphans
PID 2   kthreadd                              ← parent of ALL kernel threads
        └─ [kworker/*], [ksoftirqd/*], [migration/*], [rcu_sched], [kswapd0] ...
           kernel threads: shown in [brackets], PPID = 2, NO on-disk binary
ProcessWhat it isNotes / where it lives
systemd (PID 1)init + service managerParent of daemons; /usr/lib/systemd/systemd
kthreadd (PID 2)kernel thread spawnerParent of every [bracketed] kernel thread
[kworker], [ksoftirqd], [migration], [rcu_*], [kswapd0]kernel threadsIn [brackets], PPID 2, no /proc/PID/exe target
systemd-journald / -logind / -udevd / -resolvedsystemd subsystems/usr/lib/systemd/
sshdSSH daemonparent systemd; spawns a child per login session
cron / crondscheduled jobsa classic persistence + privesc spot
dbus-daemon, polkitd, NetworkManager, rsyslogd, chronyd, agettystandard daemonsparent systemd
Memory hook

"kernel threads wear [brackets], have PPID 2, and have no file on disk." The favorite Linux masquerade is a malicious process named like a kernel thread — [kworker/0:2] — to blend into ps. Three tells expose it: (1) a real kernel thread's parent is kthreadd (PID 2) — a fake one isn't; (2) a kernel thread has no executable — ls -l /proc/<pid>/exe is empty/errors, whereas the fake points at a real (often deleted or /tmp) binary; (3) kernel threads use no user memory (RSS ~0). So: bracketed name + non-kthreadd parent + a real exe = malware in a costume.

Linux red flags regardless of name

  • Execution from /tmp, /dev/shm, /var/tmp, /run — ls -l /proc/<pid>/exe
  • Deleted binary still running — /proc/<pid>/exe → ...(deleted) (dropped, then unlinked to hide)
  • A process with a space/odd char appended to look benign (sshd with trailing space), high-entropy names, or base64 in the cmdline
  • Listeners on odd ports / outbound to mining pools (ss -tunap)
bash
# Quick Linux triage
ps auxf                                   # full process TREE — see parent/child at a glance
ss -tunap                                 # listening + established sockets → owning process
ls -l /proc/<pid>/exe                     # real path; "(deleted)" or /tmp = suspicious
ls -l /proc/<pid>/cwd                     # working dir
cat /proc/<pid>/cmdline | tr '\0' ' '     # full command line
# Hunt processes running from temp dirs:
ls -l /proc/*/exe 2>/dev/null | grep -E '/tmp|/dev/shm|/var/tmp|\(deleted\)'

macOS — Core Processes

Everything descends from launchd (PID 1) — macOS's combined init and service manager.

PID 0   kernel_task                         ← the kernel
PID 1   launchd                             ← init + launchd service manager; ancestor of ALL
        ├─ LaunchDaemons (system services, root)
        └─ per-user launchd → LaunchAgents (user GUI/login services)
ProcessWhat it isNotes
kernel_task (PID 0)the kernelAlso manages thermals
launchd (PID 1)init + service managerParent of essentially everything; legit persistence = LaunchAgents/Daemons
WindowServerthe GUI/display serverruns as _windowserver
loginwindowlogin session manager
mds / mds_stores / mdworkerSpotlight indexinghigh disk/CPU here is normal indexing — and a common masquerade target
cfprefsdpreferences daemon
securityd / trustdsecurity & cert trust
configd, coreaudiod, bluetoothd, distnoted, UserEventAgentcore daemonsparent launchd
Finder, Dock, SystemUIServeruser GUI shellrun as the user
Memory hook

on macOS, "everything's parent is launchd (PID 1), and persistence = LaunchAgents/Daemons." Unlike Windows' rigid tree, macOS is flat under launchd, so the tells shift to code signature + path + plist. The common masquerade is naming malware after a Spotlight worker like mdworker or mds while running it from /tmp, /Users/Shared, or a hidden dir instead of /System/Library/.... Three checks: (1) is the binary code-signed and notarized (codesign -dv --verbose, spctl -a)? — system daemons are signed by Apple; (2) is it in the expected system path or somewhere user-writable? (3) what LaunchAgent/LaunchDaemon plist launched it (~/Library/LaunchAgents, /Library/LaunchDaemons), and is that plist legit? (See macOS hardening.)

bash
# Quick macOS triage
ps auxww                                  # all processes + args
ps -axo pid,ppid,user,comm                # parent/child + user
codesign -dv --verbose=4 /path/to/binary  # signing identity (Apple? unsigned? ad-hoc?)
spctl --assess --verbose /path/to/app     # Gatekeeper assessment
launchctl list                            # loaded launchd jobs
ls -la ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons   # persistence
lsof -i -nP                               # network connections → process

Cross-Platform Triage Checklist

For any suspicious process, ask the six baseline questions:
[ ] NAME    — exact spelling? (svchost vs scvhost, mdworker vs mdworkers)
[ ] PATH    — expected system dir, or %TEMP%/AppData/Public / /tmp / /dev/shm / /Users/Shared?
[ ] PARENT  — does the parent make sense? (svchost←services, lsass←wininit, all←launchd/PID1/2)
[ ] USER    — right account? (lsass=SYSTEM, explorer=user, kernel thread=root w/ no exe)
[ ] COUNT   — expected number? (exactly ONE lsass / wininit / services)
[ ] BEHAVIOR— right children & network? (lsass has NO kids; Office shouldn't spawn powershell)
PLUS:
[ ] Is the binary SIGNED/notarized? (Authenticode on Windows, codesign on macOS, pkg on Linux)
[ ] Is the on-disk file present, or DELETED-but-running? (/proc/pid/exe → (deleted))
[ ] What's it connected to? (ss/netstat/lsof → unexpected egress, beaconing, mining pools)
Memory hook

the process tree beats the process list. A flat list of process names hides the masquerade; the parent-child relationship exposes it. lsass.exe looks fine in a list — but lsass.exe spawned by cmd.exe, or spawning cmd.exe, is damning. Always pull the tree (ps auxf, Process Explorer, pstree), because the relationship is the evidence — which is the same reason endpoint detection is built on process lineage.


Interview Questions

Q
Why is knowing legitimate processes important for detection?
Model answer

Because malware routinely masquerades as legitimate system processes — naming itself svchost.exe, hiding as a bracketed kernel thread, or impersonating a Spotlight worker — and signature detection misses novel samples. What it can't easily fake is the full context: the right name, in the right path, with the right parent, as the right user, in the right count, behaving correctly. So detection becomes anomaly-against-baseline: a process called svchost.exe running from %TEMP%, lacking the -k flag, or parented by Word instead of services.exe is obviously wrong even if I've never seen that specific malware. You can't spot the impostor without knowing what the real one looks like, which is why "know normal, find evil" is the foundation of triage and hunting.

Q
What's suspicious about a second lsass.exe, or lsass.exe with a child process?
Model answer

On a healthy Windows host there is exactly one lsass.exe, it lives in System32, it's parented by wininit.exe, it runs as SYSTEM, and critically it spawns no child processes. lsass holds credential material in memory, so it's a prime target. Multiple lsass processes usually means something is masquerading as it — often a credential dumper or malware using the trusted name. lsass spawning a child like cmd.exe or rundll32 is a strong sign of code execution within or injection into lsass, again typically credential theft. And a near-miss spelling like lsas.exe or lsass1.exe, or an lsass running from a non-System32 path, is the same masquerade. Any of these is high-severity because they cluster around credential access.

Q
How do you spot malware hiding as a Linux kernel thread?
Model answer

Real kernel threads have three signatures: their name appears in square brackets in ps like [kworker/0:1], their parent is kthreadd at PID 2, and they have no on-disk executable and essentially no user memory because they live in kernel space. Malware sometimes names itself like a kernel thread to blend into ps output. I expose it by checking those invariants: is its parent actually PID 2, and does /proc//exe point to a real binary? A bracketed name whose parent isn't kthreadd, or that has a real executable — often in /tmp or marked (deleted) — and nonzero resident memory is malware wearing a costume. So the tell is a kernel-thread name with a userland reality.

Q
A process named svchost.exe is running. What do you check to decide if it's legitimate?
Model answer

I verify the six baseline attributes. The path must be C:\Windows\System32\svchost.exe — not a user-writable folder. Its parent must be services.exe; svchost spawned by Office, a browser, or PowerShell is malware. Its command line should include the -k flag naming a service group — legitimate svchost is always launched with -k, so a bare svchost.exe with no -k is a red flag. It should run as SYSTEM, NETWORK SERVICE, or LOCAL SERVICE, not a regular user. The name spelling must be exact, since scvhost or svhost are typosquats. And I'd check its children and network connections for anything out of character, and verify the Authenticode signature. Process Explorer shows the parent, path, command line, and signature together, which makes this a quick check.

Q
How does macOS process triage differ from Windows?
Model answer

Windows has a rigid boot tree, so a lot of detection is verifying the expected parent-child relationships — lsass under wininit, svchost under services. macOS is much flatter: essentially everything descends from launchd at PID 1, so parent-child lineage tells you less. Instead the tells shift to code signature, path, and the launch configuration. System daemons are code-signed and notarized by Apple and live under /System/Library, so I lean on codesign and spctl to check whether a binary is properly signed or unsigned/ad-hoc, and on whether it's running from a user-writable location like /tmp or /Users/Shared. And because persistence on macOS is via LaunchAgents and LaunchDaemons plists, I inspect those plists and launchctl to see what launched a suspicious process. The common masquerade is naming malware after a Spotlight worker like mdworker but running it unsigned from the wrong path.

Q
Why is the process tree more useful than the process list in triage?
Model answer

Because the masquerade hides in a flat list but is exposed by relationships. A process called lsass.exe or svchost.exe looks perfectly normal in a list of names — the malicious context only appears when you see who its parent is and what children it spawned. lsass.exe is fine until you see it was launched by cmd.exe, or that it launched powershell; svchost is fine until you see its parent is winword.exe. The parent-child edge is the actual evidence, which is exactly why endpoint detection is built on process lineage and why I always pull the tree with ps auxf, pstree, or Process Explorer rather than reading a name list. The relationship turns an innocent-looking name into a smoking gun.