Registry Parser
All articles

Jump List forensics in the registry: the jumplistdata plugin

9 min read

Jump List forensics is one of those topics where everyone reaches for the on-disk *.automaticDestinations-ms files and forgets there is a registry side at all. The jumplistdata artifact, and the RegRipper jumplistdata plugin that reads it, is the part that lives inside NTUSER.DAT. It will not give you the rich per-file detail of the parsed Jump List files, but it gives you something they do not: a compact, timestamped index of which applications a user actually touched through the taskbar and Start menu, keyed by AppID. Used together, the registry value and the files answer "which programs did this user run, and which files did they open through them" with a precision that few other per-user artifacts match.

This post is about the registry half. I will be explicit about which part of the puzzle lives in the hive and which part lives in the files, because conflating the two is the most common way analysts misstate what a Jump List proves.

What lives in the registry

The value the plugin parses is under the user's NTUSER.DAT, at:

HKCU\Software\Microsoft\Windows\CurrentVersion\Search\JumpListData

Under that key you get a flat list of values. Each value name is an application AppID. Each value's data is an 8-byte FILETIME — the last time that application's Jump List was accessed, which in practice means the last time the user interacted with that program's entry on the taskbar or Start menu. That is the whole structure: name = AppID, data = one timestamp. No run count, no file list, no focus time. It is an index, not a log.

The RegRipper jumplistdata plugin reflects exactly this. It walks the JumpListData key, and for every value whose data is at least 8 bytes long it reads the FILETIME at offset 0 and emits one row: the AppID and the last-access time in UTC. The columns are deliberately minimal — "Application (AppID)" and "Last access (UTC)" — because that is all the registry value carries.

A worked note from the plugin's own output makes the contract clear: each value is an application AppID; the data is an 8-byte FILETIME of last access via the taskbar/jump list. If you see analysis tooling claiming run counts or file paths out of this key, it is inventing them.

A note on ProgramsCache and StartPage2

There is a related, often-cited registry location:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage2\ProgramsCache

with the ProgramsCacheSMP and ProgramsCacheTBP values (Start Menu Pinned and Taskbar Pinned, by the usual reading). These hold serialized shell item ID lists describing the pinned and recent layout of the Start menu and taskbar, and they are a legitimate Jump List adjacent artifact. I want to be precise here: the jumplistdata plugin as implemented reads the Search\JumpListData AppID-to-FILETIME index, not the StartPage2\ProgramsCache blobs. Other tooling parses ProgramsCache separately because its format is a different beast — nested SHITEMID structures rather than a flat FILETIME table. Treat them as two distinct registry artifacts that happen to describe overlapping behaviour (taskbar/Start interaction). If your case turns on pinned-item provenance, parse ProgramsCache; if it turns on last-touch timing per application, JumpListData is the cleaner source.

The AppID concept

The AppID is the hinge that ties the registry index to the on-disk files. An AppID is a hash (a CRC-64 variant, historically) derived from the application's executable path — or, for applications that set one explicitly, an Application User Model ID string the program declares to the shell. Two installs of the same binary at the same path produce the same AppID; the same binary at a different path produces a different one.

This matters because the AppID is also the filename of the on-disk Jump List:

%AppData%\Microsoft\Windows\Recent\AutomaticDestinations\<AppID>.automaticDestinations-ms

So a value named, say, 5f7b5f1e01b83767 in JumpListData corresponds — same AppID — to 5f7b5f1e01b83767.automaticDestinations-ms on disk. The registry tells you "this AppID was last touched at this time"; the file tells you "and here are the specific documents that application opened, with their own timestamps." The bridge is the AppID, and it is exact. There are well-known public AppID lists for common applications (Notepad, the various Office binaries, mstsc.exe, PowerShell) precisely because the hash is stable per path; mapping an unknown AppID back to a binary is a matter of hashing candidate paths until one matches, or consulting those lists.

What lives in the files

The AutomaticDestinations (and the user-pinned CustomDestinations) files are not in the registry at all. They are OLE compound files (the old structured-storage format) sitting in AppData\Roaming\Microsoft\Windows\Recent\. Inside each is a DestList stream that orders entries by recency and stores per-entry metadata, plus a series of streams that are, structurally, embedded LNK shortcuts. That is where the forensic richness lives:

  • Full target paths of files opened through the application.
  • The MAC timestamps captured at the time of access (created, modified, accessed of the target).
  • Volume serial numbers, droid/object IDs, and sometimes network paths — the same shell-link goodness you get from a LNK file.
  • Per-entry "last opened" times from the DestList.

So the division of labour is clean: the registry (JumpListData) gives you a per-application last-touch timestamp and a compact list of which AppIDs exist; the files give you the per-file detail behind each AppID. The registry is fast triage; the files are the deep dive.

What Jump Lists actually prove

A Jump List entry is created by shell interaction. When a user opens a file through an application that participates in the Jump List system — or pins an item, or the OS records a recent item for that app — the shell writes to the corresponding .automaticDestinations-ms file and updates the timing. So a Jump List proves three overlapping things:

  • Program execution — the application ran and interacted with the shell. The JumpListData FILETIME is your "last interacted" marker for that program.
  • File access — through the on-disk files, the specific documents the user opened with that application, with target metadata.
  • Pinned and recent items — what the user deliberately pinned versus what the system recorded as recent, distinguishing intentional workflow from incidental access.

What it does not prove, the same caveat that applies to UserAssist and friends: command-line and service-driven activity that never touches the shell will not create or update a Jump List. Absence is not evidence of non-execution. And the JumpListData value is last-touch only — it will not tell you how many times, only when last. For frequency, you go to the DestList in the file, or to other execution artifacts.

Forensic value: taskbar and Start interaction history

The reason to bother with the registry side is triage speed and attribution. JumpListData is inside the user's NTUSER.DAT, so attribution is unambiguous — the activity belongs to the profile that owns the hive. A single pass over the key gives you a sorted list of every application the user interacted with via taskbar or Start, newest first if you sort by the FILETIME. That is a one-glance behavioural profile: the remote-desktop client touched at 02:14, the archiver touched right after, a scripting host touched a minute later. You then pivot into the matching .automaticDestinations-ms file for the actual files involved.

Treat the FILETIME the way you treat any "last" timestamp: it is volatile. Re-running the application moves it and the previous value is gone from the live hive. Acquire once at a known time, and lean on VSS snapshots to reconstruct earlier states. The same discipline that applies to RecentDocs and UserAssist LastWrite analysis applies here.

Tools

  • RegRipper's jumplistdata plugin. Walks Software\Microsoft\Windows\CurrentVersion\Search\JumpListData and emits AppID plus last-access FILETIME per value. Minimal by design — it reports what the key holds and nothing more. The RegRipper source is on GitHub. See the RegRipper plugins reference for the full artifact catalog, and note that JumpListData and StartPage2\ProgramsCache are separate plugins for separate keys.
  • Jump List file parsers — Eric Zimmerman's JLECmd is the reference for the .automaticDestinations-ms and .customDestinations-ms files, resolving the DestList and the embedded LNK streams.
  • The parser on this site surfaces the JumpListData AppID/last-access pairs as part of its NTUSER.DAT tree view. You can analyze NTUSER.DAT in your browser with nothing uploaded.

A good Jump List workflow uses both halves: read JumpListData from the hive for the timeline of application interaction, then resolve each interesting AppID to its file for the document-level detail.

Frequently asked questions

Where is the Jump List registry data stored? In HKCU\Software\Microsoft\Windows\CurrentVersion\Search\JumpListData inside the user's NTUSER.DAT. Each value name is an application AppID; each value's data is an 8-byte FILETIME of last access via the taskbar or Start menu.

How is that different from the AutomaticDestinations files? The registry value is a compact index — AppID to a single last-access timestamp. The on-disk *.automaticDestinations-ms files in AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations\ are OLE compound files holding a DestList stream and embedded LNK shortcuts with full target paths and timestamps. Registry = index; files = detail.

What is an AppID? A stable identifier for an application, derived from its executable path (historically a CRC-64 hash) or set explicitly by the program. The same AppID names both the JumpListData value and the on-disk Jump List file, which is how the two link up.

Does a Jump List prove a program was executed? It proves shell interaction — the program ran and engaged the Jump List system, or the user pinned/opened items through it. Command-line, service, and scheduled-task launches that never touch the shell will not appear, so absence is not proof of non-execution.

Can I read jumplistdata online? Yes — load the NTUSER.DAT hive into Registry Parser and the JumpListData AppIDs and last-access times are decoded in the browser, with nothing uploaded.

Further reading

The registry side of Jump Lists is small, but it is the fastest way to get a per-user, timestamped list of which applications were touched through the taskbar and Start menu. Pair it with the AutomaticDestinations files and you have both the index and the detail — who interacted with what, when, and which files came along for the ride.