yuzu

execution_artifacts

What it doesWindows execution-evidence sources: ShimCache, Amcache InventoryApplicationFile, and Prefetch. Forensics-gated, single-target, default-off
Version1.0.0
KindCollector · read-only · gathered (windows.execution_artifacts.shimcache, windows.execution_artifacts.amcache, windows.execution_artifacts.prefetch)
PlatformsWindows ✅ · macOS ⛔ unsupported · Linux ⛔ unsupported
Actionsamcache (definition windows.execution_artifacts.amcache) · prefetch (definition windows.execution_artifacts.prefetch) · shimcache (definition windows.execution_artifacts.shimcache)
Securitysecurable Forensics · operation Read · risk High · dispatch ReadOnly · approval gate AdminOrApproval
Rolesexecute: admin · author: content-author

How it works

Three independent, read-only actions read Windows execution-evidence sources on one named device; a failure in one never affects the others. shimcache reads the AppCompatCache value under HKLM\SYSTEM\CurrentControlSet\Control\Session Manager (up to 16 MiB) and decodes the Windows 10/11 layout into one row per cached executable path with its cached last-modified time and size. amcache copies C:\Windows\appcompat\Programs\Amcache.hve (and its .LOG1 / .LOG2 sidecars when present) into a private scratch directory, loads the copy as a private read-only registry hive, and turns every Root\InventoryApplicationFile entry into a row of path, SHA-1, size, link date, publisher, binary type and product identity. prefetch lists C:\Windows\Prefetch\*.pf, decompresses each file with the built-in Windows decompressor, and parses it into executable name, hash, run count, up to eight last-run timestamps and volume and file-reference counts.

Every source is bounded (file counts, byte totals, subkey counts) and a source that cannot be read completely says so with a named reason instead of returning an empty success. Only paths, hashes and timestamps are read; file contents are never read or emitted. The plugin starts no process and makes no network call. Each action is authorised at Forensics:Read with an administrator-or-approval gate, accepts one explicit target only, and stays refused until an operator enables the plugin’s server-side kill switch.

flowchart LR
  OP["Operator or workflow"] --> SRV["Server: authz Forensics, Read; single target; kill switch on"]
  SRV -->|"gRPC mTLS"| EX["Agent: execution_artifacts"]
  EX --> SC["shimcache: read AppCompatCache value"]
  EX --> AC["amcache: copy hive then load private copy"]
  EX --> PF["prefetch: read and decompress .pf files"]
  SC --> ROWS["rows and typed result status"]
  AC --> ROWS
  PF --> ROWS
  ROWS --> RS[("ResponseStore")]
  RS --> API["REST /api/responses"]

What you can decide with it

All three actions answer one question on one Windows device: what executables does Windows have a record of, and where did that record come from. They do not answer it on macOS or Linux, where each action returns a single unsupported row with provenance windows_only_artefact.

SourceWhat a row meansWhat it does not proveReading an empty or partial result
shimcacheWindows cached this executable path with its file last-modified time and size. insert_flag is always -: the Windows 10/11 layout has no execution-confirmation bit.That the file ever ran, or when. The timestamp is a file time, not a run time.Zero rows is reported as constrained (shimcache_empty), never as success. Older Windows layouts report unknown_version.
amcacheWindows’ application-compatibility inventory recorded this file, with its SHA-1 and product identity.That the file ran. Some entries legitimately carry only a SHA-1 and blank fields.A copy, load or enumeration failure reports constrained with a named reason.
prefetchA prefetch file exists for this executable, with a run count and up to eight last-run times. This is the most direct of the three for “it ran, how often, when”.Anything about the executable when prefetching is off or the files were deleted.No files is classified: prefetch_disabled (prefetching configured off), prefetch_evidence_absent (configured on, no files: consistent with removal, not proof of it) or prefetch_state_unknown.

Use prefetch for “did it run and when”, amcache for “which binary (by SHA-1) was present, and shimcache for the executable paths Windows cached. Agreement across sources raises confidence; presence in one source alone is a lead, not a finding. A clean result is never “nothing ran”: it means the source held no entries or could not show them, and the status tells you which.

Diagrams

Amcache acquisition

sequenceDiagram
  participant A as Agent
  participant D as Scratch directory
  participant L as Offline hive lock
  participant H as Amcache.hve
  participant R as Registry
  A->>H: stat source (256 MiB cap)
  A->>D: create random per-dispatch directory under data_dir
  A->>D: open handle, verify owner
  A->>L: acquire lock (held to the end of the read)
  A->>H: CopyFileW, backup-semantics fallback on sharing violation
  A->>H: copy LOG1 and LOG2 if present
  A->>R: RegLoadAppKeyW on the private copy
  R-->>A: Root InventoryApplicationFile subkeys (up to 20000)
  A->>R: close keys
  A->>L: release lock
  A->>D: remove directory

The registry never loads the live hive; only a private copy in a fresh, random-named directory is loaded. One process-wide lock serialises everything that loads an offline hive, so the copy, load, enumeration and close happen under a single hold. The scratch directory is removed on every exit path, and a sweep at agent start and before each amcache dispatch reclaims directories a crashed run left behind.

Why prefetch can be empty

flowchart TD
  S["List .pf files in the Windows Prefetch directory"] --> Q{"Any file found"}
  Q -->|"yes"| P["Parse each file: row, or prefetch_error row"]
  Q -->|"no"| E{"EnablePrefetcher value"}
  E -->|"0"| D["prefetch_disabled"]
  E -->|"1, 2 or 3"| X["prefetch_evidence_absent"]
  E -->|"unreadable or other"| U["prefetch_state_unknown"]

An empty prefetch directory is not one answer. Prefetching configured off explains it; configured on with no files is consistent with files having been removed afterward, but the SysMain service state is not consulted, so it is a lead rather than proof; and an unreadable setting stays unknown. A failed registry read never blocks the action.

OS capability

ActionWindowsmacOSLinux
amcache🟡 constrained · rung 1 · copy Amcache.hve(+.LOG1/.LOG2) then RegLoadAppKeyW; whole sequence serialised by offline_hive_mutex⛔ unsupported⛔ unsupported
prefetch✅ supported · rung 1 · CreateFileW read + ntdll RtlGetCompressionWorkSpaceSize/RtlDecompressBufferEx(COMPRESSION_FORMAT_XPRESS_HUFF)⛔ unsupported⛔ unsupported
shimcache✅ supported · rung 1 · RegQueryValueExW HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache (local bounded reader, 16 MiB)⛔ unsupported⛔ unsupported

Declared limits per leg (descriptor fallback text, verbatim):

Privileges and prerequisites

OSRuns asExtra grant neededMeasuredIf the read is refused
Windowsagent service account (LocalSystem today, docs/agent-privilege-model.md)None known. shimcache is a bounded HKLM value read and prefetch a directory listing plus per-file reads under C:\Windows\Prefetch. amcache loads its private copy with RegLoadAppKeyW, which did not need SeBackupPrivilege; a backup-semantics copy is attempted only when the plain copy hits a sharing violation, and takes no privilege beyond what the service account can already request.Probed in an administrator session and as LocalSystem on one workstation: the plain copy always succeeded and the private load succeeded with the privilege disabled. Not measured under a least-privilege service account, and the backup-semantics fallback has never been exercised on real hardware.constrained with a named reason (reg_<code>, hive_locked, regload_<code>, subkey_open_failed, and so on). The tokens do not separate “access denied” from “not found” or “vanished mid-walk”: a refused open and a missing key report through the same per-source token family.
macOSn/a - the plugin loads but reads nothingn/an/a - no macOS mechanism existsEvery action returns unsupported with provenance windows_only_artefact and rc 1
Linuxn/a - the plugin loads but reads nothingn/an/a - no Linux mechanism existsEvery action returns unsupported with provenance windows_only_artefact and rc 1

No external binaries, no subprocesses and no network access: every call is an in-process Win32 registry or file call, or an in-process ntdll decompression call. The plugin performs no authorization of its own. Forensics:Read, the administrator-or-approval gate and single-target enforcement live at the server dispatch layer, and the server-side plugin-config kill switch (PluginConfigStore::seed_kill_switch_default_off) keeps every action refused until an operator enables it.

Data contract

Inputs

No action takes parameters.

Outputs

Pipe-delimited rows, one discriminator-prefixed row per artefact entry (shimcache|..., amcache|..., prefetch|...); every untrusted string field is escaped through safe_output_field. A source that fails outright emits no data row, only constrained|<token>, and sets the matching typed status. shimcache is all or nothing: any decode failure in the blob is that single constrained row. amcache and prefetch read entry by entry. prefetch emits one prefetch_error|<file>|<reason> row per skipped file and, when a cap or an enumeration fault truncated the walk, a closing constrained|<reason> row. amcache folds per-entry failures into the typed status only (see Caveats). amcache adds note|malformed_fileid_count=<n> when a FileId could not be normalised to a 40-hex SHA-1 and note|temp_cleanup_failed when its scratch directory could not be removed; note| lines are diagnostics, not data, and a consumer of amcache| rows skips any line without that prefix. shimcache’s insert_flag is always -; every other field is the decoded value, or - when that field could not be read.

windows.execution_artifacts.amcache — lower_case_long_path|sha1|size|link_date|publisher|binary_type|product_name|product_version

FieldTypeValuesAvailableExampleDescription
lower_case_long_pathstring-Windowsc:/program files/app/app.exeLower-cased full executable path from the InventoryApplicationFile subkey, escaped.
sha1string-Windowsda39a3ee5e6b4b0d3255bfef95601890afd80709Normalised 40-hex-character SHA-1 from the subkey’s FileId; ”-” when absent or malformed.
sizestring-Windows2048576File size as recorded by Amcache (raw string form, not re-parsed).
link_datestring-Windows01/02/2026 03:04:05Linker timestamp as recorded by Amcache.
publisherstring-WindowsExample CorpPublisher string as recorded by Amcache, escaped.
binary_typestring-Windowspe32_amd64Binary type as recorded by Amcache.
product_namestring-WindowsExample AppProduct name as recorded by Amcache, escaped.
product_versionstring-Windows1.2.3.4Product version as recorded by Amcache.

windows.execution_artifacts.prefetch — exe_name|hash_hex|version|run_count|last_runs_epoch_ms|volume_count|file_ref_count

FieldTypeValuesAvailableExampleDescription
exe_namestring-WindowsNOTEPAD.EXEExecutable name recorded in the Prefetch file’s header, escaped.
hash_hexstring-WindowsDDFD0A8D8-uppercase-hex-digit Prefetch hash from the filename/header.
versionint32-Windows31Prefetch format version; only 23, 26, 30 and 31 decode — see Caveats.
run_countint64-Windows42Recorded run count.
last_runs_epoch_msstring-Windows1690000000000,1689999999000Comma-separated last-run timestamps (up to 8 on versions 26/30/31, 1 on version 23), epoch milliseconds.
volume_countint64-Windows1Number of volume entries in the file-information block.
file_ref_countint64-Windows12Total number of NTFS file references, summed across every declared volume entry in the file-information block (not just the first).

windows.execution_artifacts.shimcache — path|last_modified_epoch_ms|data_size|insert_flag

FieldTypeValuesAvailableExampleDescription
pathstring-WindowsC:/Windows/System32/notepad.exeExecutable path recorded in the AppCompatCache entry, escaped.
last_modified_epoch_msint64-Windows1690000000000Cached last-modified timestamp from the entry, epoch milliseconds.
data_sizeint64-Windows175616Cached file size in bytes, from the entry.
insert_flagstring-Windows-Always ”-”: the Windows 10/11 AppCompatCache layout this plugin decodes carries no execution-confirmation bit.

Result status

StatusCompletenessProvenanceWhen
OKfull(empty)shimcache: the AppCompatCache value opened, read within the 16 MiB bound, and parsed to at least one row. amcache: every enumerated subkey and value read cleanly, no cap hit. prefetch: every .pf file was enumerated, read, decompressed and parsed with no per-file error and no cap hit.
OKpartialfile_oversized · read_failed · ntdll_symbol_missing · ntstatus_<hex> · bad_magic · truncated_header · unknown_version · truncated_entry · oversize_count · bad_path_length (comma-joined when several fire)prefetch only: the directory enumeration completed in full but one or more individual .pf files failed to open, read, decompress or parse; each failed file is already on the stream as its own prefetch_error|<file>|<reason> row, so the run is reported as a degraded success rather than a failure — one truncated file must never fail every other good row.
CONSTRAINEDpartialshimcache: reg_<code> · oversized · reg_changed_during_read · shimcache_empty · bad_magic · truncated_header · unknown_version · truncated_entry · oversize_count · bad_path_length · internal_error. amcache: data_dir_unset · dest_dir_create_<code> · dest_dir_open_<code> · dest_dir_acl · hive_missing · hive_oversized · hive_locked · win32_<code> · hive_short_write · regload_<code> · amcache_root_missing · subkey_cap · enum_<code> · subkey_open_failed · value_enum_incomplete · value_read_failed · amcache_empty · internal_error (comma-joined; amcache_empty is always listed together with any other accumulated reason, never alone when a real cause is known). prefetch: prefetch_disabled · prefetch_evidence_absent · prefetch_state_unknown · prefetch_enum_<code> · file_cap · byte_cap · internal_error (plus any of the OK/partial per-file tokens above, accumulated alongside a cap).shimcache: the key/value could not be opened or read, the blob exceeded the 16 MiB cap, changed mid-read, parsed to zero rows, failed header parsing, or an unexpected exception was caught. amcache: agent.data_dir was never configured for this host (data_dir_unset); its per-dispatch random scratch directory could not be created (dest_dir_create_<code>) or could not be re-opened as a handle immediately afterward (dest_dir_open_<code>); or that freshly-created directory failed an owner/reparse-point safety check proving it is really the object this process just created (dest_dir_acl) — otherwise the hive could not be found, copied, size-checked, loaded, or enumerated within kAmcacheMaxSubkeys (20000), or an unexpected exception was caught. prefetch: no .pf file exists under C:\Windows\Prefetch — reported as prefetch_disabled when HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters\EnablePrefetcher reads 0 (prefetching is configured off), prefetch_evidence_absent when it reads 1, 2 or 3 (prefetching is configured on, yet no file exists — consistent with, but not proof of, removal after the fact: the SysMain service state is not consulted, and a disabled SysMain leaves the directory legitimately empty with the value still 3), or prefetch_state_unknown when the best-effort registry read failed or returned an undocumented value (a read failure never blocks or fails the action); otherwise the Prefetch directory could not be enumerated, or the per-file-count (2048) or total-byte (256 MiB) cap truncated the walk before every file was seen, or an unexpected exception was caught.
UNAVAILABLEpartialwindows_only_artefactAll three actions, on every non-Windows build — this plugin has no macOS or Linux mechanism for ShimCache, Amcache, or Prefetch; the fixed fallback reports this token and rc 1 without attempting any OS call. The row itself is <action>|unsupported|windows_only_artefact — action-name-prefixed, the same leading-discriminator shape as every other row this plugin emits and the registry/rdp_control sibling convention.

Where the data goes

Sample output

Windows — captured: windows Windows 10.0.26200 x86_64 · bare-metal · 2026-09-17 · interactive user (elevated) · leg-hash 421f7d82a099

== action=shimcache
shimcache|00000009	03e865f424f10000	000a00007fff0000	8664	MicrosoftWindows.Client.CoreAI	cw5n1h2txyewy	|0|100|-
shimcache|C:/Program Files/Git/usr/bin/file.exe|1776703804000|72|-
shimcache|C:/Program Files/Git/usr/bin/sed.exe|1776703722000|72|-
shimcache|C:/WINDOWS/system32/la57setup.exe|1771278093368|72|-
shimcache|C:/WINDOWS/SoftwareDistribution/Download/Install/AM_Delta_Patch_1.459.111.0.exe|1788939517775|72|-
shimcache|C:/WINDOWS/SysWOW64/regsvr32.exe|1788174299287|604|-
shimcache|C:/WINDOWS/system32/regsvr32.exe|1788174299287|604|-
shimcache|00000009	03e865f424e40000	000a00007fff0000	8664	MicrosoftWindows.Client.CoreAI	cw5n1h2txyewy	|0|36|-
shimcache|C:/WINDOWS/system32/SbUpdateWorker.exe|1788888386924|148|-
shimcache|C:/Program Files/Git/usr/bin/xxd.exe|1776703802000|72|-
shimcache|D:/yuzu-dev/Yuzu-worktrees/feat-wave9-pr91a/build-windows/tools/plugin-capture/plugin-capture.exe|1788887960842|84|-
shimcache|C:/WINDOWS/winsxs/amd64_microsoft-windows-servicingstack_31bf3856ad364e35_10.0.26100.9441_none_a5253a19774da03c/TiWorker.exe|1788438536000|148|-
… 12 of 26 rows shown
[result_status] OK / FULL

== action=amcache
amcache||69cb415403de1ae2d4af937c0d2b6927a24a7553||||||
amcache||3a73d566a6bcd68518fe786ae33d25b2cb0b6473||||||
amcache||c7dea815b5f548a7619f4811d01c0b8af7bd7bf1||||||
amcache||c7dea815b5f548a7619f4811d01c0b8af7bd7bf1||||||
amcache||c7dea815b5f548a7619f4811d01c0b8af7bd7bf1||||||
amcache||c737866bf375bb9c5d0217f60680ea4c23f451d9||||||
amcache||569002bb6b12556826aa49176beb972425ea53e8||||||
amcache||afdfac7ba0bffa66a18477d2b80139d9797fad98||||||
amcache||5b94a0c08e13cf31493be1ce239f1e4e9c42eefb||||||
amcache||305ac3116e895257cd38673664e0750b82ef4789||||||
amcache||f869ae2fc9db261dba1a6e79554266cb87d8168c||||||
amcache||c6aa7959dadf274f066b9ee093665efc34df00c1||||||
… 12 of 26 rows shown
[result_status] OK / FULL

== action=prefetch
prefetch|ACROBAT.EXE|4E1700B6|31|17|1782139503883,1782139502989,1781888840096,1781532567812,1781532568325,1778602224391,1778602225066,1775144109458|1|65
prefetch|ACROBAT.EXE|4E1700B7|31|13|1782139503088,1781888840199,1781532877455,1781532606215,1781532603318,1781532577675,1781532579663,1781532567890|1|150
prefetch|ADOBEARM_UCB.EXE|699477AF|31|8|1781888881590,1781532923846,1781532763225,1781532746374,1781532732471,1781532722873,1781532714314,1781532691179|1|86
prefetch|AM_DELTA_PATCH_1.459.235.0.EX|2A451206|31|1|1789608233479|1|28
prefetch|AM_DELTA_PATCH_1.459.242.0.EX|7DEB36D4|31|1|1789643346854|1|29
prefetch|APPLICATIONFRAMEHOST.EXE|4CE44C83|31|13|1789416505926,1788293894278,1788268755499,1788174626805,1787914810795,1787853706962,1787836052340,1787670246111|1|157
prefetch|BASH.EXE|48EFF813|31|7|1789643981062,1789643788477,1789643719871,1789643498301,1789643400046,1789643123084,1789643055226|1|29
prefetch|BASH.EXE|9F01E358|31|12|1789595786712,1789594513759,1789594513912,1789594513896,1789594513880,1789594513862,1789594513854,1789594513841|2|98
prefetch|BASH.EXE|E0DADEC9|31|15|1789643981070,1789643719879,1789643400060,1789643400120,1789643055234,1789643055394,1789643055378,1789643055360|2|97
prefetch|BLIZZARD UNINSTALLER.EXE|9315A60E|31|1|1781888609592|1|164
prefetch|CALCULATORAPP.EXE|C6E3451F|31|4|1777546250945,1774701267760,1771862077416,1771862054413|1|232
prefetch|CCLEANER.EXE|9768B079|31|35|1787047972018,1787047970346,1787038430500,1787038428816,1785787922675,1784885968351,1784885966299,1784124629815|1|85
… 12 of 26 rows shown
[result_status] OK / PARTIAL / unknown_version,truncated_header

macOS — captured: macos macOS 26.6.2 arm64 · bare-metal · 2026-09-17 · euid 501 · leg-hash 421f7d82a099

== action=shimcache
shimcache|unsupported|windows_only_artefact
[result_status] UNAVAILABLE / PARTIAL / windows_only_artefact
[rc] 1

== action=amcache
amcache|unsupported|windows_only_artefact
[result_status] UNAVAILABLE / PARTIAL / windows_only_artefact
[rc] 1

== action=prefetch
prefetch|unsupported|windows_only_artefact
[result_status] UNAVAILABLE / PARTIAL / windows_only_artefact
[rc] 1

Caveats and known gaps

  1. Presence is evidence of a record, not proof of execution. ShimCache and Amcache record that Windows saw a file, and ShimCache’s timestamp is the file’s own last-modified time. Only Prefetch carries a run count and run times, and a Prefetch gap (disabled, cleared or never created) says nothing about what ran. Corroborate across sources before concluding anything.
  2. A partial Amcache read is visible only in the typed result status. When the walk is truncated or an entry fails, amcache returns the rows it read with status CONSTRAINED / PARTIAL but writes no constrained|<reason> row, unlike prefetch; a consumer reading rows alone cannot tell the list is incomplete. Some rows also legitimately carry only a SHA-1 with every other field blank, because the registry entry itself holds nothing else.
  3. Prefetch v17 is rejected and the v23/v26 volume layout is unverified. Windows XP/2003 (v17) files report unknown_version rather than being decoded with the wrong offsets. The v23 and v26 volume-entry size comes from published format documentation and was not checked against a real capture here (every real fixture is v31); a naturally wrong size fails closed, but a deliberately crafted file could still parse to fabricated counts, which needs administrator-tier write access to the Prefetch directory.
  4. The actions stay refused until an operator enables the kill switch. PUT /api/v1/plugin-config/execution_artifacts/kill-switch {"enabled":true} turns them on; until then every dispatch is refused at the server rather than reported as a plugin failure. This is the expected state on a fresh install or an unconfigured fleet, so a refusal there is not a fault.
  5. Amcache needs a configured data directory and normally leaves nothing behind. amcache reports constrained|data_dir_unset without agent.data_dir (the agent daemon always sets it) and dest_dir_acl if the fresh scratch directory fails its owner check; re-dispatching creates a new directory. The scratch directory is removed on every normal exit, and one left by a crashed agent or by antivirus holding the copy open (note|temp_cleanup_failed) is reclaimed by a capped sweep at agent start and before each amcache dispatch once it is over an hour old. The sweep is bounded and pauses for an hour after a forward wall-clock step, so reclamation can be delayed.

Source and tests