{"id":199,"date":"2023-01-28T09:00:00","date_gmt":"2023-01-28T09:00:00","guid":{"rendered":"http:\/\/justruss.tech\/index.php\/2023\/01\/28\/windows-prefetch-files-in-incident-response\/"},"modified":"2026-05-13T12:59:35","modified_gmt":"2026-05-13T12:59:35","slug":"windows-prefetch-files-in-incident-response","status":"publish","type":"post","link":"https:\/\/justruss.tech\/index.php\/2023\/01\/28\/windows-prefetch-files-in-incident-response\/","title":{"rendered":"Windows Prefetch Files in Incident Response"},"content":{"rendered":"<p>Windows Prefetch files provide execution evidence even after attacker cleanup. They are created by the Windows Prefetcher (SysMain service) to speed up application launches, but their forensic value is that they record execution time, run count,<br \/>\nand the files accessed during startup \u2014 all timestamped and persistent.<\/p>\n<h3>Location, naming, and storage format<\/h3>\n<p>Prefetch files live at <code>C:\\Windows\\Prefetch\\<\/code>. Naming convention:<\/p>\n<pre>EXECUTABLE_NAME-HASH.pf\n# Examples:\nMIMIKATZ.EXE-3A27C2B8.pf\nPROCDUMP.EXE-1B2C3D4E.pf\nCMD.EXE-89305D4C.pf\nCMD.EXE-AC113AA0.pf  # different hash = run from different path<\/pre>\n<p>The 8-character hash is computed from the full path of the executable. The same binary run from two different directories produces two different prefetch files. This means even if an attacker copies their tools to a new location, a new prefetch<br \/>\nentry is created with the new path encoded in the hash.<\/p>\n<p>Maximum prefetch files: 128 (Windows XP\/Vista\/7), 1024 (Windows 8+). On heavily used systems, older entries are overwritten. On investigation targets that were not rebooted repeatedly, entries can go back weeks.<\/p>\n<h3>Data stored per prefetch file<\/h3>\n<ul>\n<li>Executable name and path<\/li>\n<li>Run count (total executions)<\/li>\n<li>Last 8 run timestamps (Windows 8+; Windows 7 stores only the most recent)<\/li>\n<li>Volume information (drive serial number, volume path)<\/li>\n<li>Referenced files and directories (loaded during first 10 seconds of execution)<\/li>\n<\/ul>\n<h3>Parsing with PECmd<\/h3>\n<pre># Process single prefetch file\nPECmd.exe -f \"C:\\Windows\\Prefetch\\MIMIKATZ.EXE-3A27C2B8.pf\" --csv C:\\Output\\\n\n# Process entire Prefetch directory\nPECmd.exe -d \"C:\\Windows\\Prefetch\" --csv C:\\Output\\ --csvf prefetch_results.csv\n\n# Parse from forensic image (files extracted to working directory)\nPECmd.exe -d \/tmp\/prefetch_extracted\/ --csv \/tmp\/output\/<\/pre>\n<p>Sample output columns:<\/p>\n<pre>SourceFilename,SourceCreated,LastRun,RunCount,PreviousRun1,PreviousRun2,...\nMIMIKATZ.EXE-3A27C2B8.pf,2023-09-18 23:24:01,2023-09-18 23:28:44,3,2023-09-18 23:26:12,2023-09-18 23:24:01\nPROCDUMP.EXE-1B2C3D4E.pf,2023-09-18 23:31:05,2023-09-18 23:31:05,1,,<\/pre>\n<h3>Referenced files analysis<\/h3>\n<p>The referenced files list shows what the executable read during its first 10 seconds. For credential dumping tools this is extremely revealing:<\/p>\n<pre># MIMIKATZ.EXE referenced files (partial):\n\\WINDOWS\\SYSTEM32\\LSASS.EXE\n\\WINDOWS\\SYSTEM32\\DBGHELP.DLL\n\\WINDOWS\\SYSTEM32\\NTDLL.DLL\n\\WINDOWS\\SYSTEM32\\LOGONSESSION.DLL\n\\USERS\\VICTIM\\DESKTOP\\LSASS.DMP  &lt;-- output file location<\/pre>\n<p>The presence of LSASS.EXE in the referenced files list confirms the tool accessed LSASS. The LSASS.DMP reference reveals the output path \u2014 useful for knowing where to look for data that may have been exfiltrated.<\/p>\n<h3>Timeline integration<\/h3>\n<pre>python3 &lt;&lt; EOF\nimport csv, datetime\n\n# Build execution timeline from PECmd output\nentries = []\nwith open(&quot;prefetch_results.csv&quot;) as f:\n    for row in csv.DictReader(f):\n        name = row[&quot;ExecutableName&quot;]\n        for ts_field in [&quot;LastRun&quot;,&quot;PreviousRun1&quot;,&quot;PreviousRun2&quot;,\n                          &quot;PreviousRun3&quot;,&quot;PreviousRun4&quot;,&quot;PreviousRun5&quot;,\n                          &quot;PreviousRun6&quot;,&quot;PreviousRun7&quot;]:\n            if row.get(ts_field):\n                try:\n                    ts = datetime.datetime.strptime(row[ts_field], &quot;%Y-%m-%d %H:%M:%S&quot;)\n                    entries.append((ts, name, row[&quot;RunCount&quot;]))\n                except:\n                    pass\n\nentries.sort()\nincident_start = datetime.datetime(2023, 9, 18, 22, 0, 0)\nincident_end   = datetime.datetime(2023, 9, 19, 2, 0, 0)\n\nfor ts, name, count in entries:\n    if incident_start &lt;= ts &lt;= incident_end:\n        # Flag suspicious executables\n        suspicious = any(s in name.upper() for s in [\n            &quot;MIMIKATZ&quot;,&quot;PROCDUMP&quot;,&quot;METERPRETER&quot;,&quot;COBALTSTRIKE&quot;,\n            &quot;RUBEUS&quot;,&quot;SHARPHOUND&quot;,&quot;BLOODHOUND&quot;\n        ])\n        marker = &quot; *** SUSPICIOUS ***&quot; if suspicious else &quot;&quot;\n        print(f&quot;{ts} | {name} | runs={count}{marker}&quot;)\nEOF<\/pre>\n<h3>Prefetch on Windows Server<\/h3>\n<p>Prefetching is disabled by default on Windows Server editions. The registry key:<\/p>\n<pre>HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters\nValue: EnablePrefetcher\n  0 = Disabled\n  1 = Application prefetching only\n  2 = Boot prefetching only\n  3 = Both (default on workstations)<\/pre>\n<p>On server compromises where Prefetch is disabled, the fallback artefacts are Amcache (which is present on Server editions), the Windows event log (4688 with command line logging), and Sysmon if deployed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Prefetch files can tell you what ran, when it ran, and sometimes from where &#8211;<br \/>\neven after the original executable has been deleted.<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-199","post","type-post","status-publish","format-standard","hentry","category-dfir"],"_links":{"self":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/199","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/comments?post=199"}],"version-history":[{"count":2,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/199\/revisions"}],"predecessor-version":[{"id":241,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/199\/revisions\/241"}],"wp:attachment":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/media?parent=199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/categories?post=199"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/tags?post=199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}