Le format de fichier AutomaticDestinations-ms expliqué
Un fichier automaticDestinations-ms est un OLE Compound File (CFB / MS-CFB).
Chaque flux numéroté contient un shell link (LNK) pour un élément récemment
utilisé, et un unique flux DestList fournit l'ordre, les horodatages et le nom
d'hôte d'origine.
Le conteneur externe : OLE Compound File
Le fichier suit le format Microsoft Compound File Binary (MS-CFB), le même conteneur de stockage structuré qui sous-tend les documents Office antérieurs à 2007. En interne, le fichier est divisé en secteurs de taille fixe (512 octets pour la plupart des jump lists), chaînés via une FAT, avec un mini-stream pour les entrées plus petites que 4096 octets. Un répertoire à un index de secteur connu liste les flux nommés (« storages » et « streams » dans la terminologie CFB).
Pour une Jump List, seul le répertoire vous intéresse. Vous verrez un ensemble
plat de flux : un par élément récent, nommé avec un nombre hexadécimal, plus un
unique flux DestList. Il n'y a pas de storages imbriqués.
Flux numérotés : un LNK par entrée
Chaque nom de flux numéroté est un entier hexadécimal en minuscules — 1, 2,
a, 1f, et ainsi de suite — et contient un shell link Windows standard, tel
que documenté dans [MS-SHLLINK]. Cela signifie que le même parseur LNK que
vous utilisez déjà pour les fichiers .lnk sur disque le décodera :
ShellLinkHeader, LinkTargetIDList optionnel, LinkInfo, les blocs StringData
(NAME_STRING, RELATIVE_PATH, WORKING_DIR, COMMAND_LINE_ARGUMENTS,
ICON_LOCATION), et les blocs ExtraData (TrackerDataBlock,
PropertyStoreDataBlock, et compagnie).
Le nom du flux est l'identifiant de l'entrée, et c'est ce qui relie chaque LNK à
une ligne du DestList.
Le flux DestList
DestList est l'index qui transforme le sac de LNKs en une liste ordonnée et
datée d'éléments récemment utilisés. Il commence par un en-tête de 32 octets
suivi d'une séquence d'enregistrements d'entrée de longueur variable.
DestList header (32 bytes, little-endian)
offset size field
0x00 4 version (0x01..0x04 observed; Win7=1, Win10+=3/4)
0x04 4 number of entries
0x08 4 number of pinned entries
0x0C 4 unused / reserved (often a float; varies by version)
0x10 4 last entry ID issued
0x14 4 unused / reserved
0x18 4 last revision number
0x1C 4 unused / reserved
Chaque entrée qui suit porte — dans l'ordre — les métadonnées nécessaires pour reconstruire d'où provient le LNK :
DestList entry (variable length)
field size notes
checksum / reserved 8 version-dependent
NewVolumeID (GUID) 16 target volume
NewObjectID (GUID) 16 target object (file)
BirthVolumeID (GUID) 16 original volume
BirthObjectID (GUID) 16 original object
NetBIOS hostname 16 ASCII, NUL-padded
entry ID 4 matches the numbered stream name
reserved 4
access count 4 IEEE-754 float; sentinel = pinned
last access FILETIME 8 100-ns ticks since 1601-01-01 UTC
entry pin status / reserved 4 layout differs by version
name length (chars) 2 UTF-16LE code units
name 2*N UTF-16LE, not NUL-terminated
trailer 4 only on DestList v3/v4
Les versions 3 et 4 (Windows 10 et ultérieures) ajoutent un petit trailer par
entrée et ajustent quelques champs réservés ; les noms et rôles des champs
ci-dessus sont stables, mais les offsets exacts varient légèrement entre
versions. Faites toujours un branchement sur la version de l'en-tête avant de
parser les entrées.
Entrées épinglées vs non épinglées
L'en-tête indique le nombre d'entrées épinglées, mais le marqueur d'épinglage
par entrée est encodé dans le champ access count. Les éléments non épinglés
stockent un float normalisé représentant la fréquence à laquelle l'utilisateur
a ouvert la cible. Les éléments épinglés stockent une valeur sentinelle —
historiquement 0xFFFFFFFF interprété comme un float 32 bits (NaN) — pour
indiquer que l'entrée est épinglée par l'utilisateur et que le compteur n'a pas
de sens. La sentinelle exacte et la position de tout flag d'épinglage
supplémentaire varient entre versions de DestList ; traitez donc le compteur
comme opaque jusqu'à avoir vérifié la version.
Notes pratiques de parsing
- Endianness. Tout est little-endian, y compris les GUIDs (
Data1/Data2/Data3sont little-endian ;Data4est un tableau d'octets). - FILETIME. Convertir avec
unix_seconds = (filetime / 10_000_000) - 11_644_473_600. Conservez-les en UTC ; les jump lists n'enregistrent pas de fuseau horaire. - Hostname. Le nom NetBIOS de 16 octets est le poste de travail qui a ouvert le fichier. Sur un domaine, il est inestimable pour corréler l'activité entre hôtes.
- Entry ID. Mettez en correspondance le
entry IDde 4 octets de chaque ligne DestList avec les noms de flux hexadécimaux du répertoire CFB ; c'est votre clé de jointure. - Décalage de version. Windows 7 produisait DestList v1. Windows 8/8.1 a introduit v3 ; Windows 10 et 11 émettent couramment v3 ou v4. Les anciens parseurs qui supposent la disposition v1 liront mal les fichiers modernes — lisez toujours l'en-tête en premier.
- Ordre. Ne supposez pas que les lignes du DestList sont dans l'ordre MRU.
Triez par
last access FILETIME(ou parlast entry IDmoins un offset, selon ce dont vous avez besoin).
Pour inspecter un vrai fichier sans écrire de code, déposez-en un sur le parseur dans le navigateur — il exécute un parseur Rust DestList + LNK compilé en WebAssembly, entièrement côté client. Pour le contexte sur l'origine de ces fichiers et leur intérêt pour une enquête, voir le primer forensique.