Zurück zu allen Beiträgen

Die meisten Leute, die mit Prefetch arbeiten, sehen nie auf die Bytes. Sie starten einen Parser, lesen eine Tabelle und ziehen weiter. Das ist meist in Ordnung. Es ist nicht in Ordnung, wenn der Parser falsch liegt, und die einzige Möglichkeit zu wissen, ob Ihr Parser falsch liegt, besteht darin zu verstehen, was er eigentlich tun soll.

Das Prefetch-Format hat sich in zwanzig Jahren fünf- oder sechsmal geändert. Jede Änderung hat seinerzeit mindestens einen verbreiteten Parser kaputtgemacht. Wenn Sie eine .pf-Datei von einem Win11-Host mit einem Tool lesen, das zuletzt 2019 aktualisiert wurde, sollte Sie das interessieren.

SCCA: das Magic und die Form

Jede klassische Prefetch-Datei beginnt mit der ASCII-Zeichenkette SCCA an Offset 0x04. Die vier Bytes davor sind das Versionsfeld, Little-Endian. Das prüft jeder Parser zuerst, und die Version ist das Tor zu allem anderen.

Die bekannten Werte:

  • 0x11 (dezimal 17) für Windows XP und 2003
  • 0x17 (23) für Vista und Windows 7
  • 0x1A (26) für Windows 8 und 8.1
  • 0x1E (30) für Windows 10 (unkomprimierte Ära und die ersten MAM-komprimierten Builds)
  • 0x1F (31) für spätere Windows-10/11-Builds. Behandeln Sie das als „Win10+ aktuell" statt an einen bestimmten Build gebunden.

Wenn die ersten vier Bytes der Datei nicht SCCA sind und nicht die MAM-Signatur (gleich mehr dazu), haben Sie keine Prefetch-Datei. Sie haben etwas anderes mit der Endung .pf, und der Fall, den ich am häufigsten gesehen habe, ist, dass jemand eine Datei über SMB mit einem encoding-fähigen Tool kopiert hat, das sie verunstaltet hat. Neu erfassen.

Nach Version und Magic folgt ein kleiner Header-Block: Gesamtdateigröße, der Name der ausführbaren Datei als UTF-16LE (bis zu 30 Zeichen, mit Null gepolstert) und ein Pfad-Hash (auch separat im Detail behandelt). Der Name der ausführbaren Datei im Header sollte mit dem Präfix des Dateinamens übereinstimmen. Wenn nicht, sehen Sie eine umbenannte Datei, manuelle Manipulation oder, seltener, eine Binärdatei, deren internes Namensfeld länger als 29 Zeichen war und abgeschnitten wurde.

Sections A, B, C, D und der Rest

Innerhalb der Datei ist Prefetch in Sektionen organisiert, die ihren Zweck über die Versionen hinweg ungefähr beibehalten haben, auch wenn sich Offsets und Feldbreiten verändert haben:

  • Section A ist das File-Metrics-Array. Ein Eintrag pro Datei, die die Binärdatei während des Trace-Fensters berührt hat. Jeder Eintrag hat eine Startzeit, eine Dauer, einen Dateinamens-String-Offset in Section C und eine Dateireferenz in die MFT (letztere nur auf neueren Versionen).
  • Section B ist das Trace-Chains-Array. Das sind die Page-Fault-Sequenzdaten, die das Betriebssystem tatsächlich interessieren. Aus forensischer Sicht ist das überwiegend Rauschen; Sie werden es selten explizit parsen.
  • Section C sind die Dateinamen-Strings. UTF-16LE-Pfade, einer nach dem anderen, per Offset aus Section A referenziert. Daraus wird die „Datei-Load-Liste", wenn Sie einen Bericht ausgeben.
  • Section D ist das Volume-Informations-Array. Ein Eintrag pro Volume, das die Binärdatei berührt hat. Jeder Eintrag hat einen Volume-Pfad (typischerweise \DEVICE\HARDDISKVOLUMEn), eine Erstellungszeit, eine Seriennummer und einen Index in die Directory-Strings-Tabelle.

Nach Section D finden Sie üblicherweise die Directory-Strings und, auf neueren Versionen, zusätzliche Metadaten, die je nach Build variieren. Die acht Ausführungszeitstempel leben im Header ab Win8+, in einem leicht anderen Layout als unter Win7 (das nur einen Zeitstempel hatte). Der Ausführungszähler sitzt daneben.

Die zwei Dinge, die sich zwischen Versionen bewegen, sind die Offsets zu jeder Section (im Header aufgezeichnet) und die Größe einzelner Einträge (der Eintrag im File-Metrics-Array wuchs von 20 Byte unter XP/7 auf 32 Byte unter Win10, um die MFT-Referenz aufzunehmen). Ein Parser, der „Section A beginnt bei Offset 0x98" hardcodiert, statt den Offset aus dem Header zu lesen, wird bei der nächsten OS-Release stillschweigend ausfallen. Davon kursieren noch einige auf GitHub.

MAM: der Win10-Kompressions-Wrapper

Irgendwann um Windows 10 1607 begann Microsoft, Prefetch-Dateien in MAM-Kompression einzupacken. Die Datei beginnt nicht mehr mit SCCA. Sie beginnt mit MAM\x04 (das Byte 0x04 ist der Algorithmus-Identifikator, Xpress Huffman). Die nächsten vier Bytes sind die unkomprimierte Größe, Little-Endian. Alles danach ist der Xpress-Huffman-komprimierte Strom, der das enthält, was sonst die einfache SCCA-Datei wäre.

Wenn Sie korrekt dekomprimieren, erhalten Sie genau die oben beschriebene SCCA-Struktur zurück, Version 0x1E oder 0x1F. Das Format on the wire ist dasselbe; nur der Wrapper hat sich geändert.

Die relevante Windows-API ist RtlDecompressBufferEx mit COMPRESSION_FORMAT_XPRESS_HUFF. Eric Zimmermans PECmd ruft die Windows-API auf Windows-Hosts auf und verwendet eine verwaltete Xpress-Huffman-Implementierung, wenn es unter Linux läuft. Mehrere Python-Parser liefern einen reinen Python-Xpress-Huffman-Decoder, der langsam, aber korrekt ist. Diejenigen, die MAM überhaupt nicht behandeln, drucken „keine Prefetch-Datei" oder, schlimmer, geben Müll aus und enden mit Exit 0.

Bestätigen Sie immer die MAM-Unterstützung Ihres Parsers, indem Sie ihm eine bekannte gute Win10-Prefetch-Datei vorlegen (jede Datei aus C:\Windows\Prefetch\ auf einem aktuellen Win10/11-Host genügt) und prüfen, ob Ausführungszähler und -zeiten mit dem übereinstimmen, was PECmd meldet.

Was sich zwischen Win10 v30 und Win11 v31 änderte

Weniger, als die Versionsnummer suggeriert, auf dem Papier. Das interne Layout ist nahezu identisch. Was sich in der Praxis änderte:

  • Die Art, wie der Pfad-Hash Kontext einbezieht (Befehlszeilenargumente, „App-V"-Umgebung, Paket-Full-Name bei UWP-Apps), wurde erweitert. Dieselbe EXE in zwei verschiedenen Sandboxen erzeugt zwei verschiedene .pf-Dateien, wo auf früheren Builds eine Kollision möglich war.
  • Prefetch-Trace-Zeiten wurden feinkörniger. Auf v31 sehen Sie manchmal Sub-Sekunden-Auflösung, die frühere Versionen gerundet haben.
  • Das Ablaufverhalten verschob sich. Der Acht-Zeitstempel-Ring ist als FIFO mit fester Größe dokumentiert, aber Win10 1709+ trimmt ältere Einträge aggressiv während Idle-Wartung. v31 trimmt noch aggressiver auf SSD-Systemen.

Ein Parser, der v30 verarbeitet, verarbeitet meist auch v31 ohne Modifikation, weil sich die Struktur kaum bewegt hat. Was sich unter der Struktur bewegt, ist das, was Windows selbst hineinschreibt, und das können Sie in einem Parser nicht reparieren.

Das File-Metrics-Array: worauf zu schauen ist

Wenn Sie nur Zeit haben, einen Teil einer Prefetch-Datei von Hand zu betrachten, schauen Sie auf Section A.

Jeder Eintrag sagt Ihnen: wann im Zehn-Sekunden-Trace-Fenster die Datei zuerst berührt wurde, wie lange die Berührung dauerte und den Pfad zur Datei. Auf neueren Versionen gibt Ihnen die MFT-Referenznummer die Datei-ID, was Gold ist, wenn der Pfad nicht mehr existiert. Sie können die Dateireferenz mit der Live-MFT gegenkreuzen und den Originaleintrag wiederherstellen, auch wenn der Pfad inzwischen von einer anderen Datei wiederverwendet wurde.

Ein konkretes Muster: Eine .pf-Datei, deren Load-Liste Referenzen enthält, die auf in der Live-MFT als gelöscht markierte MFT-Einträge zeigen, bedeutet, dass diese Dateien beim Lauf der Binärdatei auf der Platte waren und seitdem entfernt wurden. Paaren Sie das mit dem USN-Journal und Sie können das Verzeichnis zum Ausführungszeitpunkt rekonstruieren.

Welche Parser welche Versionen verarbeiten

Operative Notizen, Stand jetzt:

  • Eric Zimmermans PECmd ist die Referenz. SCCA v17, v23, v26, v30, v31 und MAM-eingepackte Varianten von v30/v31 werden korrekt verarbeitet. Das ist das Offline-Tool, das ich standardmäßig nehme.
  • libscca (Joachim Metz) ist die C-Bibliothek unter mehreren anderen Tools. Sie verfolgt das Format genau und ist das, wogegen ich heute bauen würde, wenn ich meinen eigenen Parser schreiben würde.
  • Windows-Prefetch-Parser (PoorBillionaire) ist der Python-Parser, den die meisten Leute zuerst auf GitHub finden. Auf Pre-Win10-Dateien ist er in Ordnung. Er verarbeitet MAM-komprimiertes Prefetch nicht von Haus aus und produziert stillschweigend falsche Ausgaben auf Win10/11-Hosts, sofern Sie keinen Dekompressor einpatchen. Lesen Sie das README sorgfältig und prüfen Sie das Datum.
  • Der Parser auf dieser Seite verarbeitet SCCA und MAM-eingepackte Dateien vollständig im Browser. Nützlich, wenn Sie ein oder zwei Dateien anschauen möchten, ohne Werkzeuge hochzufahren. Für Bulk-Arbeit verwenden Sie PECmd.

Wenn Sie einen Parser haben, dessen Name nicht auf dieser Liste steht und dessen letzter Commit mehr als zwei Jahre zurückliegt, testen Sie ihn gegen ein bekanntes Sample, bevor Sie seinem Output vertrauen.

Warum das wichtig ist, wenn Sie einen Bericht schreiben

Das Versionsfeld ist das Erste, das Sie prüfen. Der MAM-Wrapper ist das Zweite. Die Section-Offsets, aus dem Header gelesen, sind das Dritte. Bekommen Sie diese drei richtig, und Sie können jede Prefetch-Datei aus jedem produktiven Windows von XP bis aktuell parsen. Bekommen Sie irgendetwas davon falsch, und Ihre Werkzeuge geben eine Zahl aus, aber die Zahl wird falsch sein, und Sie werden nicht wissen, dass sie falsch ist, bis jemand Sorgfältigeres als Sie sich die rohen Bytes während eines Kreuzverhörs ansieht.

Ich war diese sorgfältigere Person, auf der falschen Seite eines Einsatzes, mehr als einmal.

Weiterführende Literatur