digital forensics

Parsing Artifacts with Eric Zimmerman Tools

Parse registry, prefetch, shellbags, and MFT with EZ Tools and Timeline Explorer.

artifact-parsingdfirdigital-forensicseric-zimmermanmftprefetchregistry-forensicsshellbags
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Authorized Use Only: These tools parse evidence acquired from systems. Only analyze data you are authorized to handle, maintain chain of custody, and work from forensic copies rather than originals.

Overview

Eric Zimmerman's Tools (EZ Tools) are a free, open-source suite of high-fidelity Windows forensic parsers, each focused on a specific artifact class and each producing analyst-ready CSV/JSON output. They are the de facto standard for Windows artifact analysis and are what KAPE's !EZParser module invokes under the hood. Key tools include:

  • MFTECmd — parses $MFT, $J ($UsnJrnl), $Boot, $SDS, and $LogFile from NTFS volumes.
  • PECmd — parses Windows Prefetch (.pf) for evidence of program execution.
  • RECmd — registry hive parser/searcher driven by batch plugins (RECmd Batch files).
  • SBECmd — parses ShellBags (folder access history) from UsrClass.dat/NTUSER.DAT.
  • AmcacheParser — parses Amcache.hve for application execution and metadata.
  • AppCompatCacheParser — parses ShimCache (AppCompatCache) from SYSTEM hive.
  • LECmd — parses LNK shortcut files. JLECmd — parses Jump Lists. EvtxECmd — parses EVTX event logs to a normalized schema.

Output is designed to load into Timeline Explorer (also by Eric Zimmerman), a fast CSV/Excel viewer purpose-built for filtering, tagging, and pivoting across forensic CSVs. The 2025+ releases run on .NET and also work natively on Linux.

When to Use

  • After triage collection (e.g. with KAPE) when you need to parse raw artifacts into structured, searchable evidence.
  • To establish program execution, file/folder access, and persistence during incident response.
  • To build artifact-specific CSVs that feed timelines, Timesketch, or SIEM ingestion.

Prerequisites

Objectives

  • Parse the MFT, prefetch, shellbags, registry, and amcache from a collection.
  • Produce normalized CSV/JSON per artifact.
  • Load results into Timeline Explorer for analysis.
  • Establish execution and access evidence supporting the investigation.

MITRE ATT&CK Mapping

ID Official Technique Name Relevance to this skill
T1112 Modify Registry RECmd, AmcacheParser, and AppCompatCacheParser parse registry-resident artifacts; analysts use them to detect adversary registry modification (persistence, defense evasion) recorded in hives.

These are defensive parsers; the mapping reflects the artifact (registry) most relevant to the adversary behavior they help uncover.

Workflow

1. Download/update the tools

Keep parsers current so they handle the latest artifact formats.

.\Get-ZimmermanTools.ps1 -Dest C:\Tools\EZ

2. Parse the MFT for file-system activity

-f points at a single $MFT; --csv sets the output directory and --csvf the filename. Add --csvf for $J/UsnJrnl with -f $J.

MFTECmd.exe -f "E:\collection\C\$MFT" --csv "E:\out\mft" --csvf MFT.csv
 
REM Parse the USN Journal change log
MFTECmd.exe -f "E:\collection\C\$Extend\$J" --csv "E:\out\mft" --csvf UsnJrnl.csv

3. Parse Prefetch for execution evidence

-d recurses a directory of .pf files. Output CSV + JSON.

PECmd.exe -d "E:\collection\C\Windows\Prefetch" --csv "E:\out\prefetch" --csvf Prefetch.csv --json "E:\out\prefetch\json"

4. Parse ShellBags for folder-access history

-d points at the directory containing the user's UsrClass.dat/NTUSER.DAT (or -f a single hive).

SBECmd.exe -d "E:\collection\C\Users\jsmith" --csv "E:\out\shellbags"

5. Parse the registry with RECmd batch plugins

RECmd is driven by batch files (--bn) that bundle plugins; the Kroll_Batch file is comprehensive. -d recurses a directory of hives.

RECmd.exe -d "E:\collection\C\Windows\System32\config" --bn "C:\Tools\EZ\RECmd\BatchExamples\Kroll_Batch.reb" --csv "E:\out\registry" --csvf Registry.csv
 
REM Search a single hive for a value/key
RECmd.exe -f "E:\collection\C\Users\jsmith\NTUSER.DAT" --sk "Run" --csv "E:\out\registry"

6. Parse Amcache and ShimCache

AmcacheParser.exe -f "E:\collection\C\Windows\AppCompat\Programs\Amcache.hve" --csv "E:\out\amcache" -i
 
AppCompatCacheParser.exe -f "E:\collection\C\Windows\System32\config\SYSTEM" --csv "E:\out\shimcache"

7. Parse LNK, Jump Lists, and EVTX

LECmd.exe -d "E:\collection\C\Users\jsmith\AppData\Roaming\Microsoft\Windows\Recent" --csv "E:\out\lnk"
 
JLECmd.exe -d "E:\collection\C\Users\jsmith\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations" --csv "E:\out\jumplists"
 
EvtxECmd.exe -d "E:\collection\C\Windows\System32\winevt\Logs" --csv "E:\out\evtx" --csvf EventLogs.csv

8. Analyze in Timeline Explorer

Open the resulting CSVs in Timeline Explorer (TimelineExplorer.exe). Use column filters, conditional formatting, and tagging to pivot on time, file path, and user. CSVs from all EZ Tools share consistent timestamp columns for cross-artifact correlation.

9. Cross-correlate

Build a working theory by correlating PECmd (execution time) with MFTECmd (file creation), Amcache/ShimCache (program presence), and ShellBags/LNK (access), all anchored on UTC timestamps.

Tools and Resources

Tool Artifact parsed Link
MFTECmd $MFT, $J, $Boot, $SDS, $LogFile https://github.com/EricZimmerman/MFTECmd
PECmd Prefetch https://github.com/EricZimmerman/PECmd
RECmd Registry hives https://github.com/EricZimmerman/RECmd
SBECmd ShellBags https://github.com/EricZimmerman/Shellbags
AmcacheParser Amcache.hve https://github.com/EricZimmerman/AmcacheParser
AppCompatCacheParser ShimCache https://github.com/EricZimmerman/AppCompatCacheParser
LECmd / JLECmd LNK / Jump Lists https://ericzimmerman.github.io/
EvtxECmd EVTX event logs https://github.com/EricZimmerman/evtx
Timeline Explorer CSV analysis viewer https://ericzimmerman.github.io/
Get-ZimmermanTools Downloader/updater https://github.com/EricZimmerman/Get-ZimmermanTools

Common Flags

Flag Meaning
-f <file> Parse a single file
-d <dir> Recurse a directory
--csv <dir> CSV output directory
--csvf <name> CSV output filename
--json <dir> JSON output directory
--bn <file> RECmd batch (.reb) file
-i AmcacheParser: include file entries (unassociated)

Validation Criteria

  • EZ Tools downloaded/updated via Get-ZimmermanTools
  • $MFT (and $J) parsed to CSV
  • Prefetch parsed for execution evidence
  • ShellBags parsed for folder-access history
  • Registry parsed with Kroll_Batch (RECmd)
  • Amcache and ShimCache parsed
  • LNK/Jump Lists/EVTX parsed as needed
  • Output loaded and reviewed in Timeline Explorer
  • Cross-artifact correlation performed on UTC timestamps
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 2

api-reference.md2.3 KB

EZ Tools Command Reference

All tools are .NET CLI parsers that emit CSV/JSON. Common flags: -f (single file), -d (directory recurse), --csv (output dir), --csvf (output filename), --json (JSON output dir).

MFTECmd

Flag Purpose
-f Path to $MFT, $J, $Boot, $SDS, or $LogFile
--csv / --csvf CSV output dir / filename
--json JSON output dir
--de <entry> Dump a specific MFT entry
MFTECmd.exe -f "C:\$MFT" --csv "C:\out" --csvf MFT.csv
MFTECmd.exe -f "C:\$Extend\$J" --csv "C:\out" --csvf UsnJrnl.csv

PECmd (Prefetch)

Flag Purpose
-f / -d Single .pf / directory
--csv / --csvf / --json Outputs
-k <keywords> Highlight keywords
PECmd.exe -d "C:\Windows\Prefetch" --csv "C:\out" --csvf Prefetch.csv --json "C:\out\json"

RECmd (Registry)

Flag Purpose
-f / -d Single hive / directory of hives
--bn <file> Batch file (.reb), e.g. Kroll_Batch.reb
--sk <value> Search keys/values
--csv / --csvf Outputs
RECmd.exe -d "C:\config" --bn "RECmd\BatchExamples\Kroll_Batch.reb" --csv "C:\out"

SBECmd (ShellBags)

SBECmd.exe -d "C:\Users\jsmith" --csv "C:\out"

AmcacheParser

Flag Purpose
-f Path to Amcache.hve
-i Include unassociated file entries
--csv Output dir
AmcacheParser.exe -f "C:\Windows\AppCompat\Programs\Amcache.hve" --csv "C:\out" -i

AppCompatCacheParser (ShimCache)

AppCompatCacheParser.exe -f "C:\Windows\System32\config\SYSTEM" --csv "C:\out"

LECmd / JLECmd (LNK / Jump Lists)

LECmd.exe  -d "C:\Users\jsmith\AppData\Roaming\Microsoft\Windows\Recent" --csv "C:\out"
JLECmd.exe -d "...\Recent\AutomaticDestinations" --csv "C:\out"

EvtxECmd (EVTX)

EvtxECmd.exe -d "C:\Windows\System32\winevt\Logs" --csv "C:\out" --csvf EventLogs.csv

Get-ZimmermanTools (downloader)

.\Get-ZimmermanTools.ps1 -Dest C:\Tools\EZ

Timeline Explorer

GUI CSV viewer: TimelineExplorer.exe. Loads EZ Tools CSVs; supports column filters, conditional formatting, and tagging for cross-artifact correlation on UTC timestamps.

standards.md1.2 KB

Standards and Framework Mapping — Parsing Artifacts with Eric Zimmerman Tools

NIST Cybersecurity Framework 2.0

ID Name Rationale
RS.AN-03 Analysis is performed to establish what has taken place during an incident and the root cause of the incident EZ Tools parse Windows artifacts (MFT, prefetch, registry, shellbags, amcache) into structured evidence that establishes attacker execution, access, and persistence during incident analysis.

MITRE ATT&CK

ID Name Rationale
T1112 Modify Registry RECmd, AmcacheParser, and AppCompatCacheParser parse registry artifacts where adversary registry modifications (persistence, evasion) are recorded and recovered.

Supporting References

Scripts 1

agent.py4.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
EZ Tools batch driver.

Runs Eric Zimmerman's forensic parsers over a KAPE-style collection or mounted
image, writing per-artifact CSV/JSON into an output tree. Each command uses the
real EZ Tools flags. Works as a dry-run command generator on any platform.

Reference: https://ericzimmerman.github.io/
"""
import argparse
import os
import shutil
import subprocess
import sys
from pathlib import Path

# Map of artifact -> (tool exe, builder(collection_root, out_dir) -> argv)
def _mft(tool, root, out):
    mft = os.path.join(root, "$MFT")
    return [tool, "-f", mft, "--csv", out, "--csvf", "MFT.csv"]

def _usn(tool, root, out):
    j = os.path.join(root, "$Extend", "$J")
    return [tool, "-f", j, "--csv", out, "--csvf", "UsnJrnl.csv"]

def _prefetch(tool, root, out):
    d = os.path.join(root, "Windows", "Prefetch")
    return [tool, "-d", d, "--csv", out, "--csvf", "Prefetch.csv",
            "--json", os.path.join(out, "json")]

def _amcache(tool, root, out):
    f = os.path.join(root, "Windows", "AppCompat", "Programs", "Amcache.hve")
    return [tool, "-f", f, "--csv", out, "-i"]

def _shimcache(tool, root, out):
    f = os.path.join(root, "Windows", "System32", "config", "SYSTEM")
    return [tool, "-f", f, "--csv", out]

def _evtx(tool, root, out):
    d = os.path.join(root, "Windows", "System32", "winevt", "Logs")
    return [tool, "-d", d, "--csv", out, "--csvf", "EventLogs.csv"]

def _registry(tool, root, out, batch):
    d = os.path.join(root, "Windows", "System32", "config")
    return [tool, "-d", d, "--bn", batch, "--csv", out, "--csvf", "Registry.csv"]


ARTIFACTS = {
    "mft":       ("MFTECmd.exe", _mft),
    "usn":       ("MFTECmd.exe", _usn),
    "prefetch":  ("PECmd.exe", _prefetch),
    "amcache":   ("AmcacheParser.exe", _amcache),
    "shimcache": ("AppCompatCacheParser.exe", _shimcache),
    "evtx":      ("EvtxECmd.exe", _evtx),
}


def resolve_tool(tools_dir, exe):
    """Find a tool either in tools_dir or on PATH."""
    if tools_dir:
        candidate = Path(tools_dir) / exe
        if candidate.exists():
            return str(candidate)
        # also try without .exe on Linux .NET builds
        alt = Path(tools_dir) / exe.replace(".exe", "")
        if alt.exists():
            return str(alt)
    found = shutil.which(exe) or shutil.which(exe.replace(".exe", ""))
    return found or str(Path(tools_dir or ".") / exe)


def run_one(name, tools_dir, root, out_root, batch, dry_run):
    exe, builder = ARTIFACTS[name]
    tool = resolve_tool(tools_dir, exe)
    out = os.path.join(out_root, name)
    os.makedirs(out, exist_ok=True)
    if name == "registry":
        cmd = _registry(tool, root, out, batch)
    else:
        cmd = builder(tool, root, out)
    print("[*] " + " ".join(f'"{c}"' if " " in c else c for c in cmd))
    if dry_run:
        return 0
    try:
        return subprocess.run(cmd, check=False).returncode
    except FileNotFoundError:
        print(f"[!] tool not found: {tool}", file=sys.stderr)
        return 127


def main():
    p = argparse.ArgumentParser(description="EZ Tools batch driver")
    p.add_argument("--collection", required=True,
                   help="Root of the collection (the 'C' directory)")
    p.add_argument("--out", required=True, help="Output root directory")
    p.add_argument("--tools-dir", help="Directory containing EZ Tools binaries")
    p.add_argument("--batch", help="RECmd batch (.reb) file for registry")
    p.add_argument("--artifacts", default="mft,prefetch,amcache,shimcache,evtx",
                   help="Comma-separated: " + ",".join(list(ARTIFACTS) + ["registry"]))
    p.add_argument("--dry-run", action="store_true")
    args = p.parse_args()

    if not os.path.isdir(args.collection):
        print(f"[!] collection not found: {args.collection}", file=sys.stderr)
        return 2
    os.makedirs(args.out, exist_ok=True)

    requested = [a.strip() for a in args.artifacts.split(",") if a.strip()]
    rc = 0
    for name in requested:
        if name == "registry":
            if not args.batch:
                print("[!] registry requires --batch (.reb file); skipping",
                      file=sys.stderr)
                rc = rc or 2
                continue
            r = run_one("registry", args.tools_dir, args.collection, args.out,
                        args.batch, args.dry_run)
        elif name in ARTIFACTS:
            r = run_one(name, args.tools_dir, args.collection, args.out,
                        args.batch, args.dry_run)
        else:
            print(f"[!] unknown artifact: {name}", file=sys.stderr)
            r = 2
        rc = rc or r
    print(f"[+] done (exit {rc})")
    return rc


if __name__ == "__main__":
    sys.exit(main())
Keep exploring