Ask a candidate how they prove a binary executed and you get a list. Prefetch, Amcache, ShimCache, 4688, Sysmon. Usually in that order, usually delivered at speed, and usually with ShimCache somewhere near the top.
Nothing on that list is wrong. What is missing is the next step. For each one, what wrote it, and what does that let you claim? That is what I am asking about.
There is one question underneath all of it. Who wrote the record, and how? The tiers below group the sources by that, and the point is not that one tier beats another. It is that when you put a confidence statement in a report, the mechanism is what you defend it with.
Technical assumptions
Windows 7 and later, and a working familiarity with the event log: channels, providers, event IDs. Where I name an event I name the channel with it, because the same ID under a different provider is a different record.
The question almost always comes up about a real estate, not a lab, so assume nothing was prepared. No agent, no tuned audit policy, nothing switched on that somebody had to think about first. That is the state most hosts are in when you reach them, and it is why one of the tiers below matters far more than the others.
One caveat before we start. PowerShell 7 does not write to the PowerShell 5.1 logs. Query only the classic provider on a host running pwsh and you will get a quiet answer that is wrong. I come back to it below.
Why the flat list fails
Two things get findings thrown out, and a list will not help you with either.
The first is overclaiming. You put a record in the report, somebody asks who wrote it, and the answer turns out to be any process running as a local admin. You had a lead and you cited it as proof.
The second is treating silence as clean. Maybe the channel was off. Maybe it was twenty megabytes and rolled last Tuesday. You write no evidence of execution and the client reads nothing ran. Say which one you mean, and say what you were missing.
Absence of evidence is a statement about your telemetry, not about the host. If the channel was not there, say so, name the retention window, and call it low-confidence-clean.
Four questions I ask of any source
Before the tiers, the four questions the tiers are built from.
Who wrote it
The kernel, the OS component that did the launching, a security control that checked the file first, or the application talking about itself. This is the one that decides how much confidence the record earns.
What it actually tells you
What is in the record. Full path, command line, hash, user SID, PID, parent process. A record that names a binary but not how it was invoked answers a smaller question.
Could it be faked
Could a user-mode process have written this. If yes, the record is a lead until something else agrees with it.
Was it even switched on
Is it on by default, does it need audit policy turned on, does it need an agent deployed, or is it live-only telemetry that exists solely if something was already capturing it. Availability decides your blind angles. A blind angle is not a no. It is a question you never got to ask.
Tier A: the kernel saw it happen
The kernel, or an agent sitting on kernel telemetry, watched the process get created. The record is made as the process starts, by something running underneath it.
| Log or provider | Event IDs | Available | What it contains | What it proves |
|---|---|---|---|---|
| Sysmon/Operational | 1, 5 | DEPLOY | Image, CommandLine, parent image and parent command line, hashes, user, integrity level, ProcessGuid | A process started, what launched it, and what it was. Pair 1 with 5 and you get how long it ran. |
| Security | 4688, 4689 | CONFIG | NewProcessName, PID, creator PID, token elevation type, user SID. Command line only if the policy is on | The same thing with less in it. Without that policy you get a path and nothing about the arguments. |
| Kernel-Process (ETW) | 1, 2, 5 | LIVE | ProcessID, ImageName, ParentProcessID, CreateTime, loaded image and base address | Nothing after the fact. It only exists if a trace session was already running, so you rarely have it. |
| EDR telemetry | vendor | DEPLOY | Process, command line, hashes, parent chain, signer, user, network activity | Sysmon quality with retention off the host. On a long dwell case it is often the only thing left. |
Two of those four need a word of warning. Kernel-Process ETW is native, nothing to install, but it does not persist anywhere, so after the fact it is almost never there. And EDR is as good as Sysmon but it lives in a vendor console with its own retention. Neither one is something you pull from the local event log.
Tier B: whatever did the launching wrote it down, and this is the goldmine
This is the tier I care most about, and the one that separates a good answer from a list.
These records are written by the OS component that actually did the launching. Not the kernel, but not the application talking about itself either. The service control manager knows it started a service. The task scheduler knows it fired an action. WMI knows it instantiated a consumer. These components have no reason to lie and no interface that lets an attacker rewrite their account of what they did.
And the part that matters operationally: they are on by default. No agent, no audit policy, no licence. On a host where nobody enabled anything, this tier is still there.
What lives here
| Log or provider | Event IDs | Available | What it contains | What it proves |
|---|---|---|---|---|
| System | 7045 | DEFAULT | ServiceName, ImagePath, ServiceType, StartType, AccountName | A service was installed. The PsExec and remote-service tell. Read the image path, it is often an interpreter with an encoded payload and not a binary. |
| Shell-Core | 9707, 9708 | DEFAULT | The full Run or RunOnce command line, then completion and PID | Something launched from a Run key, and whether it finished. Badly under-watched and it often survives. |
| TaskScheduler/Operational | 106, 129, 200, 201 | DEFAULT | TaskName, ActionName, InstancePID, user context, result code | Whether persistence was registered, armed, or actually fired. 129 and 200 are the ones that mean it ran. |
| WMI-Activity/Operational | 5857 to 5861 | DEFAULT | ClientProcessId, user, query text. 5861 carries the consumer CommandLineTemplate or ScriptText | WMI subscription persistence, and it is the only native record of it. |
| BITS-Client/Operational | 3, 59, 60 | DEFAULT | JobId, JobTitle, Owner, RemoteName (the URL), LocalName, NotifyCmdLine | A download, and a notify command line that runs out of svchost with no service and no task behind it. |
PowerShell, and the thing people get wrong
Two different questions, two different logs. And version 7 hides from anyone who only looks at version 5.
| Log or provider | Event IDs | Available | What it contains | What it proves |
|---|---|---|---|---|
| Windows PowerShell (5.1) | 400, 403 | DEFAULT | HostApplication with the full invocation including -EncodedCommand, HostName, EngineVersion, RunspaceId | PowerShell ran and how it was launched. Nothing typed inside the session. EngineVersion 2.0 on a modern box is a downgrade attack. |
| PowerShell/Operational (5.1) | 4104 | CONFIG | ScriptBlockText, already deobfuscated, ScriptBlockId, Path | What the script actually did, however it was launched. Suspicious blocks still log at Warning when the policy is off. |
| Module logging | 800, 4103 | CONFIG | CommandLine, CommandInvocation, ParameterBinding, UserId | Pipeline detail, but only for the modules where it was switched on, so partial by design. |
| PowerShellCore/Operational (7.x) | 4104, 40961, 40962 | DEPLOY | Same fields, different provider | PowerShell 7. Separate product, separate log. Query only the 5.1 provider and pwsh activity is invisible. |
Tier C: a control checked the file first
An application control product inspected the image before it was allowed to run. That gives you the most complete detail you will find anywhere in the event log: full path, hash, publisher, the rule that matched, the user.
| Log or provider | Event IDs | Available | What it contains | What it proves |
|---|---|---|---|---|
| AppLocker, EXE and DLL | 8002, 8003, 8004 | DEPLOY | FullFilePath, FileHash, publisher, RuleName, PolicyName, TargetUser SID | Allowed, audited or blocked. In audit mode 8002 is a complete list of everything that ran. |
| AppLocker, MSI and script | 8005, 8006, 8007 | DEPLOY | Same fields, for msi, ps1, vbs, js, cmd and bat | Script and installer execution, which the exe rules never see. |
| CodeIntegrity/Operational | 3076, 3077, 3089 | DEPLOY | File name, process name, signing level, policy name. 3089 adds publisher, issuer and hash | WDAC. 3076 is an audit block, 3077 an enforced one. Tells you exactly what tried to run. |
| Application (legacy SRP) | 865 to 868 | DEPLOY | Blocked file path, user, enforcement policy | Software Restriction Policy. Still turns up on older estates. |
The standing recommendation I make on almost every engagement lives here: run AppLocker or WDAC in audit mode. You get 8002 as a full record of what ran, and none of the risk of blocking something that matters.
What is not in this tier: antivirus and ASR blocks. A 1121 means the file did not run. The path is an 8.3 short name, and the process named in the event is the initiator rather than the target. Corroboration only.
Tier D: the application talking about itself
All Application-channel providers, all on by default. The thing to understand is how they are made: the provider name in a classic Application event is self-declared, so it is not tied to whatever actually wrote the record. That is what limits the claim you can build on one.
| Log or provider | Event IDs | Available | What it contains | What it proves |
|---|---|---|---|---|
| Application Error | 1000 | DEFAULT | App name and full path, version, faulting module, exception code, PID, app start time | The binary was running, because it crashed. The start time is a bonus you rarely get elsewhere. |
| Windows Error Reporting | 1001 | DEFAULT | Fault bucket, event name, app path and version | Same thing, and it correlates to the .wer files sitting on disk. |
| ESENT | 216, 325 to 327 | DEFAULT | Calling process and PID, database name and path. 325 means a new database was created | Who touched an ESE database. A copy of ntds.dit at an odd path announces itself here. |
| MsiInstaller | 1033, 11707, 11708 | DEFAULT | Product name, version, manufacturer, install result | An MSI package installed (11707) or failed (11708). |
| .NET Runtime | 1000 | DEFAULT | Free text. No schema at all | Nothing on its own. Any application can write anything here under that provider name. |
The poisoning trap. That last row is the one to watch. The .NET Runtime provider is an arbitrary passthrough, and I have seen legitimate tooling drop full command lines into it. Convenient, right up until you remember the same door is open to everyone. And eventcreate.exe ships with Windows and will forge any of these on request.
So: Tier D never stands alone. Corroborate it, and promote it with the tier below.
Tier E: everything outside the event log
One thing to get straight before the table, because the letter misleads. E is not the bottom of anything. Prefetch and Amcache answer the did-it-run question as well as anything in Tier A or B, and I would rather have Prefetch than a 4688 with no command line.
What puts them in their own group is that they are not event log records at all. Different subsystems write them for their own reasons, which is why they survive log clearing, and why what each one proves has to be argued per artifact. So the third column here is what creates the record. They are all on by default.
| Artifact | Where it lives | What creates it | What it contains | What it proves |
|---|---|---|---|---|
| Prefetch | %SystemRoot%\Prefetch | The prefetcher, on run | Executable name and hash, run count, last eight run times, volume, referenced files and DLLs | It ran, how often, and the last eight times. Nothing else gives you repetition. |
| Amcache | Amcache.hve | Compatibility subsystem | Full path, SHA-1, first execution time, PE and publisher metadata | The binary existed and ran, with a hash, even when the file is long gone. |
| SRUM | SRUDB.dat | The SRUM service | Application id and path, bytes sent and received, foreground time, user SID | How much data an application moved. This is the artifact for the exfiltration question. |
| BAM / DAM | Registry, per user SID | Background Activity Moderator | Path, last run time, user SID | Execution tied to one specific user. |
| PCA | PcaAppLaunchDic.txt | Program Compatibility Assistant | Path, UTC timestamp, exit code. Also logs shares and USB | Launch and exit on Windows 11. |
| ShimCache | Registry, AppCompatCache | Shim engine, on enumeration | Path, size, last modified. An exec flag only before Windows 8 | That the file was seen. NOT that it ran. Pair it with Amcache or Prefetch before you claim a run. |
Below those sit the per-user traces, UserAssist, RecentApps, Jump Lists and MUICache, which are what you want when the question is whether a human double-clicked something or a service started it. Plus MPLog and the file system journals for binaries that have since been deleted.
The special case: DCOM, where there is no event at all
I include this one because it is where a list gets you nowhere at all. There is no native record that says “DCOM launched process X.” Activation and process creation are decoupled, so you reconstruct it from three things and you learn the formula, not an event ID.
Take your process creation record, Sysmon 1 or 4688. Look for the tell, which is a command line ending in -Embedding, and a parent of svchost.exe -k DcomLaunch, or a surrogate in the form dllhost.exe /Processid:{CLSID}. Then find the remote source in Security 4624 type 3.
The CLSID tells you which server process to expect. MMC20.Application gives you mmc.exe. ShellWindows and ShellBrowserWindow give you Explorer, or a surrogate host.
And the trap, which is the whole reason this needs saying out loud: the spawned process has a local parent, the DCOM launcher running as SYSTEM. The attacker is nowhere in the process tree. The only place the source address exists is the network logon, and if you did not collect 4624 you have a process with no origin and no way to get one afterwards. The DistributedCOM events in the System log do not rescue you either. They fire on failure, and 10016 in particular is by-design noise that has sent more people down more dead ends than almost anything else in that channel.
The traps, said out loud before you commit
Every claim in a report has to survive somebody reading it who wants it to be wrong. Each of these has ended a finding on cross-examination.
Self-declared providers
Classic Application events carry a provider name the writer chose. Treat the name as a claim, nothing more.
ASR and antivirus are not execution
A block means it did not run. The short-name path and the initiator-versus-target confusion make it worse than useless if you read it quickly.
ShimCache is not execution
Worth repeating in its own section because it is the single most common overclaim I see.
Application log rotation
Roughly twenty megabytes, circular. A noisy application can roll it in hours. Before you conclude anything from silence in that channel, check the record ID continuity and the oldest record present, and quote the window you actually had.
Attempt is not success
Service failure events and DCOM failure events prove somebody tried. They do not prove anything completed. The sentence you write has to match which of those you have.
Absence is not clean
Where nothing was collecting, the honest finding is low-confidence-clean with the blind angle stated. It reads weaker than a clean bill of health, and it is the only version that will survive somebody checking.
The order I actually pull in
For a compromise assessment, where the question is long dwell and not a live alert, the order follows availability instead of tier. Default-on first, because it is the material that will actually be there.
Tier E first: Prefetch, Amcache, SRUM, BAM, PCA. Long lookback and it survives clearing. Then PowerShell, the invocation line and the script blocks, from both the 5.1 and 7 providers. Then the default-on subsystem channels in order of how often they carry the answer: service installs, Run and RunOnce, the task scheduler, WMI subscriptions, BITS. Then the Application channel providers, checking retention before trusting the silence. Then application control if it is deployed, which is the most detailed material on the box. And Security last, not because it is weak, it is Tier A, but because it is audit-policy dependent and on an unprepared estate it is frequently the emptiest thing you will open.
Kernel ETW and EDR sit outside that order entirely. One is live-only, the other is in somebody else's console.
What a good answer sounds like
If I ask this in an interview, I am not counting artifacts. I am listening for five things.
That you can say who wrote a given record and how, and what that lets you claim from it. That you know which sources are on by default, because that is the difference between a method and a wish list. That Tier D is a lead, not proof. That DCOM has no single event and you can describe the reconstruction. And that you will not let “no evidence” be read as “clean” without naming what was missing.
The event IDs are lookup. Those five are the ones I cannot teach you in an hour, so they are the ones I ask about.
References
- Process auditing Include command line in process creation events, the policy setting that makes 4688 worth collecting learn.microsoft.com/windows/security/threat-protection/auditing/event-4688
- Process telemetry Sysmon event 1, process creation, and the fields it records learn.microsoft.com/sysinternals/downloads/sysmon
- PowerShell About logging: module logging, script block logging and transcription, and where each writes learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_logging_windows
- Application control AppLocker event IDs, including 8002 as an allow-list execution record in audit mode learn.microsoft.com/windows/security/application-security/application-control/app-control-for-business/applocker/using-event-viewer-with-applocker
- Application control App Control for Business, CodeIntegrity operational events 3076, 3077 and 3089 learn.microsoft.com/windows/security/application-security/application-control/app-control-for-business/operations/event-id-explanations
- Lateral movement MITRE ATT&CK T1021.003, Remote Services: Distributed Component Object Model attack.mitre.org/techniques/T1021/003/
- Companion piece What file timestamps mean, and how to catch tampering /field-notes/what-file-timestamps-mean/