{"id":51595190,"url":"https://github.com/securityronin/vhd-forensic","last_synced_at":"2026-07-11T18:01:45.081Z","repository":{"id":369592399,"uuid":"1290126866","full_name":"SecurityRonin/vhd-forensic","owner":"SecurityRonin","description":"Legacy VHD (Virtual PC) disk-image forensic reader — pure-Rust, read-only, no runtime deps.","archived":false,"fork":false,"pushed_at":"2026-07-06T02:20:14.000Z","size":48899,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-06T04:09:29.555Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SecurityRonin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-05T15:57:04.000Z","updated_at":"2026-07-06T02:20:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SecurityRonin/vhd-forensic","commit_stats":null,"previous_names":["securityronin/vhd-forensic"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/SecurityRonin/vhd-forensic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fvhd-forensic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fvhd-forensic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fvhd-forensic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fvhd-forensic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SecurityRonin","download_url":"https://codeload.github.com/SecurityRonin/vhd-forensic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fvhd-forensic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35370428,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-11T18:01:42.385Z","updated_at":"2026-07-11T18:01:45.073Z","avatar_url":"https://github.com/SecurityRonin.png","language":"Makefile","funding_links":["https://github.com/sponsors/h4x0r"],"categories":[],"sub_categories":[],"readme":"# vhd-forensic\n\n[![Crates.io: vhd-core](https://img.shields.io/crates/v/vhd-core.svg?label=vhd-core)](https://crates.io/crates/vhd-core)\n[![Crates.io: vhd-forensic](https://img.shields.io/crates/v/vhd-forensic.svg?label=vhd-forensic)](https://crates.io/crates/vhd-forensic)\n[![Docs.rs](https://img.shields.io/docsrs/vhd-core)](https://docs.rs/vhd-core)\n[![Rust 1.85+](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://www.rust-lang.org)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)\n[![CI](https://github.com/SecurityRonin/vhd-forensic/actions/workflows/ci.yml/badge.svg)](https://github.com/SecurityRonin/vhd-forensic/actions/workflows/ci.yml)\n[![unsafe: forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/SecurityRonin/vhd-forensic)\n[![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r)\n\n**Read and audit legacy VHD (Virtual PC / Hyper-V Gen-1) disk images in pure Rust — a hardened `Read + Seek` container reader plus a footer integrity analyzer for DFIR.**\n\nThis workspace ships two crates: **`vhd-core`** — the MS-VHD container reader (Fixed and Dynamic disks), exposing a `Read + Seek` view over the virtual sector stream (published as `vhd-core`, imported as `vhd`); and **`vhd-forensic`** — the integrity analyzer that parses the footer *raw* (which the reader validates-and-discards) and reports tamper / structural anomalies as `forensicnomicon::report::Finding`. Zero unsafe code, no C bindings, no external tools.\n\n```toml\n[dependencies]\nvhd-core = \"0.2\"       # reader — imported as `vhd`\nvhd-forensic = \"0.2\"   # analyzer — graded footer findings\n```\n\n## Usage\n\n### Audit a VHD footer for tampering\n\n```rust\nuse vhd_forensic::audit;\nuse forensicnomicon::report::Observation;\n\nfor anomaly in audit(\u0026image_bytes) {\n    let finding = anomaly.to_finding(source);   // canonical forensicnomicon Finding\n    println!(\"{} — {}\", finding.code, finding.note);\n}\n```\n\n### Open a VHD and read the virtual sector stream\n\n```rust\nuse std::io::Read;\nuse vhd::VhdReader;\n\nlet reader = VhdReader::open(std::path::Path::new(\"disk.vhd\"))?;\nprintln!(\"current size:  {} bytes\", reader.virtual_disk_size()); // CurrentSize @48 (readable)\nprintln!(\"original size: {} bytes\", reader.original_size());     // OriginalSize @40 (creation)\n// original_size() != virtual_disk_size()  ⇒  the disk was resized after creation\n```\n\n`VhdReader::open_reader` accepts any `Read + Seek + Send + Sync`, so a VHD stored\ninside an archive can be read without extracting it to a temp file.\n\n## Forensic analysis — `vhd-forensic`\n\n`audit(\u0026[u8])` parses the trailing 512-byte footer at the documented MS-VHD offsets\nand returns typed anomalies; each implements `Observation`, so `.to_finding(source)`\nyields a graded finding.\n\n| Code | Severity | Meaning |\n|---|---|---|\n| `VHD-FOOTER-TRUNCATED` | High | file smaller than the 512-byte footer |\n| `VHD-FOOTER-COOKIE-INVALID` | High | cookie != `conectix` |\n| `VHD-FOOTER-CHECKSUM-MISMATCH` | High | one's-complement checksum tamper / corruption |\n| `VHD-FORMAT-VERSION-UNEXPECTED` | Medium | format version != 1.0 |\n| `VHD-DISK-TYPE-UNKNOWN` | Medium | disk type not Fixed / Dynamic / Differencing |\n| `VHD-DATA-OFFSET-INCONSISTENT` | Medium | `DataOffset` inconsistent with the disk type |\n| `VHD-SAVED-STATE` | Low | image captured in a saved (suspended) state |\n| `VHD-SIZE-RESIZED` | Low | `OriginalSize`@40 != `CurrentSize`@48 — disk resized after creation (History) |\n\n## Trust but verify\n\n- **Panic-free** — `unsafe_code = forbid`, `clippy::unwrap_used`/`expect_used = deny`,\n  bounded readers, and `checked_add`/`checked_mul` on every offset/length from the image.\n- **Fuzzed** — `fuzz_open` (reader) and `fuzz_audit` (analyzer) over arbitrary bytes;\n  local smoke ran 8.1 M / 52 K executions with no panic.\n- **Validated against real qemu-img images with an independent oracle** — including the\n  `current_size` offset bug caught by spec research and fixed against qemu-img's own\n  reported size. See [Validation](https://securityronin.github.io/vhd-forensic/validation/).\n\n## Supported disk types\n\n| Type | Read | Notes |\n|---|---|---|\n| Fixed | ✅ | raw sector data + trailing footer |\n| Dynamic | ✅ | BAT-addressed sparse blocks |\n| Differencing | — | rejected (parent-locator resolution out of scope) |\n\n---\n\n[Privacy Policy](https://securityronin.github.io/vhd-forensic/privacy/) · [Terms of Service](https://securityronin.github.io/vhd-forensic/terms/) · © 2026 Security Ronin Ltd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fvhd-forensic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecurityronin%2Fvhd-forensic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fvhd-forensic/lists"}