- New --format hashcat: outputs NTLM hashes (mode 1000) and DCC2 (mode 2100)
for direct use with hashcat
- Raw disk support: handles flat VMDKs (-flat.vmdk) and raw images (.raw/.img/.dd)
as simple seek+read without sparse container parsing
- EPT walker: scans for nested hypervisor page tables (VBS/Hyper-V) when
System process not found in L1 physical memory, translates L2→L1 addresses
through Extended Page Tables to access Windows kernel structures
- Debug logging for System process scan near-misses (DTB/Flink rejections)
Win10 1607+ (build 19045) stores a 20-byte SHA/DPAPI field at +0x36 before
the actual hashes, shifting NtOwfPassword from +0x36 to +0x4A. Previous code
extracted the first 16 bytes of ShaOwPassword instead of the real NT hash.
Changes:
- Add DPAPI-shifted layout detection in structural_score(): compares data at
0x36 with data at 0x6A (both contain ShaOwPassword/dppiGenericRandom)
- Add 6 PRIMARY_CRED_OFFSET_VARIANTS: canonical mimikatz (0x36, 0x28, 0x20),
no-unk (0x30), and empirical DPAPI-shifted (0x4A, 0x4C)
- Replace first-match entropy selection with scored candidates, preferring
variants with highest structural_score()
- When DPAPI layout detected: variant 0x36 gets score=0, variant 0x4A gets
score=23 (flags validated + zero LM + DPAPI confirmed)
Verified against pypykatz: NT=bbf7d1528afa8b0fdd40a5b2531bbb6d matches
across all 3 VMware snapshots and VBox snapshot.
- VMware layer: fall back to identity mapping when VMSN has no region
tags (older VMware snapshots), fixes "System process not found" on
VMs with minimal VMSN metadata
- MSV physical scan: replace broken variant-0 fallback with proper
entropy-based validation. When SHA1 cross-validation fails for all
offset variants, check if SHA1 field is zero (not stored on Win7/2012)
and validate hash bytes don't look like UTF-16 text. Prevents garbage
hashes (username/domain text displayed as NT hashes) on older builds.
- Add Win11 24H2 (build 26100+) EPROCESS offsets: UniqueProcessId,
ActiveProcessLinks, ImageFileName shifted +8 from Win10 layout
Tested on ESXi against 12 Windows VMs spanning Win7 through Win11:
Win7, Win8/2012, Win10, Win11, Server 2012 DC, Server 2016,
Server 2016 DC, Server 2019
When WDigest is paged out (common on VBox snapshots), SYSTEM and
service sessions have empty domain. Now fills "NT AUTHORITY" as
domain for LUIDs 0x3e7/0x3e4/0x3e5 when domain is empty, while
preserving WDigest-discovered values (e.g. WORKGROUP) when present.
- Fill in SYSTEM/NETWORK SERVICE/LOCAL SERVICE usernames for well-known
LUIDs when they're empty (common on VBox where WDigest is paged out)
- Ensures DPAPI-only sessions show meaningful identifiers
- When physical scan credential has empty domain (local logons), match
by username only instead of requiring exact domain match
- Prefer Interactive (logon_type=2) sessions when multiple sessions
match the same username, ensuring credentials are shown under the
correct session entry
- Fixes VBox output showing \User instead of DESKTOP-HMI10SP\User
Log count of readable vs matched candidates to aid debugging.
Most VM snapshots have Kerberos data genuinely paged out, so
the physical scan finds security principal names (false positives)
rather than actual Kerberos credential structures.
Extract common walk logic into walk_session_buckets/walk_session_list.
Use HashMap<LUID, MsvSessionInfo> instead of Vec + HashSet to allow
metadata enrichment when a session is re-discovered by a variant with
richer data (e.g. variant 2 has logon_time, variant 0 doesn't).
The inline hash table walk now tries ALL variants across ALL tables
instead of breaking on the first match, ensuring metadata from
MSV1_0_LIST_63 (variant 2) enriches sessions first found in
NlpActiveLogon (variant 0).
DPAPI: Complete rewrite with correct encrypted key extraction.
- Keys at +0x34 are encrypted with LsaProtectMemory (3DES/AES), not plaintext
- Correct offsets: GUID=+0x18, keySize=+0x30, key=+0x34 (all Windows x64)
- Add SHA1 masterkey computation (inline, no external crate)
- Add physical memory scan fallback for paged-out g_MasterKeyCacheList
- Add LEA-to-.data scan as intermediate fallback between .text and .data
- All 6 DPAPI masterkeys now match pypykatz output exactly
Session discovery: Walk NlpActiveLogon + MSV hash tables + WDigest.
- New extract_msv_sessions() discovers sessions from all MSV list variants
- Resolve both LogonSessionList address and bucket count from patterns
- Walk all hash table buckets (not just the first linked list)
- Extract metadata: LogonType, SessionId, LogonServer, SID (embedded)
- WDigest l_LogSessList discovers remaining sessions (DWM, UMFD, SYSTEM)
- 8 sessions discovered (up from 2-3), matching pypykatz session count
WDigest: Validate pattern-resolved list address before use.
- File-backed .text resolution can produce stale RIP-relative offsets
- Fallback to .data scan when flink validation fails
Types: Add session metadata fields and DPAPI sha1_masterkey display.
New --dump <process> flag exports a process's virtual memory as a Windows
minidump file compatible with pypykatz (lsa minidump command).
Writes 3 streams: SystemInfoStream, ModuleListStream, Memory64ListStream.
Captures present+transition+pagefile PTEs plus module VA ranges.
Supports pagefile and file-backed DLL resolution via --disk flag.
Verified: pypykatz extracts identical NT hash from our dump as our direct
extraction (bbf7d1528afa8b0fdd40a5b2531bbb6d on VMware Win10 snapshot).
Extract MsCacheV2 (DCC2) hashes from SECURITY\Cache\NL$n values,
decrypted with the NL$KM key from LSA secrets. Output in hashcat
mode 2100 format ($DCC2$<iter>#<user>#<hash>).
- VHDX reader: full MS-VHDX spec implementation with dynamic and
differencing disk support (BAT with interleaved sector bitmaps,
metadata region parsing, parent locator chain)
- VHD reader: legacy VHD format with fixed, dynamic, and differencing
disk support (big-endian BAT, per-block sector bitmaps, parent
locator entries)
- Auto-detection: .vhd/.vhdx extensions trigger SAM mode
- Folder discovery: VHDX and VHD files auto-discovered in VM directories
- Updated CLI help text for Hyper-V disk support
When file-backed resolution provides lsasrv.dll .text section, the key
init pattern is found but .data globals read as 0 (pages paged out).
Previously, the .data section fallback was only triggered when the
.text pattern wasn't found — not when all offset sets failed.
Changes:
- Fall through to .data section scan when all 7 offset sets fail
(some .data pages may be accessible as transition pages even when
the specific globals referenced by the pattern are paged out)
- Add physical UUUR scan as third-level fallback: enumerate all
present+transition LSASS pages for BCRYPT_HANDLE_KEY structures,
bypassing .data globals entirely
- Wire physical scan fallback in finder.rs
VBox results: crypto keys now extracted via .data fallback, enabling
MSV1_0 hash extraction (previously failing with "Invalid BCrypt
handle pointer: 0x0"). Pagefile resolves 998 pages (up from 0).
- Add scan_blocks_for_bootkey(): scans all physically present hbin blocks
for JD/Skew1/GBG/Data NK cells with cross-block class name resolution.
This bypasses tree navigation entirely, finding bootkey components even
when parent path (ControlSet→Control→Lsa) is broken.
- Wire scattered bootkey into VMDK grain scan pipeline: after fragmented
SYSTEM hive assembly, read all hbin blocks and attempt bootkey extraction
before falling back to regular SYSTEM hive parsing.
- Improve bootkey error diagnostics: when all extraction methods fail,
report percentage of zero-filled pages in SYSTEM hive and explain that
bootkey cells are in missing disk extents.
- Enhance MFTMirr fallback logging: when target files have inaccessible
first extents, attempt zero-fill read and log whether regf/hbin data
is present (instead of silently skipping).
When the primary MFT is inaccessible (e.g., in a truncated/missing
VMDK extent), bootstrap MFT access through $MFTMirr:
1. Parse NTFS boot sector to locate $MFTMirr
2. Read $MFT record from MFTMirr to get MFT data runs
3. Determine which MFT segments are accessible
4. Scan accessible records for SAM/SYSTEM/SECURITY files
5. Verify parent chain (config/System32) when possible
6. Fall back to regf-signature validation when parent is inaccessible
Includes full NTFS FILE record parsing: fixup arrays, attribute
enumeration, data run decoding, $FILE_NAME extraction with namespace
handling, and non-resident $DATA reading with zero-fill for
inaccessible runs.
For Windows10vstdio (50% disk coverage): MFTMirr is accessible at
partition+0x2000, MFT has 3 runs (500K records), but SAM/SYSTEM
records are in inaccessible Run 0 (records #0-204927). The fallback
correctly identifies this and falls through to grain scan.
- Bypass Select key requirement: try ControlSet001/002/003 directly
when Select key is missing from fragmented SYSTEM hive
- Phase 2c gating: detect small SYSTEM hives (< 512KB) from Phase 2b
and allow fragmented assembly to try building a larger hive
- Relax SYSTEM hive validation: accept ControlSet001/002 in addition
to Select for both build_hive_from_hbins and validate_hive_content
- Add brute-force NK cell scan: when tree navigation fails, scan all
cells in assembled hive for JD/Skew1/GBG/Data bootkey components
- Add read_class_hex helper for UTF-16LE class name cell decoding
- Extract tickets from 3 linked lists per Kerberos logon session
(TGT, TGS, Client) with multi-version offsets (Win7-11)
- Parse KERB_EXTERNAL_NAME for service/client principal names
- Full ASN.1 DER encoding for .kirbi (KRB-CRED) format
- Add KerberosTicket type with all fields (flags, key, timestamps, blob)
- Display tickets with type, service name, enc type, flags, times, base64 kirbi
- Add base64_encode() to crypto module
- Fix all 17 clippy warnings (is_multiple_of, div_ceil, if_same_then_else)
When Windows drops DLL .text pages from the working set, it zeros the
PTE knowing the data can be re-read from the DLL file. This commit
reads DLL files from the disk image via NTFS and serves those pages
when a zero-PTE fault occurs in a known non-writable DLL section.
Architecture:
- FileBackedResolver reads PE files from disk, extracts non-writable
sections (.text, .rdata), maps them to module_base + VirtualAddress
- Binary search resolves VA to on-disk section data
- Integrated into ProcessMemory::read_virt() as fallback on PageFault
- Works synergistically with pagefile resolution (DLL .text enables
pattern scans that discover structures whose data pages are in pagefile)
Results on VMware test snapshots:
- 472 sections loaded from 93 DLLs (~40 MB)
- 12,020 DLL pages resolved from disk per snapshot
- 2,235 pagefile pages resolved (up from 0 without file-backed)
- New --disk flag for single-file mode, auto-discovered in folder mode
When page table pages (PDPT/PD/PT) are themselves swapped to
pagefile.sys, the parent entry becomes a pagefile PTE. The new
translate_with_pagefile() method resolves page table pages from
the pagefile at each walk level before continuing translation.
Also wire pagefile into ProcessMemory::read_virt() to resolve
data pages that are in pagefile (PageFileFault handling).
Phase 2c: fragmented hive assembly from scattered hbin blocks.
When registry hives are fragmented by NTFS (regf header at one location,
hbin blocks scattered across non-contiguous clusters), the grain scan now:
- Collects ALL hbin blocks during grain scan (not just offset=0 roots)
- Groups blocks by offset_in_hive into a candidate map
- Backtracking DFS (small hives ≤256KB): proximity-sorted candidates,
strict then relaxed validation fallback
- Greedy assembly (large hives): first-match with zero-filled gaps
- Two-tier validation: strict (expected subkeys) → structural (root name)
- Broadened regf path matching for SYSTEM/SECURITY hives
- Default bins_size inference when no matching regf header exists
For incomplete delta disks (e.g., Windows10vstdio with 50% missing extents),
hives are now found and the error is specific ("Select not found" vs
generic "SYSTEM not found").
- Add scan_all_grains() to VmdkDisk: iterates physically allocated grains
bypassing LBA translation, for fast scanning of incomplete VMDK images
- Add grain-direct fallback in SAM extraction pipeline: scans grains for
regf/hbin signatures, assembles hives from virtual disk space
- Fix NK root key detection: remove KEY_HIVE_ENTRY (0x04) flag requirement
since SAM's root key only has KEY_COMP_NAME (0x20)
- Add offset_in_hive validation when reading contiguous hbin blocks to
prevent mixing blocks from different hives
- Add hive content validation (Select/Domains/Policy subkey checks) to
reject false matches from non-system config hives
Two bugs fixed:
- Wrong AES mode: was using AES-256-CBC, should be AES-256-ECB
(confirmed by mimikatz CRYPT_MODE_ECB, impacket per-block CBC
reinit, pypykatz AESModeOfOperationECB)
- Wrong LSA key offset: PolEKList Secret is NT6_SYSTEM_KEYS struct
(per mimikatz), actual key at offset 68 in decrypted blob, not 44
DefaultPassword now decrypts correctly (was garbled), DPAPI_SYSTEM
now shows correct 44-byte structure with valid version field.
When a VM directory contains both memory snapshots and disk images,
open pagefile.sys from the VMDK/VDI/QCOW2 disk to resolve pages
that Windows swapped out. Uses pre-built NTFS data run map with
RefCell<Box<dyn DiskImage>> for interior mutability.
- PTE pagefile detection (bits 0/10/11 + pagefile number/offset)
- PageFileFault error variant in page table walker
- PagefileReader: opens disk, extracts pagefile.sys data runs,
binary-search page resolution
- --disk CLI option for explicit disk image in single-file mode
- Folder mode auto-discovers disk and opens pagefile automatically
- Feature-gated behind "sam" (requires NTFS + disk image support)
- Makefile with release/debug/strip/install/check/clippy/test targets
- Show full help with examples when run without arguments (instead of
cryptic clap error)
- Add --version flag, EXAMPLES section, supported input types in help
- Validate --format to text|csv|ntlm
EPROCESS.ImageFileName is a fixed 15-byte field, causing names like
"fontdrvhost.ex", "StartMenuExper", "VGAuthService." to be truncated.
Now reads PEB → ProcessParameters → ImagePathName (UNICODE_STRING) using
each process's own DTB for address translation, extracting just the
filename. Falls back to the 15-byte ImageFileName for kernel processes
(PEB=0) or when PEB pages are paged out.
- Skip PID 0 (System Idle Process) in enumeration: has no valid DTB,
PEB, or name, only adds noise to the listing
- Filter ImageFileName to printable ASCII to prevent replacement
characters from non-UTF8 bytes (e.g. 0xFF fill in Idle process)
- Add hbin-based fallback scan for NTFS-fragmented hives where regf
header and hbin data are at non-contiguous disk locations
- Validate hive sizes: reject SYSTEM < 512KB and SAM < 16KB to avoid
false matches (e.g. 28KB volatile "System" hive)
Three extraction modes:
- LSASS: credentials from .vmem/.vmsn/.sav snapshots (9 SSP providers)
- SAM: NT/LM hashes + LSA secrets from .vdi/.vmdk/.qcow2 disk images
- Folder: auto-discover and process all VM files in a directory
Key features:
- VMware twoGbMaxExtentSparse VMDK with snapshot chain support
- VMDK descriptorless mode for orphan extent files with gap handling
- VirtualBox .sav SSM format with LZF decompression
- VDI dynamic/differencing images with parent chain
- QCOW2 L1/L2 address translation with backing file chain
- MBR/GPT partition tables, NTFS navigation via ntfs crate
- Raw regf + hbin scan fallbacks for incomplete disk images
- Hive size validation to reject false matches
- All 9 mimikatz SSP providers with physical scan fallbacks