vmdk-forensic
Forensic integrity analysis for VMware VMDK images. The evidence-grade layer on top of the vmdk reader — it reparses the raw structure (so it works on images too damaged to open cleanly) and reports the redundant-grain-directory, dangling-pointer, recovery, and header-provenance findings that qemu-img and libvmdk discard.
Quick start
use VmdkIntegrity;
use Severity;
let mut a = new;
for finding in a.analyse?
# Ok::
What it detects
analyse() aggregates every check into a severity-graded Vec<Finding> of
canonical forensicnomicon::report
findings (sorted worst-first), so VMDK findings normalize alongside every other
SecurityRonin analyzer. Each carries a stable code, a 5-level severity, a
category, and a plain-language note.
| Severity | code |
Meaning |
|---|---|---|
| High | VMDK-RGD-MISMATCH |
The redundant grain directory diverges from the primary — the grain tables they reference hold different contents (compared by content, not pointers, so healthy two-copy images don't false-positive). Consistent with MITRE ATT&CK T1565.001 |
| High | VMDK-DANGLING-GT |
A grain-table pointer points beyond end-of-file (truncation or tampering) |
| High | VMDK-DANGLING-GRAIN |
A grain pointer points beyond end-of-file |
| High | VMDK-PRIMARY-GD-UNRECOVERABLE |
The primary grain directory is damaged with no RGD recovery available |
| High | VMDK-FTP-ASCII-MANGLED |
Header newline-detection bytes were rewritten by an ASCII-mode FTP transfer |
| Medium | VMDK-PRIMARY-GD-RECOVERABLE |
The primary grain directory is damaged but recoverable via the redundant copy |
| Low | VMDK-UNCLEAN-SHUTDOWN |
uncleanShutdown flag set — the disk was not closed cleanly |
Individual checks
Each finding is also available directly:
use VmdkIntegrity;
let mut a = new;
// Redundant-GD adjudication: are the grain tables the GD and RGD reference identical?
let rgd_ok = a.validate_rgd?;
// Recovery triage: how much of a damaged primary GD can the RGD recover?
let rec = a.grain_directory_recovery?;
println!;
// Structural integrity: dangling GD/GT/grain pointers (VMDK4 sparse + seSparse).
let integ = a.check_integrity?;
assert!;
// Header provenance: unclean-shutdown flag, FTP-ASCII-mangling, flag bits.
if let Some = a.header_provenance?
# Ok::
Reader vs. analyzer
This is the same split as vhdx/vhdx-forensic and ewf/ewf-forensic:
vmdk— the leanRead + Seekreader. Use it to read virtual-disk bytes, including the opt-in RGD-fallback recovery read path.vmdk-forensic— this crate. Use it to audit an image before trusting it: tamper/corruption detection, recovery triage, and provenance. It re-exportsvmdk::VmdkReader, so one dependency covers read + analysis.
Trust but verify
Built to run on untrusted, potentially crafted images: every offset derived from a
header field uses saturating arithmetic and is bounds-checked before any read or
allocation; the grain-directory size is capped (16 MiB); zero unsafe
(unsafe_code = "forbid" workspace-wide). The analysis pipeline has a dedicated
cargo fuzz target (fuzz_forensic), and the underlying vmdk-core reader is
cross-validated byte-for-byte against qemu-img convert -O raw on real
COWD/seSparse images — so the analyzer and its fixtures don't share a blind spot.
Findings are observations, not legal conclusions — MITRE ATT&CK references
(e.g. T1565.001 on VMDK-RGD-MISMATCH) read "consistent with," and the analyst
draws the conclusion.
Privacy Policy · Terms of Service · © 2026 Security Ronin Ltd