Jump List Parser
Zurück zum Blog

Das Dateiformat CustomDestinations-ms erklärt

2026-05-255 Min. Lesezeit

automaticDestinations-ms ist das, was Windows über den Benutzer geschrieben hat. customDestinations-ms ist das, was die Anwendung über sich selbst geschrieben hat. Gleicher Ordner, gleiche AppID-benannte Dateien, völlig unterschiedliche Container. Die Automatic-Seite ist MS-CFB mit nummerierten LNK-Streams. Die Custom-Seite ist ein flacher Byte-Stream mit Kategorien und Rücken an Rücken stehenden Shell-Links, und nirgendwo eine Compound-Datei zu sehen. Wenn Sie eine OLE-Reader füttern würden in der Erwartung der anderen, wüssten Sie das schon.

Warum CustomDestinations überhaupt existiert

Die Automatic-Datei beantwortet "Was hat der Benutzer kürzlich angefasst?". Die Custom-Datei beantwortet "Was möchte die Anwendung in ihrer Jump List haben?". Die Aufteilung erfolgt nach Autor, nicht nach Inhalt. Ein Entwickler, der Chromes Eintrag "Neues Inkognito-Fenster" oder Words Aufgabe "Neues Dokument" haben möchte, ruft ICustomDestinationList auf: BeginList, fügt IObjectCollection-Instanzen über AppendCategory, AppendKnownCategory oder AddUserTasks hinzu, dann CommitList. Die Shell serialisiert das in %AppData%\Microsoft\Windows\Recent\CustomDestinations\<AppID>.customDestinations-ms.

Typischer Inhalt:

  • Eine Tasks-Kategorie, Verben, die der Entwickler eingebaut hat. "Neues Inkognito-Fenster", "Neues privates Fenster", "E-Mail verfassen", "Beenden". Diese zeigen auf die eigene ausführbare Datei der Anwendung mit spezifischen Befehlszeilenargumenten.
  • Eine Known-Kategorie, Frequent oder Recent, an die Shell delegiert. Die App sagt "Zeige hier die Standardliste"; die Shell füllt sie aus.
  • Eine oder mehrere Custom-Kategorien, beliebige UTF-16LE-Namen. Browser, IDEs, Medienplayer verwenden das für Dinge wie "Meistbesucht", "Zuletzt verwendete Projekte", "Zuletzt gespielt".

Struktur auf der Festplatte

Die Datei beginnt mit einem festen Header, der einen Magic-Wert, eine Formatversion und eine Anzahl von Kategorieeinträgen trägt. Jeder Kategorieeintrag codiert:

  • Ein type-Feld: 0 für eine benutzerdefinierte (App-benannte) Kategorie, 1 für eine bekannte Kategorie wie Frequent oder Recent, 2 für die Tasks-Kategorie.
  • Für Typ 0, einen UTF-16LE-Namen, präfixiert durch seine Länge in Zeichen (nicht Bytes).
  • Eine Eintragsanzahl.
  • So viele serialisierte LNK-Strukturen, Rücken an Rücken geschrieben.
[ header: magic + version + category_count ]
repeat category_count times:
    [ type (0=custom | 1=known | 2=tasks) ]
    [ if type==0: name_len_chars + UTF-16LE name ]
    [ entry_count ]
    [ LNK #1 ][ LNK #2 ] ... [ LNK #entry_count ]
[ trailing footer 0xBABFFBAB / padding ]

Es gibt keinen Längen-Präfix pro Eintrag vor jedem LNK. Sie parsen den Shell-Link an Ort und Stelle und lassen die LNK-Struktur Ihnen sagen, wo sie endet. Deshalb ist ein funktionierender LNK-Parser für dieses Format nicht verhandelbar.

Der Terminator 0xBABFFBAB ist ein Sniff-Test, so gut wie die MS-CFB-Magic auf der Automatic-Seite. Wenn Sie diese vier Bytes am Dateiende sehen und keinen Compound-File-Header am Anfang, schauen Sie auf eine CustomDestinations-Datei.

Die LNK-Nutzlast, Byte für Byte

Jedes Ziel ist ein standardmäßiger MS-SHLLINK Shell-Link, identisch in der Form mit den nummerierten Streams innerhalb einer Automatic-Datei. Gleicher Parser, kein Sonderfall. Sie erhalten ShellLinkHeader, optionale LinkTargetIDList, LinkInfo mit der VolumeID und LocalBasePath, die StringData-Strings (NAME_STRING, RELATIVE_PATH, WORKING_DIR, COMMAND_LINE_ARGUMENTS, ICON_LOCATION) und jegliche ExtraData-Blöcke. Der TrackerDataBlock überlebt auch hier mit seinen Volume- und Machine-IDs und Droid-GUIDs. Zielpfad, Arbeitsverzeichnis, Befehlszeilenargumente, Icon-Speicherort und die drei FILETIME-Zeitstempel kommen alle aus dem Inneren des LNK.

Dieser letzte Punkt ist wichtig: Der CustomDestinations-Container dupliziert keine Zeitstempel oder Zugriffszählungen pro Eintrag. Es gibt keine DestList. Die Reihenfolge ist nach Dateiposition, und die einzigen Zeitstempel sind die innerhalb der eingebetteten LNKs.

Angeheftete Elemente und die Tasks-Kategorie

Die Tasks-Kategorie (type = 2) enthält entwicklerdefinierte Verben, keine Benutzerdokumente. "Neues Fenster öffnen", "E-Mail verfassen", "Private Sitzung starten". Diese LNKs zeigen fast immer auf die Anwendungsbinärdatei mit Argumenten, chrome.exe --incognito, winword.exe /n, outlook.exe /c ipm.note. Nützlich, um zu verstehen, was eine Anwendung anbot; nicht nützlich als Aufzeichnung der Benutzeraktivität.

Angeheftete Einträge sind anders. Sie werden neben anderen Kategorien gespeichert, aber sie überleben Jump-List-Resets und das explizite Löschen kürzlich verwendeter Elemente. In der Triage ist ein angehefteter Eintrag Absicht. Der Benutzer hat aktiv "An diese Liste anheften" geklickt. Behandeln Sie das als ein stärkeres Signal als einen vorübergehenden MRU-Hit.

Praktische Parsing-Hinweise

  • Lesen Sie streng sequentiell. Es gibt kein zentrales Verzeichnis; Offsets sind implizit in der Cursor-Position. Ein fehlgeschlagenes Parsen bei Offset N macht alles nach N ungültig.
  • Keine OLE-Schicht. Versuchen Sie nicht, die Datei mit einem Compound-File-Reader zu öffnen. Behandeln Sie sie als rohen Byte-Stream.
  • UTF-16LE-Strings sind in Zeichen längen-präfixiert. Multiplizieren Sie mit zwei, bevor Sie den Cursor vorrücken.
  • Trailing-Footer oder Padding ist normal. Tolerieren Sie einen kurzen Schwanz, anstatt ihn als Korruption zu behandeln. Der 0xBABFFBAB-Marker, wenn vorhanden, ist das Ende.
  • Verwenden Sie Ihren LNK-Parser wieder. Die Form ist in [MS-SHLLINK] dokumentiert und wurde wiederholt reverse-engineered: Volatility, libforensics, Eric Zimmermans JLECmd, Kacos2000s Jumplist-Browser, fox-its Forschungs-Releases. Schreiben Sie keinen eigenen von Grund auf, es sei denn, Sie tun es zum Spaß.

Warum das für die Triage wichtig ist

Eine customDestinations-ms-Datei mit einer abgestandenen Tasks-Liste ist unauffällig, es ist das, was die Anwendung ausgeliefert hat. Eine customDestinations-ms-Datei, deren angeheftete LNKs auf Netzwerkfreigaben, USB-Laufwerke oder unerwartete ausführbare Dateien zeigen, ist interessant. Die Anheftung überlebte, weil der Benutzer sie dort platzierte. Vergleichen Sie die AppID mit dem Anwendungskatalog (die LNK-Dateien in Recent\ und die passende automaticDestinations-ms werden bestätigen), und schauen Sie dann in jeder angehefteten LNK auf die LinkInfo- und TrackerDataBlock-Felder für Pfad, Hostname und Droid-GUID.

Um all dies an einem echten Sample zu sehen, ohne Code zu schreiben, legen Sie eines in den Parser auf der Startseite, er dekodiert beide Dateitypen nebeneinander.

Weiterführende Literatur