Registry Parser
All articles

RecentApps execution history: the RegRipper recentapps plugin

7 min read

RecentApps is one of the very few NTUSER execution artifacts that gives you both a launch count and a precise last-run timestamp from a single record. That combination is rare. Most per-user execution evidence is one or the other: a count with no time, or a time with no count. The RegRipper recentapps plugin pulls the RecentApps keys apart so you can read both. The catch is that RecentApps is a Windows 10-era artifact that comes and goes across builds, so before you lean on it, you need to know whether the host you are examining actually populated it.

Where it lives

The data sits in the user's NTUSER.DAT under an Explorer-adjacent path. RegRipper's plugin and most published references put it at:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentApps\

You will also see it referenced under the Search branch on some builds:

HKCU\Software\Microsoft\Windows\CurrentVersion\Search\RecentApps\

I have seen both paths in the wild and in tooling. Treat the exact branch as build-dependent and check both rather than assuming. The structure under either is the same: a set of GUID subkeys, one per tracked application.

RecentApps\
  {1AC14E77-02E7-4E5D-...}\
    AppId            = "Microsoft.Windows.Explorer"
    LaunchCount      = 14
    LastAccessedTime = <8-byte FILETIME>
    RecentItems\
      {child GUID}\
        ...
  {another GUID}\
    ...

Each GUID subkey is one application. The GUID is a per-app identifier minted by the shell, not something you decode into a path directly. The human-readable identity comes from the AppId value.

The three values that matter

For each app GUID subkey, three values carry the evidence:

  • AppId — a string identifying the application. Sometimes an AppUserModelID (Microsoft.Windows.Explorer, Microsoft.WindowsStore), sometimes a full path to the executable, sometimes a hashed token. It is the same family of identifiers you meet in JumpLists and the taskbar pinning data. Treat it as the join key against those artifacts, not as a guaranteed clean path.
  • LaunchCount — a DWORD. How many times the shell counted this app being launched. This is the count half of the rare count-plus-time pairing.
  • LastAccessedTime — a QWORD holding a Windows FILETIME (100-nanosecond ticks since 1601-01-01 UTC). This is the precise last-run half. Decode it as an 8-byte little-endian FILETIME, not as a Unix epoch.

Our parser reads exactly these. It pulls AppId as a string, takes LaunchCount as a numeric DWORD, and decodes LastAccessedTime from the raw 8 bytes as a FILETIME. It then surfaces four columns per app: AppId, Launch count, Last accessed (UTC), and the subkey's own Key last written (UTC), sorting most-recent-access first. If AppId is missing it falls back to the GUID subkey name so you never lose a row silently.

A parsed record reads like:

AppId:        Microsoft.Windows.Explorer
Launch count: 14
Last accessed: 2026-06-10 09:41:17 UTC
Key written:  2026-06-10 09:41:17 UTC

That single line tells you this app was launched fourteen times through the shell UI, most recently at the stated second. Compare that to the LastWrite-only artifacts where you would get the time but never the count, or to MUICache where you get presence but neither.

What it proves, and what it does not

RecentApps records launches that the Windows Search and Start UI registered. Think of it as a sibling of UserAssist: shell-driven, GUI-driven, per-user. If a user typed a name into Start, clicked a tile, or launched through the Search box, RecentApps is where the shell tallied it.

What it does not see is the same blind spot every shell-driven artifact has. Command-line launches, scheduled tasks, services, WMI process creation, and remote execution do not go through this path and do not appear here. If you want the full reasoning on why shell artifacts miss programmatic execution, the same logic in the UserAssist write-up applies verbatim. RecentApps is a window into deliberate user behavior, not into malware's behavior.

The attribution is clean for the same reason UserAssist's is clean: the data lives in one user's NTUSER.DAT. When you find a record, the user who owns the hive is the user who ran the app. No system-wide ambiguity, no "this binary existed somewhere" hand-waving.

The RecentItems subkeys

This is the part that earns RecentApps a place beyond "another count artifact." Under each app GUID, there is frequently a RecentItems subkey, and under that, further child GUID subkeys — one per document or item recently opened with that application.

Those child entries typically carry their own values: a path or link to the opened item, a display name, and their own access timestamps. The shape is the per-item analogue of the per-app structure above. In practice this lets you say not just "the user ran this app fourteen times, last on the 10th" but "and the last documents they opened in it were these, at these times."

That document-to-application linkage overlaps heavily with what JumpLists encode, and the two corroborate each other. Where JumpLists give you the rich destination data (full paths, volume IDs, MAC times embedded in the DestList), RecentApps gives you the launch count and the registry LastWrite cadence. Note that our current recentapps parser focuses on the app-level values — AppId, LaunchCount, LastAccessedTime — and does not yet expand the RecentItems children into rows. If you need the document links, walk the RecentItems subkeys directly in the tree view or reach for a JumpList parser, and treat the RecentApps RecentItems data as confirmation rather than your primary source.

The build-variation problem

Be honest with yourself about coverage. RecentApps appeared in the Windows 10 generation and is genuinely inconsistent across builds. On some builds the key is fully populated and reliable; on others it is sparse, present-but-empty, or absent because the relevant shell telemetry was disabled or moved. Microsoft reworked Start, Search, and the surrounding usage telemetry repeatedly through the 10 lifecycle, and RecentApps was caught in that churn. On later builds and into Windows 11, this specific tracking is widely understood to have been superseded by other telemetry, so do not expect parity with what you saw on a 2017-era 1709 image.

The practical rule: an empty or missing RecentApps key proves nothing about user activity. It may mean the user did nothing, or it may mean this build simply does not keep the artifact. Never read absence here as evidence of absence of execution. Confirm what the build does by checking whether RecentApps is populated for known-active applications before you cite it for a target one.

Pairing it up

RecentApps is a corroboration artifact. It is at its strongest when it agrees with, or fills a gap in, the rest of the execution timeline.

  • UserAssist is the closest sibling: same hive, same shell-launch scope, also count-plus-time. Where both exist, they should agree on which apps the user runs. Disagreements are interesting and worth chasing.
  • FeatureUsage tracks taskbar and Start interaction at a finer grain (focus, switches, clicks) and overlaps the same UI surface RecentApps watches. Use it to add interaction depth to a RecentApps launch count.
  • JumpLists carry the document destinations that RecentApps only gestures at through RecentItems, and tie back through the same AppId family.
  • Prefetch and AmCache give you per-host execution that, unlike RecentApps, is not tied to GUI launches — the cross-check that tells you whether a missing RecentApps entry is a build quirk or genuine non-use.

The point of the pairing is the same as always: no single NTUSER artifact is a complete execution log, but RecentApps contributes a count and a precise time, which is more than most of them manage alone.

Tools

  • RegRipper's recentapps plugin parses the GUID subkeys, decodes the LastAccessedTime FILETIME, and surfaces AppId and LaunchCount. Read the plugin source to see exactly which values it extracts on the build you are working from.
  • Eric Zimmerman's RECmd with an appropriate batch file will dump the same keys to CSV.
  • The parser on this site decodes RecentApps as part of its execution view, and you can analyze NTUSER.DAT in your browser without uploading the hive anywhere. The full plugin set is documented in the RegRipper plugins reference.

RecentApps will not carry a case on its own, and on the wrong build it will not carry anything at all. But when it is populated, a per-user launch count next to a second-precise last-run time is a combination worth reaching for — just confirm the build keeps it before you put weight on what is, or is not, there.