> Where you are: Part III, Chapter 16 of 40. Chapter 14 taught you to acquire a forensic image and prove it is unaltered; Chapter 15 taught you to triage a live or freshly-imaged system and pull the artifacts that matter first. Now you open that...
In This Chapter
- Why Windows is an examiner's favorite witness
- The registry as a forensic goldmine
- High-value registry artifacts
- Event logs: the system's signed statements
- Execution evidence: proving a program ran
- File and folder access: LNK files and Jump Lists
- $Recycle.Bin: what was deleted, when, and by whom
- Tool demonstration: the Zimmerman workflow and Autopsy
- Worked example: the engineer who covered their tracks
- Common mistakes
- Limitations: knowing when to stop
- Progressive project: extract and interpret the Windows artifacts in your case
- Summary
Chapter 16: Windows Forensics — Registry, Event Logs, Prefetch, and the Artifacts Windows Leaves Behind
Where you are: Part III, Chapter 16 of 40. Chapter 14 taught you to acquire a forensic image and prove it is unaltered; Chapter 15 taught you to triage a live or freshly-imaged system and pull the artifacts that matter first. Now you open that image and read what Windows actually recorded. This is the home chapter for anchor case #2 — the departing engineer who tried to cover their tracks — because no operating system on Earth keeps more receipts than Windows, and almost nobody who tampers with them knows where they all are.
Learning paths: This is the densest chapter for the 🔍 Forensic Examiner — registry, event logs, and execution artifacts are the daily bread of Windows DFIR. 🛡️ Incident Response lives here too: logon events, service installs, and autostart keys are how you find persistence and lateral movement. 📜 Legal/eDiscovery practitioners should read the USB-history and LNK/Jump List sections closely — they are the backbone of nearly every trade-secret and exfiltration case. 💾 Data Recovery technicians get less here than in Part II, but the registry will still tell you which devices held the lost data, and
$Recycle.Binrecovery is pure recovery work.
Why Windows is an examiner's favorite witness
Windows does not trust you to remember anything. It caches, it indexes, it pre-loads, it logs, it keeps "most recently used" lists for the convenience of a user who will never look at them, and it writes timestamps into a dozen places that no human ever reads. Every one of those conveniences is a forensic artifact. A clean Windows 10 or 11 installation, untouched by any user, already contains thousands of records describing the system's own configuration and history. Add a few months of ordinary use and you have a sprawling, redundant, cross-correlated archive of who did what, when, and with which device. The redundancy is the gift: when one artifact is wiped, three others usually corroborate what it would have said. That is the practical meaning of one of this book's recurring themes — every action leaves a trace, and the absence of a trace is itself a trace. On Windows, that theme is not an aspiration. It is the architecture.
Consider the anchor case for this chapter. A mid-sized engineering firm — call it the client — discovers that a senior mechanical engineer has given two weeks' notice to join a direct competitor. Three days before the engineer's last day, a project manager notices that a folder of proprietary CAD files for a turbine-housing design has been touched over a weekend. The firm's counsel asks a simple question with enormous legal consequences: did this employee copy our trade secrets to a personal device before leaving? You receive a forensic image of the engineer's Windows 10 workstation, acquired and hashed per Chapter 14, with a clean chain of custody. You will not interview anyone. You will not read minds. You will read the artifacts. By the end of this chapter you will know exactly which keys, logs, and files answer that question — and why the engineer's attempt to erase the answer with a "PC cleaner" tool, and to backdate the files, made the answer easier to prove, not harder.
That is the lesson the anchor exists to teach, and it is worth stating before we touch a single byte: anti-forensics rarely beats a thorough examiner. Tools that "clean" a Windows system clean the artifacts their authors thought of. They do not clean the ones they never heard of, and they cannot clean the artifact they themselves create by running. We will return to this engineer throughout the chapter and assemble the full timeline in the worked example near the end.
Why This Matters. Most digital evidence in the world sits on Windows. As of this writing Windows runs the overwhelming majority of business desktops and laptops, which means the overwhelming majority of corporate investigations, internal HR matters, IP-theft suits, and a large share of criminal cases land on a Windows image at some point. If you learn one operating system's artifacts deeply, learn this one. The principles transfer — Chapter 17 shows you the macOS and Linux equivalents — but the volume and richness of Windows artifacts is in a class of its own.
A map before the territory
This chapter is organized around the major artifact families, roughly in the order you would consult them in a real exam:
WINDOWS ARTIFACT FAMILIES (this chapter)
┌─────────────────────────────────────────────────────────────────────┐
│ THE REGISTRY What WAS configured / connected / used │
│ SAM → local user accounts, last logon, login counts │
│ SYSTEM → hardware, USB device history, mounted volumes, services │
│ SOFTWARE → installed programs, OS version, autostart (machine-wide) │
│ NTUSER.DAT → per-user: RecentDocs, TypedURLs, RunMRU, UserAssist │
│ USRCLASS.DAT → per-user: ShellBags (folder browsing history) │
├─────────────────────────────────────────────────────────────────────┤
│ EVENT LOGS (.evtx) What HAPPENED, with system timestamps │
│ Security → logons 4624/4625, account changes, log clears 1102 │
│ System → service installs 7045, boots/shutdowns, driver loads │
│ Application → app crashes, installer activity │
├─────────────────────────────────────────────────────────────────────┤
│ EXECUTION EVIDENCE What programs RAN │
│ Prefetch (.pf) → ran at least once, run count, last 8 run times │
│ Amcache.hve → program present + SHA-1 hash + compile time │
│ ShimCache → program present, path, $SI mod time (NOT exec time)│
│ BAM/DAM, UserAssist → per-user last-execution times │
├─────────────────────────────────────────────────────────────────────┤
│ FILE & FOLDER ACCESS What files/folders were OPENED │
│ LNK files → a file was opened (even from a removed device) │
│ Jump Lists → which app opened which file, when │
│ ShellBags → which folders were browsed (even deleted ones) │
│ $Recycle.Bin → what was deleted, from where, when, by whom │
└─────────────────────────────────────────────────────────────────────┘
Keep this map in mind. The skill of Windows forensics is less about memorizing one magic key and more about correlation — knowing that USB history in SYSTEM is confirmed by MountPoints2 in NTUSER.DAT, corroborated by a LNK file with a matching volume serial, and time-anchored by a Jump List entry. One artifact is a lead. Three that agree is a finding.
The registry as a forensic goldmine
New examiners imagine the Windows Registry as a single mysterious database living somewhere inside the operating system. It is not single, and it is not mysterious. The registry you see in regedit.exe on a live machine is a runtime assembly — Windows mounts several separate files, called hives, and presents them under a unified tree of root keys (HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, and so on). On a dead-box image there is no regedit view and no HKEY_CURRENT_USER. There are only the hive files on disk, and your job is to know where they live, extract them, and parse them offline.
Where the hives live
The machine-wide hives sit in one directory:
C:\Windows\System32\config\
├── SAM → mounts as HKLM\SAM (local accounts, password hashes)
├── SECURITY → mounts as HKLM\SECURITY (LSA secrets, policy)
├── SYSTEM → mounts as HKLM\SYSTEM (hardware, devices, services)
├── SOFTWARE → mounts as HKLM\SOFTWARE (installed apps, OS settings)
├── DEFAULT → mounts as HKU\.DEFAULT (default user profile)
└── *.LOG, *.LOG1, *.LOG2 ← transaction logs (DO NOT ignore — see below)
The per-user hives sit inside each user's profile:
C:\Users\<username>\
├── NTUSER.DAT → mounts as HKU\<SID> (HKCU when that user is logged on)
└── AppData\Local\Microsoft\Windows\
└── UsrClass.dat → mounts as HKU\<SID>_Classes (per-user classes + ShellBags)
Every user who has logged in has their own NTUSER.DAT and UsrClass.dat. In a multi-user investigation, which hive an artifact came from is itself evidence — it attributes the activity to a specific account. The mapping from the path you see in tools (HKCU\Software\...) to the file on disk (NTUSER.DAT\Software\...) is something you should be able to recite under cross-examination, because opposing counsel will ask how you know an artifact belongs to this user and not the administrator.
Chain of Custody. You never open hives on the original drive. You extract them from your verified image — with The Sleuth Kit (
icatagainst the$MFTrecord number), with a forensic suite's file browser, or by mounting the image read-only — and you record the source. A defensible note reads: "ExtractedNTUSER.DATfor userjriverafrom imageWS-ENG-04.E01(SHA-256a3f1…), MFT entry 74213, to working copy; working copy MD5b9c2…." Now every artifact you cite is traceable back to a hashed image. See Chapter 14 — Forensic Acquisition for the imaging workflow and Chapter 5 — The Forensic Process for the chain-of-custody fundamentals.
Dirty hives and transaction logs
Here is a mistake that has cost examiners real findings. When you copy SYSTEM off an image, you may be copying a hive that was not cleanly flushed — the live system kept recent changes in the transaction logs (SYSTEM.LOG1, SYSTEM.LOG2) and had not yet merged them into the primary file. Such a hive is dirty. The primary-sequence and secondary-sequence numbers in the hive header do not match (more on the header below), and the most recent registry changes — possibly the exact ones you care about — live only in the .LOG files.
Modern parsers handle this for you if you give them the logs. Eric Zimmerman's RECmd/Registry Explorer will replay the transaction logs against a dirty hive when the .LOG1/.LOG2 files are present in the same directory. Older tools, or a careless extraction that grabbed only SYSTEM and not its logs, will silently show you a stale view. Always extract the hive and its transaction logs together.
SYSTEM ← primary hive (may be stale)
SYSTEM.LOG1 ← uncommitted changes ┐ replay these against SYSTEM
SYSTEM.LOG2 ← uncommitted changes ┘ to get the true, current state
Inside a hive: the binary structure
You do not need to parse hives by hand — tools do it — but you must understand the structure, because two of the most important pieces of registry evidence are not values at all: they are the last-write timestamps on keys, and they come straight from this binary format.
A hive file begins with a 4,096-byte base block (the header), followed by one or more 4,096-byte hive bins (hbin) that contain the actual cells: key nodes, value records, security descriptors, and subkey lists.
HIVE FILE LAYOUT
Offset 0x0000 ┌────────────────────────────────────────────┐
│ BASE BLOCK (4096 bytes) │
│ 0x00 "regf" signature (72 65 67 66) │
│ 0x04 primary sequence number ┐ equal ⇒ │
│ 0x08 secondary sequence number ┘ clean hive │
│ 0x0C last-written FILETIME (8 bytes) │
│ 0x14 major version 0x18 minor version │
│ 0x24 root cell offset │
│ 0x30 hive name (UTF-16, partial path) │
└────────────────────────────────────────────┘
Offset 0x1000 ┌────────────────────────────────────────────┐
│ HBIN #1 "hbin" (68 62 69 6E) │
│ ┌── nk cell "nk" (6E 6B) = a key node │
│ │ • last-write FILETIME for THIS key │
│ │ • offset to subkey list, value list │
│ ├── vk cell "vk" (76 6B) = a value │
│ │ • name, data type, data/offset │
│ ├── sk cell "sk" = security desc │
│ └── lf/lh/li/ri = subkey indexes │
└────────────────────────────────────────────┘
A real header looks like this in a hex viewer:
Offset 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII
00000000 72 65 67 66 12 0A 00 00 12 0A 00 00 a1 7c 3d c8 regf.........|=.
└─ "regf" ─┘ └ seq pri ┘ └ seq sec ┘ └ last-written
00000010 76 4f d9 01 01 00 00 00 05 00 00 00 00 00 00 00 vO..............
FILETIME ──┘ └ major=1 ┘ └ minor=5 ┘
00000020 01 00 00 00 20 00 00 00 ... .... ...
└file fmt=1┘ └root cell┘
Two facts to carry away. First, seq pri == seq sec here (0x0A12 == 0x0A12), so this hive was cleanly written — no log replay needed. If they differed, you would replay the logs. Second, every nk (key) cell carries its own last-write FILETIME. That is the single most useful timestamp in the registry, and the next section is built on it.
The last-write time: the registry's hidden clock
A FILETIME is a 64-bit count of 100-nanosecond intervals since midnight, 1 January 1601 UTC. Windows uses it everywhere — in the registry, in NTFS, in LNK files, in $Recycle.Bin metadata. You will convert FILETIMEs constantly, so internalize the arithmetic once:
# FILETIME (Windows 100-ns ticks since 1601-01-01 UTC) -> Python datetime (UTC)
# This is illustrative reference code; in practice the parsers do this for you.
import datetime
def filetime_to_utc(ft: int) -> datetime.datetime:
# 116444736000000000 = number of 100-ns intervals between 1601-01-01 and 1970-01-01
EPOCH_DIFF = 116444736000000000
unix_100ns = ft - EPOCH_DIFF
seconds, rem = divmod(unix_100ns, 10_000_000)
return datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc) \
+ datetime.timedelta(seconds=seconds, microseconds=rem // 10)
# Bytes a1 7c 3d c8 76 4f d9 01 are little-endian; assemble the 64-bit value:
raw = bytes.fromhex("a17c3dc8764fd901")
ft = int.from_bytes(raw, "little") # = 0x01d94f76c83d7ca1
print(filetime_to_utc(ft)) # -> a UTC datetime in 2023
Every registry key has exactly one last-write time: the moment its values or subkeys were last modified. That is a blessing and a trap. It is a blessing because for keys that hold a single meaningful event — say, the per-user MountPoints2\{GUID} key that records a user mounting a specific volume — the last-write time is effectively "the last time that thing happened." It is a trap because for keys that hold many values, the last-write time tells you only when the key was last touched, not when each individual value was written. We will flag that limitation again under "Limitations." For now: the last-write time is your friend, but it answers a narrower question than beginners assume.
Recovery vs. Forensics. The registry serves both disciplines, and the same key reads differently depending on your job. A 🔍 forensic examiner reads
HKLM\SYSTEM\…\Enum\USBSTORto prove a particular thumb drive was connected — vendor, product, serial, dates — as an element of an exfiltration claim. A 💾 recovery technician reads the very same key to find the device that held the lost data: a client says "the photos were on a little silver SanDisk," andUSBSTORplusMountedDevicestells you the exact model and serial to ask them to bring in for imaging. Same bytes; one purpose is admissibility, the other is restoration.
High-value registry artifacts
You could spend a career in the registry. In practice a handful of keys carry most investigations. We will walk the ones every examiner must know, grouped by what they prove.
SAM — local accounts and logon history
HKLM\SAM\SAM\Domains\Account\Users\ holds one subkey per local account (named by relative ID, e.g., 000003E9). Parsed, each gives you the username, the account creation date, the SID, the last login timestamp, the last password change, the login count, and account flags (disabled, locked, password-not-required). On a domain-joined machine the domain accounts are authenticated by a domain controller and will not be fully described here — but the local accounts, including any quietly-created backdoor account, will be. A freshly created local administrator account with a recent creation date and a login count of 2 is the kind of thing that breaks an "I never touched that server" defense.
Legal Note.
SAMalso stores password-hash material. Cracking a custodian's password to access their own encrypted data may be perfectly lawful under the warrant or engagement that authorized the exam — or it may exceed your authority and implicate other statutes. Authority and scope are decided in Chapter 25 — The Legal Framework, not improvised at the keyboard. Note what you can do; do only what you are authorized to do.
SYSTEM — devices, the great USB story, and services
SYSTEM is where most exfiltration cases are won, because it remembers external storage. The corroborating keys form a chain you should be able to draw from memory:
USB DEVICE CORRELATION (SYSTEM hive + per-user NTUSER.DAT)
(1) SYSTEM\CurrentControlSet\Enum\USBSTOR\
Disk&Ven_SanDisk&Prod_Cruzer_Glide&Rev_1.00\
4C530001234567890123\ ← the device SERIAL (instance ID)
...\Properties\{83da6326-...}\
0064 = first install FILETIME
0066 = last arrival FILETIME (last time plugged in)
0067 = last removal FILETIME (last time pulled out)
(2) SYSTEM\MountedDevices
\DosDevices\E: → binary contains "...USBSTOR#...4C53000123...#..."
\??\Volume{9f3a...} → same device ← gives the VOLUME GUID
(3) NTUSER.DAT\...\Explorer\MountPoints2\{9f3a...}
last-write time ≈ last time THIS USER mounted that volume ← attribution!
Read the chain top to bottom. USBSTOR tells you a SanDisk Cruzer Glide with serial 4C530001234567890123 was connected, and the device Properties subkey gives first-install, last-arrival, and last-removal FILETIMEs (Windows 8 and later). MountedDevices links that device to a drive letter (E:) and a volume GUID. Then MountPoints2, which lives in a user's NTUSER.DAT, contains that same volume GUID — which means this specific user account mounted that volume, and the key's last-write time approximates when. You have moved from "a device was plugged into this computer" to "this user mounted this device at this time." That attribution leap is the heart of an IP-theft case.
A crucial caveat about serial numbers. The instance ID under USBSTOR is the device's serial — unless the second character is an ampersand (&). If it is, the device did not report a unique serial and Windows generated one. A Windows-generated ID is not globally unique, so you cannot reliably track that device across machines. State this in your report when it applies; do not overclaim cross-machine identity for a &-serial device.
4C530001234567890123 ← real serial (2nd char "C"): trackable across machines
7&1c2e3f4&0 ← Windows-generated (2nd char "&"): NOT a unique serial
Two more SYSTEM facts. First, on a dead-box image there is no CurrentControlSet — that symlink only exists at runtime. You read ControlSet001 (and sometimes ControlSet002), and you check HKLM\SYSTEM\Select\Current to learn which set was current at shutdown. Second, SYSTEM\CurrentControlSet\Services is the master list of services and drivers, including their start type and binary path. A service whose ImagePath points at a file in C:\Users\…\AppData\…\Temp\ is a screaming persistence indicator for 🛡️ incident responders; it pairs with System-log event 7045 (service installed), covered below. There is also SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ and the friendly volume names in SOFTWARE\Microsoft\Windows Portable Devices\Devices, which often give you the label the user gave their thumb drive ("BACKUP", "JR-PERSONAL") — a small human detail that juries remember.
Tool Tip. The plaintext log
C:\Windows\inf\setupapi.dev.logrecords the first time each device driver was installed, with a timestamp, in readable text. It is a fast, no-parsing-required confirmation of a device's first-connect time and a useful cross-check against theUSBSTORProperties FILETIME. Grab it whenever USB history matters.
SOFTWARE — what was installed, and machine-wide autostart
SOFTWARE answers "what programs lived on this machine and what runs at boot." The OS build and install date are under Microsoft\Windows NT\CurrentVersion (ProductName, CurrentBuild, InstallDate). Installed applications appear under Microsoft\Windows\CurrentVersion\Uninstall\. Machine-wide autostart — every IR examiner's first stop for persistence — lives in the ASEPs (Auto-Start Extensibility Points):
SOFTWARE\Microsoft\Windows\CurrentVersion\Run ← runs at every logon
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce ← runs once, then deletes itself
SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
SYSTEM\CurrentControlSet\Services ← service/driver autostart
NTUSER.DAT\...\CurrentVersion\Run ← per-user autostart
Crucially for our anchor, SOFTWARE\Piriform\CCleaner exists if CCleaner was ever installed, and it stores the tool's configuration — including options like "wipe free space" and the last-run settings. The mere presence of that key, with its last-write time, is the first thread we pull in the worked example.
NTUSER.DAT — the diary of a single user
If SYSTEM is the machine's logbook, NTUSER.DAT is the user's diary. A short tour of the keys that close cases, all rooted at Software\Microsoft\Windows\CurrentVersion\Explorer\ unless noted:
RecentDocs— recently opened documents, grouped into subkeys by extension (.docx,.pdf,.sldprt…). Each value is binary (the filename in UTF-16 plus a reference to the matching LNK), and theMRUListExvalue encodes the order they were opened, most-recent first. The extension subkey's last-write time is the moment the most-recent file of that type was opened.TypedURLs(andTypedURLsTime) — URLs typed into the Internet Explorer/Edge-legacy address bar,url1being most recent. Even in a Chrome-centric world this catches the moment someone typed a cloud-storage or webmail address by hand. Browser-native history is Chapter 18's domain; this is the registry's parallel record.TypedPaths— paths typed into the File Explorer address bar (e.g.,\\fileserver\share,E:\). Direct evidence a user navigated to a network share or removable drive by hand.RunMRU— commands typed into the Win+R Run box (cmd,\\10.0.0.5\c$,powershell), withMRUListordering. A favorite of IR for spotting hands-on-keyboard activity.WordWheelQuery— terms typed into the File Explorer search box. People search for what they intend to take ("turbine", "salary", "passwords").UserAssist— underUserAssist\{GUID}\Count, Windows logs GUI-launched programs with a run count, last execution time, and focus time. The value names are ROT-13 encoded (a trivial obfuscation, not encryption — tools decode it instantly). The GUID{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}covers executables;{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}covers shortcut launches. UserAssist is per-user execution evidence — it ties "this program ran" to "this account ran it."
There is also a powerful modern execution artifact that lives in SYSTEM, not NTUSER.DAT, but is per-user in spirit: BAM/DAM (Background/Desktop Activity Moderator) under SYSTEM\CurrentControlSet\Services\bam\State\UserSettings\<SID>\. It lists executable full paths with a last-execution FILETIME, per user SID. On Windows 10 and 11 it is one of the cleanest "this user ran this exe at this time" sources you have.
USRCLASS.DAT and ShellBags — the folders someone browsed
ShellBags are among the most underappreciated and most powerful Windows artifacts. When a user opens a folder in Explorer, Windows stores that folder's view preferences — window size, position, sort order, icon mode — so it can restore them next time. To do that it must record that the folder was visited at all, and it records the path, structured as a tree, with embedded timestamps. The forensic payload is enormous: ShellBags can prove a user browsed a folder that no longer exists — a folder on a thumb drive that was unplugged and taken home, a network share that was disconnected, a folder the user later deleted.
On Windows 7 and later the primary ShellBags live in UsrClass.dat:
USRCLASS.DAT\Local Settings\Software\Microsoft\Windows\Shell\BagMRU ← the folder tree
USRCLASS.DAT\Local Settings\Software\Microsoft\Windows\Shell\Bags ← the view settings
(older / additional entries also in NTUSER.DAT\Software\Microsoft\Windows\Shell\)
BagMRU is a nested set of keys mirroring the folder hierarchy the user navigated. Each node holds a binary shell item (a PIDL fragment) that encodes the folder name and, for filesystem folders, DOS-format modified/accessed/created timestamps. Parsed by a tool like ShellBags Explorer, the tree reconstructs every path the user opened — including E:\ProjectArchive\TurbineHousing\ on a drive that is sitting in the engineer's pocket as you read the image. That is exactly the artifact our anchor case turns on.
Try This. On a practice image (see Appendix J — Practice Images and Lab Setup), extract
UsrClass.datand run it through ShellBags Explorer. Find a path on removable media (drive letter other thanC:). Notice that the folder structure persists even though the device is long gone. Then ask the question every report must answer: does this prove the files were copied, or only that the folders were viewed? Hold that distinction — it returns under "Limitations."
Event logs: the system's signed statements
Where the registry tells you about state — what is configured, what is connected — the event logs tell you about events, each stamped with a time the system itself recorded. Since Windows Vista the logs are stored in a binary XML format, .evtx, here:
C:\Windows\System32\winevt\Logs\
├── Security.evtx ← logons, privilege use, account & policy changes
├── System.evtx ← service installs, driver loads, boots/shutdowns
├── Application.evtx ← application and installer events, crashes
└── Microsoft-Windows-*.evtx ← dozens of specialized operational logs
An .evtx file begins with the signature ElfFile\0 (hex 45 6C 66 46 69 6C 65 00); records are organized into 64-KB chunks marked ElfChnk\0, and each event record starts with **\0\0 (2A 2A 00 00). You will rarely carve these by hand, but recognizing the magic bytes lets you spot an .evtx file (or fragment) in unallocated space.
The Security log: who logged on, and how
Logon and account events are the backbone of intrusion and insider cases. The event IDs you must know cold:
SECURITY LOG — events every examiner memorizes
4624 Successful logon (carries a LOGON TYPE — see below)
4625 Failed logon (failure reason / status code)
4634 Logoff
4647 User-initiated logoff
4648 Logon using explicit credentials (RunAs / "Run as different user")
4672 Special privileges assigned (≈ an administrative logon)
4688 Process creation (if audited; logs command line if configured)
4720 User account CREATED
4722 Account enabled 4724 password reset 4726 account DELETED
4732 Member added to a security-enabled LOCAL group (e.g., Administrators)
1102 THE SECURITY LOG WAS CLEARED ← always significant
The logon type field on event 4624 is what turns "someone logged on" into a story:
LOGON TYPE meaning
2 Interactive at the physical keyboard
3 Network accessed a share/resource over the network (SMB)
4 Batch scheduled task
5 Service a service started under this account
7 Unlock unlocked an already-logged-on session
8 NetworkCleartext credentials sent in the clear (e.g., basic auth)
9 NewCredentials RunAs /netonly
10 RemoteInteractive RDP / Terminal Services ← classic remote access
11 CachedInteractive logged on with cached domain creds (laptop offline)
A burst of 4625 failures (type 3 or 10) followed by a 4624 success is a brute-force that worked. A 4624 type 10 from an unfamiliar source at 3 a.m. is RDP you need to explain. A 4672 right after a 4624 means the session has admin rights. And a 1102 — the Security log was cleared — is itself a loud event: clearing the log is an action, the action is logged (event 1102 records who cleared it and when), and the gap that the clearing leaves is, once again, a trace of the absence of traces.
Why This Matters. Event timestamps are recorded by the operating system at the moment of the event, using a high-resolution clock, and they are far harder for an ordinary user to forge than the file timestamps shown in Explorer. That makes the Security log one of your most trustworthy time anchors. When file timestamps and event-log timestamps disagree, your default hypothesis is that the file timestamps were manipulated — which is precisely what happened in the anchor case.
The System log: services, drivers, boots
The System log carries the machine's operational heartbeat. The high-value IDs:
SYSTEM LOG
7045 A new SERVICE was installed ← top persistence indicator (pair w/ Services key)
7034 Service crashed unexpectedly
7035 / 7036 Service control / state change (start/stop)
6005 Event Log service STARTED ≈ system boot
6006 Event Log service STOPPED ≈ clean shutdown
6008 Previous shutdown was UNEXPECTED (crash / power loss)
1074 Shutdown/restart initiated (by user or process — names the initiator)
104 A log file was CLEARED (System or other non-Security logs)
Boots and shutdowns (6005/6006/6008) let you bound when the machine was on, which constrains when interactive activity could have occurred — a useful sanity check against any timeline. A 7045 service install at an odd hour, with an ImagePath in a user temp directory, is the kind of single line that unwinds an entire intrusion.
# Illustrative: pull successful interactive/RDP logons from a Security log.
# (Run against an EXTRACTED copy, never the live original on the evidence drive.)
Get-WinEvent -Path 'E:\evidence\Security.evtx' -FilterXPath "*[System[(EventID=4624)]]" |
ForEach-Object {
$x = [xml]$_.ToXml()
$d = @{}; $x.Event.EventData.Data | ForEach-Object { $d[$_.Name] = $_.'#text' }
if ($d['LogonType'] -in '2','10') {
[pscustomobject]@{
Time = $_.TimeCreated
User = $d['TargetUserName']
LogonType = $d['LogonType'] # 2 = interactive, 10 = RDP
Source = $d['IpAddress']
Logon_ID = $d['TargetLogonId']
}
}
} | Sort-Object Time | Format-Table -Auto
Tool Tip. For batch parsing across many
.evtxfiles, Eric Zimmerman's EvtxECmd normalizes events into a single CSV with consistent columns and a curated set of "maps" that extract the meaningful fields per event ID — far faster than clicking through Event Viewer. Load the CSV into Timeline Explorer and you can filter thousands of logons in seconds. We meet the broader timeline tooling (plaso/log2timeline) in Chapter 21 — Timeline Analysis.
Execution evidence: proving a program ran
"Did this program execute on this machine?" is one of the most common questions in both IR and insider cases — did the ransomware run, did the data-staging tool run, did the wiper run. Windows answers it from several independent sources, and the art is knowing what each one actually proves, because they are subtly different.
Prefetch — the gold standard for "it ran"
To speed up application launches, Windows monitors what files and code pages a program touches in its first ~10 seconds and writes a prefetch file so the next launch can pre-load them. Each prefetch file is named for the executable plus an eight-hex-digit hash of the path it ran from:
C:\Windows\Prefetch\
CCLEANER64.EXE-A1B2C3D4.pf
└────┬─────┘ └───┬───┘
exe name hash of full path (so the SAME exe run from C:\ and from E:\
produces TWO different .pf files — itself a useful signal)
The forensic value is direct: a prefetch file's existence means that executable ran at least once. Parsed, it gives a run count, the file's create time (≈ first run) and last-modified time (≈ most recent run), and on Windows 8 and later the last eight run times. It also lists the files and directories the program loaded — which can reveal what a tool touched (a wiper's prefetch lists the volumes it walked; an archiver's lists the files it read).
The on-disk format is "SCCA." On Windows 10/11 the file is first compressed with Xpress-Huffman and starts with the signature MAM\x04 (4D 41 4D 04); after decompression you find the version and the SCCA magic:
Windows 10/11 prefetch, on disk:
00000000 4D 41 4D 04 ... "MAM\x04" → compressed; PECmd decompresses for you
After decompression (the SCCA structure):
00000000 1E 00 00 00 53 43 43 41 ... version 0x1E (30 = Win10/11), "SCCA"
└ ver=30 ┘ └ "SCCA" ┘
Version numbers map to OS generations: 0x11 (XP), 0x17 (Vista/7), 0x1A (8/8.1), 0x1E (10/11). Parse it with PECmd:
PECmd.exe -f "CCLEANER64.EXE-A1B2C3D4.pf"
Executable name: CCLEANER64.EXE
Run count: 3
Last run: 2024-03-16 09:14:22 (most recent)
Other run times: 2024-03-12 18:02:55, 2024-03-09 08:41:10
Volume 0: \VOLUME{01d94f...-...} Serial: 9C2A-77F1 Created: 2024-03-09 08:40:58
Files referenced (excerpt):
\WINDOWS\SYSTEM32\NTDLL.DLL
\PROGRAM FILES\CCLEANER\CCLEANER64.EXE
\USERS\JRIVERA\APPDATA\LOCAL\TEMP\...
That single output — CCleaner ran three times, most recently the Saturday morning after the suspect weekend — is a load-bearing fact in the anchor case. Note the limit, though: prefetch must be enabled (it usually is on Windows clients, controlled by EnablePrefetcher under SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters), and it is frequently disabled on servers and sometimes on SSD-only systems. No prefetch entry is not proof a program never ran — see "Limitations."
Amcache — presence plus a SHA-1 hash
C:\Windows\AppCompat\Programs\Amcache.hve is itself a registry hive (parse it like any other). Its Root\InventoryApplicationFile\ subkeys describe executables that have been present on the system, and — uniquely — each entry includes the file's SHA-1 hash, full path, size, and the PE compile (link) timestamp. The SHA-1 is gold: it lets you identify a known-bad binary by hash even if the file itself was later deleted, and it lets you confirm two machines ran the same tool. Parse with AmcacheParser:
AmcacheParser.exe -f "Amcache.hve" --csv .
Path SHA1 LinkDate
C:\Program Files\CCleaner\CCleaner64.exe 5f1a...e93c 2024-01-18 ...
C:\Users\jrivera\Downloads\sdelete64.exe b7d2...10aa 2023-09-05 ...
Treat Amcache as strong evidence of presence/installation, not airtight proof of execution. The distinction matters in court and we draw it carefully under "Limitations."
ShimCache — present, with a path and a modified time
The Application Compatibility Cache, or ShimCache (a.k.a. AppCompatCache), lives in a single binary value:
SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache → "AppCompatCache"
It records executables the system encountered, storing each one's full path and its $STANDARD_INFORMATION last-modified time (the file's mod time — not the time it executed). Entries are ordered most-recently-used first. Two facts trip up beginners and delight cross-examining attorneys:
- The stored timestamp is the file's modification time, not an execution time. Reporting a ShimCache timestamp as "the program ran at 14:07" is wrong and impeachable.
- On Windows 8 and later there is no reliable execution flag. A ShimCache entry proves the file existed and was seen by the system; it does not, by itself, prove the file ran. (On Windows 7 an execution flag existed; do not assume the same on 10.)
There is also a timing subtlety: ShimCache lives in memory during the session and is flushed to the registry at shutdown. So the most recent activity may not appear in the on-disk hive until the machine reboots — and a triage capture from Chapter 15 — Live Response and Triage of memory may hold ShimCache entries the disk hive lacks.
EXECUTION ARTIFACTS — what each one ACTUALLY proves
┌──────────────┬───────────────────────┬───────────────────────────────────┐
│ Artifact │ Proves │ Key gotcha │
├──────────────┼───────────────────────┼───────────────────────────────────┤
│ Prefetch │ EXECUTED (≥1 time) │ Often off on servers/SSDs │
│ │ + run count + 8 times │ │
│ Amcache │ PRESENT + SHA-1 + │ Presence ≠ proof of execution │
│ │ compile time │ │
│ ShimCache │ PRESENT + path + │ Timestamp = file MOD time, NOT │
│ │ $SI mod time │ run time; flushed at SHUTDOWN │
│ UserAssist │ EXECUTED via GUI, │ Per-user; GUI launches only │
│ │ per user + run count │ (not command-line) │
│ BAM/DAM │ EXECUTED, per user, │ Recent window only │
│ │ last-run time │ │
└──────────────┴───────────────────────┴───────────────────────────────────┘
Read that table as a single sentence you can say on the stand: Prefetch, UserAssist, and BAM indicate execution; Amcache and ShimCache indicate presence. Together they corroborate; individually they have limits.
File and folder access: LNK files and Jump Lists
The registry's RecentDocs tells you a file was opened. The LNK files and Jump Lists tell you the same thing with far more detail — including, critically, details about where the file lived, which is how you prove a file was on a removable device that is no longer present.
LNK shortcut files
Windows auto-creates a shortcut (.lnk) in the user's Recent folder whenever a file is opened:
C:\Users\<user>\AppData\Roaming\Microsoft\Windows\Recent\*.lnk
A LNK file is a rich little container. Its header is fixed: 4 bytes 4C 00 00 00 (header size 0x4C = 76), immediately followed by the Link CLSID 00021401-0000-0000-C000-000000000046:
00000000 4C 00 00 00 01 14 02 00 00 00 00 00 C0 00 00 00 L...............
└ 0x4C ──┘ └─ CLSID 00021401-0000-0000-C000-...
00000010 00 00 00 46 ... ...F
Parsed (with LECmd), a LNK gives you: the target's full path, the target's size, the target's MAC timestamps as of the last time the shortcut was updated, the volume serial number and volume label of the drive the target was on, the drive type (fixed vs. removable), any network share path, and the source machine's NetBIOS name. The payoff: a LNK in Recent\ pointing at E:\ProjectArchive\TurbineHousing_v7.sldprt, carrying volume serial 9C2A-77F1 and drive type "removable," proves that file was opened from a removable device with that serial — even though the device left the building. Match that serial to the prefetch volume serial and to USBSTOR, and the device, the user, and the file are bound together.
Jump Lists
Jump Lists power the "recent files" you see when you right-click a taskbar icon. They are stored per application:
C:\Users\<user>\AppData\Roaming\Microsoft\Windows\Recent\
AutomaticDestinations\<AppID>.automaticDestinations-ms ← auto, OLE/CFB container
CustomDestinations\<AppID>.customDestinations-ms ← app-curated
An automaticDestinations-ms file is an OLE Compound File (signature D0 CF 11 E0 A1 B1 1A E1). Inside, each numbered stream is a LNK-format entry, and a special DestList stream is an MRU index recording, for each entry, an access count, the most-recent and original open times, and a machine identifier. The filename prefix — the AppID — identifies the application that opened the files (a published list maps AppIDs to apps; SolidWorks, Word, Notepad, and "Quick Access" all have known IDs). Parse with JLECmd. The result answers "which application opened which file, when, and how many times" — and, like LNKs, it survives the removal of the device the files lived on.
Recovery vs. Forensics. LNKs and Jump Lists are a clean illustration of the dual lens. For the 🔍 examiner they are proof of access — this user opened this file, from this device, at this time — even after the device and the file are gone. For the 💾 recovery technician they are a catalog of what once existed: a client whose drive is dying but whose profile is readable can have their recent-work history reconstructed from
Recent\, telling you exactly which files to prioritize carving and where they were stored, long before the file system itself is fully recovered. The same artifact: one reads it to prove, the other to restore.
$Recycle.Bin: what was deleted, when, and by whom
Sending a file to the Recycle Bin does not delete it; it moves it and writes a small metadata record. On Windows Vista and later each deleted item becomes two files in a per-user, per-SID folder:
C:\$Recycle.Bin\<SID>\
$IXXXXXX.<ext> ← METADATA: original path, original size, deletion time
$RXXXXXX.<ext> ← the actual file CONTENT (recoverable as-is)
The $I (info) file is small and fixed in layout. On Windows 10/11 it uses version 2:
$I file (Windows 10/11, version 2)
Offset bytes meaning
00000000 02 00 00 00 00 00 00 00 header version = 2 (Win10/11; Vista–8.1 = 1)
00000008 00 60 1E 00 00 00 00 00 original size = 0x1E6000 = 1,990,656 bytes
00000010 9B 41 5A 2A 7C 4F D9 01 deletion time (FILETIME) → 2024-03-16 09:12 UTC
00000018 32 00 00 00 path length = 0x32 = 50 (49 chars + null)
0000001C 43 00 3A 00 5C 00 ... "C:\Users\jrivera\Desktop\TurbineHousing_v7.sldprt"
(UTF-16LE, null-terminated)
(Version 1, used Vista through 8.1, has the same header/size/time layout but stores the path as a fixed 520-byte field starting at 0x18 instead of a length-prefixed string. Windows XP used a single INFO2 database in C:\RECYCLER\<SID>\ — you will still meet it on legacy media.)
Two things make $Recycle.Bin` valuable beyond the obvious. First, **the SID in the folder name attributes the deletion to a specific user** — which user emptied which file matters. Second, even when the `$R content file has been overwritten or wiped, the $I` metadata may survive, giving you the *original path, size, and deletion time* of a file you can no longer recover. Knowing that `C:\…\TurbineHousing_v7.sldprt` was deleted at 09:12 on Saturday — minutes before CCleaner ran — is a finding even without the file itself. Parse `$I files with RBCmd:
RBCmd.exe -d "E:\evidence\C\$Recycle.Bin\S-1-5-21-...-1001" --csv .
DeletedOn (UTC) FileSize FileName
2024-03-16 09:12:41 1,990,656 C:\Users\jrivera\Desktop\TurbineHousing_v7.sldprt
2024-03-16 09:12:44 842,128 C:\Users\jrivera\Desktop\BearingAssembly_rev3.sldprt
# Illustrative $I (v2) parser — the structure above, in code.
import struct, datetime
def parse_I(data: bytes):
version, size, ft = struct.unpack_from("<qqq", data, 0) # 3x 8-byte little-endian
deleted = datetime.datetime(1970,1,1,tzinfo=datetime.timezone.utc) + \
datetime.timedelta(microseconds=(ft - 116444736000000000)//10)
if version >= 2:
(plen,) = struct.unpack_from("<I", data, 24) # chars incl. null
path = data[28:28+plen*2].decode("utf-16-le").rstrip("\x00")
else:
path = data[24:24+520].decode("utf-16-le").rstrip("\x00")
return {"version": version, "size": size, "deleted_utc": deleted, "path": path}
Recovery vs. Forensics. For 💾 recovery, the
$R` file *is the data* — copy it out and you have restored the file, no carving required. For 🔍 forensics, the `$Ifile is a deletion event with a timestamp and an attributed user, useful even when the$Rcontent is gone. One artifact pair, both disciplines served — the cleanest possible example of why this book teaches them together.
Tool demonstration: the Zimmerman workflow and Autopsy
You could extract every artifact above by hand. You should not. The field standard for free, court-respected Windows artifact parsing is the Eric Zimmerman (EZ) tools suite, complemented by RegRipper for registry triage and Autopsy when you want an integrated GUI. A typical dead-box pass looks like this.
First, extract the artifact files from your verified image. With The Sleuth Kit you can pull a file by its MFT record (here, conceptually):
# Identify the partition, locate the file, extract it from the IMAGE (read-only).
mmls WS-ENG-04.E01 # find the NTFS partition's start sector
fls -o 2048 WS-ENG-04.E01 | grep -i NTUSER
icat -o 2048 WS-ENG-04.E01 74213 > ./work/NTUSER.DAT # 74213 = MFT record
# (Always also grab NTUSER.DAT.LOG1/.LOG2 so dirty hives can be replayed.)
sha256sum ./work/NTUSER.DAT >> chain-of-custody.txt
Then run the parsers. Each emits CSV you load into Timeline Explorer for sorting and filtering:
# Registry → bookmarked artifacts (USB, RecentDocs, UserAssist, etc.)
RECmd.exe --d ".\work" --bn BatchExamples\Kroll_Batch.reb --csv .\out
# Prefetch (all .pf at once, decompresses Win10 MAM automatically)
PECmd.exe -d "C:\Windows\Prefetch" --csv .\out
# Amcache (presence + SHA-1)
AmcacheParser.exe -f ".\work\Amcache.hve" -i --csv .\out
# ShimCache (AppCompatCache value)
AppCompatCacheParser.exe -f ".\work\SYSTEM" --csv .\out
# LNK files, Jump Lists, ShellBags, Recycle Bin
LECmd.exe -d "...\Recent" --csv .\out
JLECmd.exe -d "...\AutomaticDestinations" --csv .\out
SBECmd.exe -d ".\work" --csv .\out
RBCmd.exe -d "...\$Recycle.Bin" --csv .\out
# Event logs, normalized
EvtxECmd.exe -d "C:\Windows\System32\winevt\Logs" --csv .\out
For a fast first look without scripting, RegRipper runs curated plugins against a hive and prints a readable report:
rip.exe -r .\work\SYSTEM -p usbstor
rip.exe -r .\work\NTUSER.DAT -p userassist
Autopsy wraps much of this in a GUI: add the .E01 as a data source, enable the Recent Activity ingest module (which incorporates RegRipper) plus the Windows artifact analyzers, and it surfaces USB devices, web/registry artifacts, recent documents, and $Recycle.Bin entries in browsable panels — excellent for triage and for examiners who want a visual cross-check of the CLI output. The full tool landscape (Autopsy/TSK, FTK, EnCase, X-Ways, Magnet AXIOM) is surveyed in Chapter 36 — The Forensic Toolkit, and a quick-reference table of artifact paths lives in Appendix D — Forensic Artifact Locations.
Tool Tip. Run more than one tool against the artifacts that carry your conclusion. If RegRipper, RECmd, and Autopsy all independently report the same USBSTOR serial and dates, your finding is robust to any single tool's bug or parsing quirk — and "I corroborated with multiple independent tools" is a sentence that holds up under cross-examination. Tool validation is a recurring expectation under Daubert (see Chapter 27 — Expert Testimony).
Worked example: the engineer who covered their tracks
Now we assemble the anchor. You have the verified image WS-ENG-04.E01 (SHA-256 recorded, working copy hashed). Counsel's question: did user jrivera copy proprietary turbine-housing CAD files to a personal device before resigning? You proceed artifact by artifact, building a timeline. Every step below is something the chapter just taught you.
1 — Was a personal device connected? (SYSTEM → USBSTOR, MountedDevices) RECmd against SYSTEM reports a USBSTOR entry for a SanDisk Cruzer Glide, serial 4C530001234567890123 (second character C, not & — a real, trackable serial). Its device-properties FILETIMEs: first install three weeks earlier; last arrival Friday 18:51; last removal Friday 19:33. MountedDevices maps it to drive E: and volume GUID {9f3a…}.
2 — Did THIS user mount it? (NTUSER.DAT → MountPoints2) In jrivera's NTUSER.DAT, MountPoints2\{9f3a…} exists — the same volume GUID — with a last-write time of Friday 18:51. The device is now bound to the user and the time. Not "a computer"; this account, that evening.
3 — Did the user browse the device's folders? (UsrClass.dat → ShellBags) SBECmd reconstructs a ShellBags path E:\ProjectArchive\TurbineHousing\ — a folder on the removable drive, browsed Friday evening. The folder does not exist on C:; it existed only on the device now in the engineer's possession.
4 — Were the specific files opened from the device? (LNK + Jump Lists) LECmd finds TurbineHousing_v7.lnk in Recent\, target E:\ProjectArchive\TurbineHousing\TurbineHousing_v7.sldprt, volume serial 9C2A-77F1, drive type removable. JLECmd's SolidWorks Jump List (matching the known SolidWorks AppID) shows the same file opened Friday 19:04, plus three more .sldprt files from E:\. The volume serial in the LNK matches the prefetch volume serial from step 6 — same physical device.
5 — Did the user try to hide the local copies by backdating them? ($SI vs. $FN — anti-forensics) Explorer shows the local C:\Users\jrivera\Desktop\TurbineHousing_v7.sldprt with a Modified date of two years ago — suspiciously old for a "current" design. But Explorer shows the $STANDARD_INFORMATION` timestamps, which any user can set with a timestomping utility. The kernel-maintained `$FILE_NAME timestamps in the MFT tell a different story: created Friday 18:58. When $SI` is wildly older than `$FN, or $SI` sub-seconds are zeroed while `$FN carries real precision, you are looking at timestamp manipulation. (The deep treatment of MACB timestamps and timestomping detection is Chapter 21 — Timeline Analysis; here it is enough to flag the $SI`/`$FN contradiction and let the MFT's truthful clock anchor the timeline. NTFS attribute structure is defined in Chapter 4 — File Systems.)
TIMESTAMP CONTRADICTION — TurbineHousing_v7.sldprt (Desktop copy)
Modified Created
$STANDARD_INFO : 2022-02-11 10:00:00 2022-02-11 10:00:00 ← shown in Explorer (forged)
$FILE_NAME : 2024-03-15 18:58:13 2024-03-15 18:58:13 ← kernel-set (truth)
^ matches USB last-arrival + Jump List access
6 — Did the user run a cleaner to erase the tracks? (Prefetch, Amcache, UserAssist, SOFTWARE) The SOFTWARE\Piriform\CCleaner key exists, with "wipe free space" enabled. PECmd on CCLEANER64.EXE-A1B2C3D4.pf reports run count 3, last run Saturday 09:14:22. UserAssist in NTUSER.DAT shows CCleaner64.exe launched by jrivera, last execution Saturday 09:14. AmcacheParser confirms the binary's presence with its SHA-1. The anti-forensic action did not erase itself; running the cleaner created the very artifacts that prove it ran.
7 — What did the cleaner erase, and when? (the absence as a trace) Browser history (Chapter 18's domain) ends abruptly Saturday 09:14. Several NTUSER.DAT MRU lists are empty but carry a last-write time of Saturday 09:14 — wiped, not never-used. And two $I` records in `$Recycle.Bin\<jrivera-SID>\ show TurbineHousing_v7.sldprt and a sibling deleted Saturday 09:12, minutes before the cleaner ran. The gaps line up exactly with the CCleaner execution time. The absence of data is itself dated evidence.
Assembled, the timeline reads:
WS-ENG-04 — TIMELINE (UTC), user jrivera
Fri 18:51 SanDisk Cruzer Glide (SN 4C53...0123) connected → drive E: [USBSTOR/MountPoints2]
Fri 18:55 Browsed E:\ProjectArchive\TurbineHousing\ [ShellBags]
Fri 18:58 C:\...\TurbineHousing_v7.sldprt created (kernel $FN) [MFT $FILE_NAME]
Fri 19:04 Opened TurbineHousing_v7.sldprt FROM E: (SN 9C2A-77F1) [LNK + Jump List]
Fri 19:33 Device removed [USBSTOR last-removal]
Sat 09:12 TurbineHousing_v7.sldprt + sibling sent to Recycle Bin [$I metadata]
Sat 09:14 CCleaner run #3 (wipe free space on) [Prefetch/UserAssist]
Sat 09:14 Browser history ends; MRU lists wiped (same minute) [gap = trace]
(local file Modified date forged to 2022; $FN proves 2024-03-15) [$SI vs $FN]
Every line is sourced to an artifact, every artifact is from a hashed image, and the contradictions all point one way. That is what a Windows examination produces: not a hunch, but a corroborated, time-anchored, attributable account that survives cross-examination.
War Story. A real version of this case turned on one detail the suspect never imagined: the prefetch file for the wiping tool. He had wiped free space, cleared browser history, and emptied the Recycle Bin — and then, satisfied, shut down. He did not know that the act of running the cleaner wrote
…\Prefetch\<CLEANER>.EXE-XXXXXXXX.pfwith a run count and a timestamp, that Amcache recorded its hash, or that the$Irecords of the files he "deleted" survived in slack. The cleaner cleaned everything except the evidence that it had run. Anti-forensics is a chapter of its own — Chapter 30 — Anti-Forensics — and its central lesson is visible already: tools erase the traces their authors anticipated, never the ones they did not, and never the trace of their own execution.Ethics Note. When you reconstruct a person's actions this precisely, remember the sixth theme — the human cost is real. Behind this image is an individual whose livelihood and reputation hinge on your report, and a company whose innovations may have been stolen. Your obligation is to the artifacts, stated with their limits intact: report what the data shows and only what it shows. "The files were accessed from a removable device with serial 9C2A-77F1 on Friday at 19:04" is a finding. "He intended to betray the company" is a motive you cannot read from a hive and must not assert. Keep findings and inferences rigorously separate; Chapter 26 — The Forensic Report shows you how.
Common mistakes
- Parsing a dirty hive without its transaction logs. If
seq pri ≠ seq secin the header and you ignore*.LOG1/*.LOG2, you analyze a stale registry and may miss the exact change you were hired to find. Always extract the hive and its logs, and use a parser that replays them. - Reading a ShimCache timestamp as an execution time. It is the file's
$STANDARD_INFORMATIONmodified time, not when it ran — and on Windows 8+ ShimCache does not even prove execution. Calling it "the time the program ran" is a factual error that opposing counsel will exploit. - Confusing "present" with "executed." Amcache and ShimCache prove a binary was present; Prefetch, UserAssist, and BAM indicate it ran. State which question each artifact answers and corroborate before you claim execution.
- Treating Explorer's timestamps as truth. Explorer shows
$STANDARD_INFORMATION`, which any user can forge. When it matters, compare against `$FILE_NAMEin the MFT, the USN journal, prefetch, and event logs. Inconsistency is itself evidence (theme #3). - Over-trusting a USB serial that begins
X&. A second character of&means Windows generated the serial; it is not globally unique and cannot anchor cross-machine identity. Say so in the report. - Forgetting
CurrentControlSetdoes not exist offline. On a dead-box hive you readControlSet001(checkSYSTEM\Select\Currentto confirm which set was current). Looking for a non-existentCurrentControlSetand concluding "the key isn't there" is a rookie miss. - Attributing per-user artifacts to the wrong account.
RecentDocs,UserAssist, ShellBags, LNKs, and$Recycle.Bin\<SID>are per-user. Cite the SID/profile the artifact came from; never let a finding from the administrator's hive masquerade as the suspect's activity. - Working on the live machine. Running
regedit, opening files, or even letting the system idle changes timestamps and writes new artifacts. Image first, verify the hash, work the copy — the second theme, the original is sacred, is not optional here.
Limitations: knowing when to stop
Windows artifacts are abundant, not omniscient. A professional report states their limits as plainly as their findings.
A key's last-write time is the single most-misused registry value. It reflects when the key was last modified, not when each value within it was written, and not necessarily when the event you care about occurred. For a single-purpose key (MountPoints2\{GUID}) it is a tight proxy for an event; for a busy key with many values it is nearly meaningless as a per-value clock. Never present a last-write time as the timestamp of a specific value unless the key holds only that one thing.
Prefetch can be disabled (default-off on many servers, sometimes on SSD systems), so absence of a .pf is not proof a program never ran. ShimCache flushes to the registry at shutdown, so the on-disk hive may lag the true most-recent activity — and a clean reboot since the event of interest matters. Amcache and ShimCache prove presence, not execution, full stop. BAM/UserAssist windows are limited and cover GUI launches, not every command-line invocation.
ShellBags prove a folder was browsed, not that any file inside was copied — a distinction defense counsel will press hard, and rightly. A LNK or Jump List proves a file was opened, with the device and time, but does not by itself prove the file was exfiltrated off the machine; you infer exfiltration by correlating file-open evidence with USB connection windows, and you state it as a correlation. The truthfulness of $FILE_NAME` over `$STANDARD_INFORMATION is strong but not absolute — sophisticated tampering of the MFT exists, and you cross-check with the USN journal and event logs rather than resting on a single attribute.
And then there is the hardest limit: a sufficiently disciplined adversary, using full-disk encryption you cannot break (Chapter 29), or physically destroying the device, or operating entirely from a live OS that writes nothing to the system disk, can leave you with genuinely insufficient evidence. The professional answer in that situation is the fifth theme made concrete: "the available artifacts are insufficient to determine whether X occurred" is a valid, defensible finding. Forcing a conclusion the data will not support is how examiners end their careers on cross-examination. Know what your artifacts can carry, and stop there.
Progressive project: extract and interpret the Windows artifacts in your case
Continue building your Forensic Case File (the running deliverable introduced in Chapter 5 — The Forensic Process and acquired in Chapters 14–15). This chapter you add the Windows-artifact layer:
- Extract the registry hives (
SYSTEM,SOFTWARE,SAM, each user'sNTUSER.DATandUsrClass.dat, andAmcache.hve) from your verified image together with their transaction logs. Extract the.evtxlogs and the Prefetch directory. Hash every extracted file and log it in your chain-of-custody worksheet (template in Appendix F). - Parse with the EZ tools (
RECmd,PECmd,AmcacheParser,AppCompatCacheParser,LECmd,JLECmd,SBECmd,RBCmd,EvtxECmd), exporting CSV. Cross-check at least one load-bearing finding with a second tool (RegRipper and/or Autopsy). - Answer four questions for your case and cite the exact artifact (path + tool) behind each: (a) What external storage devices were connected, by which user, and when? (b) What programs executed, and is your evidence execution or merely presence? (c) What files and folders were accessed, including any from removed devices? (d) Are there signs of anti-forensic activity — wiped MRUs with recent last-write times, a cleaner's prefetch,
$SI`/`$FNcontradictions, a cleared Security log (1102)? - Add a Windows-artifacts timeline to the case file, every entry sourced to an artifact. You will merge it into the master timeline in Chapter 21 and fold it into the final report in Chapter 26. Flag any finding whose limits you must state (presence-vs-execution, browsed-vs-copied, last-write caveats) so future-you writes them honestly.
Save the CSV outputs and your timeline into the case-file folder. The capstone in Chapter 38 assembles everything; do not let this chapter's evidence live only in your head.
Summary
Windows keeps receipts, and this chapter taught you to read them. You learned that the registry is not one database but a set of hive files — SAM, SYSTEM, SOFTWARE, SECURITY, DEFAULT, and the per-user NTUSER.DAT and UsrClass.dat — each mounting under a runtime tree, each parsed offline from your verified image, and each carrying key-level last-write timestamps that come straight from the regf binary format. You walked the highest-value keys: USB device history that chains USBSTOR → MountedDevices → per-user MountPoints2 into device-plus-user-plus-time attribution; RecentDocs, TypedURLs, TypedPaths, RunMRU, WordWheelQuery, and UserAssist in the user's diary; ShellBags in UsrClass.dat that prove a folder was browsed even after the device holding it is gone; and machine-wide autostart ASEPs. You learned the .evtx event logs — logon types on 4624/4625, account and group changes, the always-significant 1102/104 log clears, and System-log service installs (7045) and boot/shutdown markers — as the system's signed, hard-to-forge time anchors. You separated the execution artifacts by exactly what each proves: Prefetch and BAM and UserAssist indicate a program ran (with run counts and the last eight run times); Amcache and ShimCache indicate a binary was present (with a SHA-1 and a path), and ShimCache's stored time is a file modified-time, not a run-time. You read LNK files and Jump Lists for file access tied to a volume serial, and $Recycle.Bin`'s `$I/$R` pairs for deletion metadata and recoverable content attributed by SID. Finally, you ran the whole machine against anchor case #2 and watched anti-forensics defeat itself: a backdated file unmasked by `$FILE_NAME, and a cleaning tool convicted by its own prefetch entry — every action leaves a trace, and the absence of a trace is itself a trace. The artifacts evolve with every Windows release, but the method does not: understand the structure, extract from the image, parse with validated tools, corroborate across sources, and state every finding with its limits.
You can now: - Locate, extract (with transaction logs), and offline-parse the Windows registry hives, and read key last-write timestamps from the
regf/hbinstructure. - Reconstruct USB device history and attribute it to a specific user and time by chainingUSBSTOR,MountedDevices, andMountPoints2. - MineNTUSER.DAT/UsrClass.datfor RecentDocs, TypedURLs/Paths, RunMRU, UserAssist, and ShellBags, and read.evtxlogon, account-change, log-clear, and service-install events. - Distinguish execution evidence (Prefetch, UserAssist, BAM) from presence evidence (Amcache, ShimCache), and avoid the ShimCache-timestamp trap. - Interpret LNK files, Jump Lists, and$Recycle.Bin` `$I/$Rpairs to prove file/folder access and deletion — even from devices no longer present. - Detect anti-forensic activity (timestomping via$SI`/`$FNcontradiction, a cleaner's own prefetch, wiped-but-dated MRUs, cleared logs) and report findings with their limitations intact.
What's next. Chapter 17 — macOS and Linux Forensics — takes the same investigative method to systems with no registry: you will trade hives and .evtx for plists, FSEvents, unified logging, bash/zsh history, syslog/journald, and ext4/APFS metadata — proof that technology changes, principles don't.
Practice in exercises.md, test yourself with the quiz, apply it in the case studies, review the key takeaways, and go deeper with further reading.