MountPoints2 and MountedDevices: the RegRipper mountpoints2 plugin
8 min read
USB forensics on Windows is mostly a system-wide story. USBSTOR tells you a device was plugged in; the SYSTEM hive records the vendor, product, and serial; the setup logs record the first connect. None of that answers the question a panel actually asks: which user account touched the device. mountpoints2 is the artifact that does. It lives in NTUSER.DAT, so when it has a record, the answer to "who mounted this volume" is the user who owns the hive. The RegRipper mountpoints2 plugin reads it, and pairing it with MountedDevices in the SYSTEM hive turns a volume GUID into a disk signature and, from there, into a specific physical drive.
Where it lives
The key is HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2 in the user's NTUSER.DAT. Under it you get one subkey per volume that user has mounted through Explorer. The subkey names come in three flavours:
- A volume GUID, like
{f7d8a3c0-4e21-11ee-9f2a-806e6f6e6963}. This is the common case for removable media and locally attached volumes. - A drive letter with a leading hash, like
CorE, recorded under theCPC\Volumestyle on some builds, though in practice the GUID form dominates for USB. - A mapped network share, written as
##servername#share(the UNC\\servername\sharewith backslashes rewritten as#).
Explorer creates these entries lazily, when the volume is browsed in the shell. That is the attribution hook: a volume only gets a per-user MountPoints2 entry if that user interacted with it through Explorer. A volume that was plugged in but never opened by a given user will sit in the system-wide USBSTOR list without ever appearing under that user's MountPoints2.
What the plugin actually returns
It is worth being honest about how thin the on-disk data is. The MountPoints2 subkeys are mostly empty shells; the forensic value is in the subkey name and the subkey LastWrite time, not in any value data. The RegRipper mountpoints2 plugin reflects that — it enumerates the subkeys and prints their names, separating the GUID-style entries from the ##server#share entries so you can read the network mounts at a glance.
The parser on this site does the same. The mountpoints2 plugin enumerates the subkeys of ...\Explorer\MountPoints2 and emits a single column, Mount point, one row per subkey name. There is no decoding to do at this layer because there is nothing encoded — the GUID is the data. The work happens when you carry that GUID over to the SYSTEM hive.
A typical output block looks like this:
{f7d8a3c0-4e21-11ee-9f2a-806e6f6e6963}
{a2c19b44-0fe0-11ef-83b1-94c691a7d2aa}
##fileserver#finance
##fileserver#hr$
Two USB volume GUIDs and two mapped drives. The mapped-drive lines are immediately useful on their own: ##fileserver#finance means this user mounted \\fileserver\finance at some point, and the $ on hr$ marks an administrative or hidden share. Those two lines alone can matter in a data-exfiltration case, no further correlation required.
What it proves, and what it does not
What MountPoints2 proves: a specific user account interacted with a specific volume through the shell. That is the attribution USBSTOR cannot give you. USBSTOR records the device at the machine level — it does not know which of five accounts on a shared workstation actually opened the drive. MountPoints2 sits in one user's hive and answers exactly that.
What it does not prove: timing with any precision, beyond the LastWrite heuristic below, and it does not prove a file was copied. It proves a mount, and a mount through Explorer. A volume accessed only from a command prompt or a script may not generate a MountPoints2 entry at all, the same way UserAssist misses command-line launches. Treat absence as inconclusive, never as proof of non-use.
The LastWrite-as-first-attach heuristic
Because Explorer creates the subkey the first time the user browses the volume and rarely rewrites it afterward, the subkey's LastWrite timestamp is widely read as a proxy for the first time that user mounted the volume. This is a heuristic, not a guarantee. The key can be rewritten — a re-mount under specific conditions, profile roaming, or shell behaviour that varies by build can all move it. Read the LastWrite as "this user first browsed this volume around here", corroborate it against the device's first-connect time in the SYSTEM setup logs and against ShellBags for the same volume, and state the uncertainty in the report. If three independent artifacts cluster within a minute, the cluster is the finding; the single LastWrite is not.
Crossing to MountedDevices
MountedDevices is a single key at the root of the SYSTEM hive — HKLM\SYSTEM\MountedDevices — and it is machine-wide, not per-user. It maps mount points to the storage they resolve to. The value names take two forms:
\DosDevices\X:— a drive letter assignment.\??\Volume{GUID}— a volume GUID, the same GUID format you saw under MountPoints2.
The value data is binary, and it comes in two shapes that you have to discriminate by length. The mounted_devices plugin on this site does exactly that:
- A 12-byte value is an MBR mapping: a 4-byte little-endian disk signature followed by an 8-byte partition offset. The plugin reads the signature as a hex value and the offset as a 64-bit integer, emitting something like
disk signature 0x1a2b3c4d, partition offset 0x100000. - Anything else is a UTF-16LE device path — for USB this looks like
\??\USBSTOR#Disk&Ven_...&Prod_...#<serial>#{GUID}, with the device serial number embedded in it.
That length check is the whole trick, and it is in the code: a 12-byte blob is decoded as signature plus offset, everything else is decoded as a UTF-16 string with the non-printable bytes stripped. The plugin reports three columns — Mount point, Type (MBR disk or Device path), and Decoded.
The correlation, end to end:
- From MountPoints2 in NTUSER.DAT you have a volume GUID and the user who mounted it.
- Look up
\??\Volume{<that GUID>}in MountedDevices. The data is either a 12-byte signature/offset pair, or a UTF-16 device path containing a USBSTOR serial. - If it is the device-path form, the embedded serial number ties the volume straight to the matching USBSTOR subkey — vendor, product, the works.
- If it is the 12-byte form, the disk signature is your pivot. Match that signature against the disk signature in the volume's NTFS boot record, against
\DosDevices\X:entries that carry the same signature to recover which drive letter the volume held, and against carved disk images.
So MountedDevices is the junction box: MountPoints2 gives you who and a GUID, MountedDevices turns the GUID into what — a serial or a signature — and USBSTOR turns the serial into a named device.
Contrast with the system-wide USBSTOR artifact
Lay them side by side. USBSTOR (and USB, and the SetupApi logs) is system-wide: it enumerates every device the machine has seen, with rich metadata — friendly name, serial, first/last connect — but no account attribution. MountPoints2 is per-user and metadata-poor: just a GUID or a UNC, plus a LastWrite, but it nails the account. Neither is sufficient alone. The complete USB story for a removable drive is:
- USBSTOR: this device, identified by serial, was attached to this machine.
- MountedDevices: this device, by serial or signature, was assigned this volume GUID and this drive letter.
- MountPoints2: this user browsed that volume GUID through Explorer.
Three hives, three artifacts, one device. Drop any one of them and you lose either the device identity, the volume mapping, or the attribution.
Building a cross-user USB timeline
The reason MountPoints2 is per-user is also why it builds timelines that USBSTOR cannot. On a multi-user host, parse every NTUSER.DAT — each profile, plus the Default and any service-account hives. For each, pull the MountPoints2 GUIDs and their LastWrites. Now group by GUID across users. A single USB volume GUID appearing under three different users, with three different LastWrite times, gives you the order in which those users first mounted that drive. That is a custody chain for the device, reconstructed from the registry alone.
The classic insider-threat shape: a finance workstation, one USB GUID that resolves through MountedDevices to a personal thumb drive's USBSTOR serial, and a MountPoints2 LastWrite under exactly one user's hive at 18:40 on a Friday. The device identity comes from SYSTEM; the time comes from the LastWrite; the name on the account comes from the hive. Corroborate the copy itself with ShellBags, LNK files, and jumplists, but the registry has already told you who and roughly when.
Tools
- RegRipper's
mountpoints2plugin (source) enumerates the MountPoints2 subkeys and splits the GUID entries from the##server#sharenetwork mounts. Run it against every NTUSER.DAT, not just the suspect's. - Pair it with a MountedDevices parser against the SYSTEM hive to resolve GUIDs to disk signatures and USBSTOR serials, and with the USBSTOR plugin to name the device. See the RegRipper plugins reference for the full set.
- You can analyze NTUSER.DAT in your browser on this site — the
mountpoints2andmounted_devicesplugins run client-side, so the hive never leaves your machine.
MountPoints2 will not stand alone in a report. It is a single, narrow fact — a user browsed a volume — and it leans on a LastWrite heuristic you should hedge. But it is the only common USB artifact that puts a named account next to a volume, and once you carry its GUID into MountedDevices and out to USBSTOR, you have the device, the mapping, and the person in one chain. For attribution, nothing else on the USB path comes close.