Das RecentFileCache.bcf Dateiformat, in einfachen Worten
Das BCF-Format ist ein Header, eine Liste von längen-präfixierten UTF-16LE-Pfaden, und das war's. Hier ist, was jedes Byte bedeutet und warum sich seit 2009 nichts geändert hat.
Es gibt forensische Dateiformate, die einem das Leben schwer machen. CBS-Logs, ESE-Datenbanken, die binäre Struktur des Windows Event Logs. RecentFileCache.bcf ist keines davon. Es ist ein Header, ein Zähler und eine Liste von Strings. Sie können es in zwölf Zeilen Python parsen und werden für nichts davon einen Hex-Editor brauchen.
Diese Einfachheit ist der Grund, warum sich das Format seit dem Erscheinen von Windows 7 SP1 nicht geändert hat. Es gibt nichts zu erweitern. Microsoft ist stattdessen zur AmCache übergegangen, anstatt diese Datei zu versionieren.
Was in der Datei steht
C:\Windows\AppCompat\Programs\RecentFileCache.bcf wird von der Application-Experience-Appraisal-Aufgabe auf Win7 SP1 und Server 2008 R2 geschrieben. Das On-Disk-Layout, in der Reihenfolge:
- Ein fester Header. Zwanzig Bytes.
- Ein 32-Bit Little-Endian Zähler der Einträge.
- Null oder mehr Einträge, jeder davon ein längen-präfixierter UTF-16LE-String, der den vollen NT-Pfad einer ausführbaren Datei enthält.
Das ist die ganze Datei. Keine Checksums. Kein CRC. Kein Tail. Kein Pro-Eintrags-Zeitstempel. Kein Pro-Eintrags-Hash. Wenn die Datei 18 Bytes lang ist, hat sie einen Header und sonst nichts. Wenn sie zwei Megabyte lang ist, ist sie eine Weile gewachsen, weil der Appraiser nicht gelaufen ist.
Der Header
Die ersten zwanzig Bytes sind auf jeder BCF konstant, die ich jemals von einem Win7 Host gezogen habe. Fünf 32-Bit Little-Endian Werte, allesamt magische Konstanten. Der interessante ist der erste: 0xFE 0xFF 0xEE 0xFE. Der Rest sind Nullen oder Padding. Wenn Sie einen anderen Wert in den ersten vier Bytes sehen, haben Sie keine RecentFileCache.bcf. Sie haben etwas anderes, das zufällig denselben Namen trägt.
Ich habe genau einen Fall eines korrumpierten Headers in der freien Wildbahn gesehen, und der wurde durch ein Antivirenprodukt verursacht, das die Datei halb in Quarantäne gestellt hat. Die Header-Bytes waren durch Nullen ersetzt worden. Wert, das zu prüfen.
Der Eintragszähler
Bytes 20 bis 23, Little-Endian, sind der Zähler der folgenden Einträge. Wenn diese Zahl null ist, ist der Appraiser kürzlich gelaufen und hat den Working Set geleert. Wenn sie groß ist, hat entweder seit Wochen nichts die Datei geleert, oder es sind viele neue Binärdateien zwischen den Bewertungsdurchläufen aufgetaucht. Beides ist auf seine Weise interessant.
Der Zähler ist autoritativ. Wenn der Zähler zehn sagt und die Datei elf Strings enthält, behandeln Sie den elften als Müll. In der Praxis passiert das nicht, weil die Datei atomar von einem einzigen Prozess geschrieben wird, aber Parser sollten sich nicht allein auf String-Walking verlassen, um das Ende zu finden.
Die Einträge
Jeder Eintrag ist:
- Eine 32-Bit Little-Endian Länge in Bytes (nicht Zeichen).
- So viele Bytes UTF-16LE-Stringdaten.
Die Strings sind NT-Object-Manager-Pfade. Sie beginnen mit \??\ und dann einem normalen Windows-Pfad:
\??\C:\Windows\System32\rundll32.exe
\??\C:\Users\bob\AppData\Local\Temp\setup.exe
Behandeln Sie das \??\-Präfix als C:\. Es ist die Art des Kernels zu sagen "DOS-Device-Namespace" und es trägt keine forensische Bedeutung über "das ist ein regulärer Dateipfad" hinaus. Streifen Sie es für die Anzeige ab, behalten Sie es für die Genauigkeit, wenn Sie maschinenlesbare Ausgabe exportieren.
Die Länge ist in Bytes, was fast jeden beim ersten Parsen stolpern lässt. Ein Pfad mit dreißig Unicode-Zeichen benötigt sechzig Bytes plus das, was die Datei für die abschließende Null verwendet, was typischerweise zwei Bytes sind, aber Sie sollten sich nicht darauf verlassen. Lesen Sie die Länge, lesen Sie so viele Bytes, decodieren Sie als UTF-16LE, streifen Sie abschließende Nullen ab. Fertig.
Es gibt keinen Separator zwischen Einträgen. Das Längenfeld des nächsten Eintrags beginnt unmittelbar nach den Stringdaten des vorherigen Eintrags. Wenn Ihr Parser um ein Byte verrutscht, erhalten Sie für den Rest der Datei Müll. Deshalb ist es wichtig, den Eintragszähler zu beachten: Er gibt Ihnen eine Stop-Bedingung, die nicht vom String-Inhalt abhängt.
Zwölf Zeilen Python
import struct
def parse_bcf(path):
with open(path, "rb") as f:
data = f.read()
if data[:4] != b"\xfe\xff\xee\xfe":
raise ValueError("not a RecentFileCache.bcf")
count = struct.unpack_from("<I", data, 20)[0]
offset = 24
entries = []
for _ in range(count):
length = struct.unpack_from("<I", data, offset)[0]
offset += 4
s = data[offset:offset + length].decode("utf-16-le").rstrip("\x00")
entries.append(s)
offset += length
return entries
Das reicht aus, um jede BCF zu parsen, die Sie antreffen werden. Keine Abhängigkeiten. Keine Edge-Cases, die ich in der Produktion erlebt habe. Wenn Sie das in einer Unternehmensumgebung machen, in der Sie nicht beliebiges Python auf der Beweismaschine ausführen können, macht der Parser auf dieser Seite dasselbe im Browser, ohne Upload.
Was das Format Ihnen nicht verrät
Das ist der Teil, in dem die Einfachheit des Formats zu einer Einschränkung wird. Die BCF zeichnet nicht auf:
- Ausführungszeit. Sie wissen, dass die Binärdatei seit dem letzten Bewertungsdurchlauf gelaufen ist, und das ist alles.
- Ausführungsanzahl. Ein Lauf und hundert Läufe sehen identisch aus.
- Den Benutzer, der sie ausgeführt hat. Die Datei ist pro Maschine.
- Einen Hash. Sie können nicht vom Inhalt der Datei zu Threat Intel pivotieren.
- Eine Load-Liste. Im Gegensatz zu Prefetch gibt es keine Aufzeichnung der in den Prozess geladenen DLLs.
- Befehlszeilenargumente. Keine. Nicht einmal die Existenz von Argumenten.
Wenn Sie eines davon benötigen, paaren Sie die BCF mit Prefetch, der Master File Table, dem USN-Journal und welchem EVTX auch immer Sie haben. Die BCF sagt Ihnen das Was; alles andere sagt Ihnen das Wann, Wie und Wer.
Warum sich das Format nicht geändert hat
Microsoft ersetzte diese Datei in Windows 8 durch die AmCache und ist nie zurückgekehrt, um Felder zur BCF hinzuzufügen. Die AmCache ist ein Hive im ESE-Stil mit Dutzenden von Feldern pro Eintrag: Hashes, Datei-Metadaten, Installationszeit, Herausgeber-Informationen. Die BCF würde da niemals hineinwachsen. Sie existierte als Arbeitsdatei für eine Bewertungspipeline, die seitdem um andere Primitive herum neu gestaltet wurde.
Die praktische Konsequenz ist, dass ein Parser aus 2014 und ein Parser aus 2026 bei derselben Eingabe die gleiche Ausgabe produzieren. Es gibt keinen Versionsdrift, um den man sich Sorgen machen müsste. Tools, die geschrieben wurden, bevor das Format öffentlich dokumentiert wurde, funktionieren immer noch. Die ursprüngliche öffentliche Analyse von Willi Ballenthin bei Mandiant aus 2014 ist heute noch korrekt; ich habe nicht ein einziges Byte gesehen, das von dem abweicht, was er dokumentiert hat.
Das ist selten für Windows-Artefakte. Die meisten von ihnen mutieren über Builds hinweg. Shimcache hat sich fünfmal zwischen Win7 und Win10 geändert. Das AmCache-Schema hat Spalten gewonnen und verloren. Prefetch wurde in Windows 10 komprimiert. Die BCF sitzt einfach da, eingefroren, weil niemand einen Grund hatte, sie nach Win7 anzufassen.
Eine Anmerkung zum Truncation
Nachdem der Appraiser die Datei verarbeitet hat, kürzt das OS sie zurück auf "Header plus Null-Zähler." Die Datei wird nicht gelöscht. Die Dateisystem-Metadaten (Erstellungszeit, Eintrag im Elternverzeichnis) überleben. Das ist aus zwei Gründen wichtig:
- Die Erstellungszeit von
RecentFileCache.bcfselbst kann jedem Pfad darin um Monate oder Jahre vorausgehen. Verwenden Sie nicht die Zeitstempel der Datei selbst, um die Einträge zu begrenzen. - Eine Binärdatei, die vor zwei Tagen lief und gestern vom Appraiser verarbeitet wurde, ist aus der Datei verschwunden, aber die Datei ist immer noch da und sieht unschuldig und klein aus. Leer ist nicht dasselbe wie nie benutzt.
Weiterführende Literatur
- Willi Ballenthin, RecentFileCache.bcf. Die ursprüngliche öffentliche Formatanalyse. Immer noch korrekt.
- Microsoft, Application Experience und Programminventur. Hersteller-Kontext dafür, warum die Datei existiert.
- Yogesh Khatri, AmCache and friends. Für wenn Sie wissen müssen, was als Nächstes kam.
Wenn Sie schon einmal ein binäres forensisches Format geparst haben, wird sich die BCF wie eine Aufwärmübung anfühlen. Das ist die richtige Reaktion. Investieren Sie Ihre Mühe in die Triage der Pfadliste, nicht in das Dateiformat.