{"id":51015052,"url":"https://github.com/securityronin/disk-forensic","last_synced_at":"2026-06-21T09:02:38.025Z","repository":{"id":362795638,"uuid":"1260252837","full_name":"SecurityRonin/disk-forensic","owner":"SecurityRonin","description":"Forensic disk-image orchestrator — decodes E01/VMDK/VHDX/VHD/QCOW2/DMG containers, auto-detects MBR/GPT/APM, and routes ISO 9660 to filesystem analysis","archived":false,"fork":false,"pushed_at":"2026-06-13T18:55:19.000Z","size":240,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-13T19:11:51.451Z","etag":null,"topics":["apm","container","dfir","disk-image","dmg","e01","ewf","forensics","gpt","iso9660","mbr","ntfs","optical","partition","qcow2","rust","udif","vhd","vhdx","vmdk"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","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-06-05T09:52:28.000Z","updated_at":"2026-06-13T18:55:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SecurityRonin/disk-forensic","commit_stats":null,"previous_names":["securityronin/disk-forensic"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SecurityRonin/disk-forensic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fdisk-forensic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fdisk-forensic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fdisk-forensic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fdisk-forensic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SecurityRonin","download_url":"https://codeload.github.com/SecurityRonin/disk-forensic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fdisk-forensic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34603639,"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-06-21T02:00:05.568Z","response_time":54,"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":["apm","container","dfir","disk-image","dmg","e01","ewf","forensics","gpt","iso9660","mbr","ntfs","optical","partition","qcow2","rust","udif","vhd","vhdx","vmdk"],"created_at":"2026-06-21T09:02:32.910Z","updated_at":"2026-06-21T09:02:37.958Z","avatar_url":"https://github.com/SecurityRonin.png","language":"Rust","funding_links":["https://github.com/sponsors/h4x0r"],"categories":[],"sub_categories":[],"readme":"# disk-forensic\n\n[![Crates.io](https://img.shields.io/crates/v/disk-forensic.svg)](https://crates.io/crates/disk-forensic)\n[![docs.rs](https://img.shields.io/docsrs/disk-forensic)](https://docs.rs/disk-forensic)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)\n[![CI](https://github.com/SecurityRonin/disk-forensic/actions/workflows/ci.yml/badge.svg)](https://github.com/SecurityRonin/disk-forensic/actions)\n[![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r)\n\n**`disk4n6` surfaces the structure — and the anomalies — of any disk, whether it's a forensic image on your desk or the live host under your fingers.** Point it at an E01 / VMDK / VHDX / VHD / QCOW2 / DMG / raw `dd` / ISO and it decodes the wrapper, identifies the partitioning scheme (MBR / GPT / APM), and runs the right forensic parser. Run it with no arguments and it maps every physical disk and partition on the running system — macOS, Linux, and Windows, one unified output — with the acquisition-integrity findings you need *before* you image.\n\n## See it work in 30 seconds\n\n```console\n$ cargo install disk-forensic   # crate: disk-forensic, binary: disk4n6\n```\n\n**Triage the live system** — run it bare. No image to decode, no platform-specific tool to remember (`diskutil` / `sfdisk` / `fdisk` all in one):\n\n```console\n$ disk4n6\n```\n\n```text\nAll storage (2 physical disks, 1.1 TB total):\n disk0  [########################################################]    1.0 TB  94.1%\n disk1  [###                                                     ]   64.0 GB   5.9%\n\n/dev/disk0  1.0 TB\n[.=####################################################+.]\n .  -  free (unallocated)              24.6 KB   0.0%\n =  1  disk0s1  C12A7328-F81F-11D2-BA4B-00A0C93EC93B   536.9 MB   0.1%\n #  2  disk0s2  7C3457EF-0000-11AA-AA11-00306543ECAC     1.0 TB  99.4%\n +  3  disk0s3  52637672-7900-11AA-AA11-00306543ECAC     5.4 GB   0.5%\n\n/dev/disk1  64.0 GB\n[=#######################################################]\n =  1  disk1s1  EBD0A0A2-B9E5-4433-87C0-68B6B72699C7   200.0 MB   0.3%\n #  2  disk1s2  EBD0A0A2-B9E5-4433-87C0-68B6B72699C7    63.8 GB  99.7%\n\nAcquisition-integrity findings:\n  disk0  [HIGH] LIVE-MOUNTED: device has mounted volume(s) during acquisition; live writes may alter the image — consistent with imaging a running system\n```\n\nThe overview bar scales every disk against the largest, so relative sizes read at a glance; each per-disk bar lays out partitions and free space proportionally, the largest partition coloured to match its disk in the overview.\n\n**Analyse an image** — hand it the evidence:\n\n```console\n$ disk4n6 evidence.E01          # an EnCase image straight off the shelf\n```\n\n```text\nScheme: Gpt\n\nMBR Forensic Analysis\n  disk signature : 0x00000000\n  boot code      : AllZeros\n  partitioning   : Unknown\n\nPartition table (1 entries):\n  [0] GPT Protective MBR       LBA            1..=409599        fs=Unknown\n\nGPT cross-check: 131 GPT partition entries\n\nGPT Forensic Analysis\n================================================================================\nDisk GUID:       9D71FE48-F2FB-43F1-9326-36644D4D4E70\nRevision:        1.0\n```\n\nThat E01 was decoded, the protective MBR cross-checked, and the GPT parsed — one\ncommand, no intermediate files. Exit code is `0` when clean and `1` when any\nanomaly is present, so it drops straight into a triage pipeline. Add `--json`\n(build with `--features serde`) for machine-readable output in either mode.\n\n## Live triage: one output across macOS, Linux, and Windows\n\nBefore you acquire, you need to know what's attached and whether touching it is safe. `disk4n6` enumerates the host's physical disks and partitions through the native interface on each platform — **macOS IOKit**, **Linux sysfs (`/sys/block`)**, **Windows `DeviceIoControl`** — and normalises them into one model, so the same command and the same output work everywhere. The enumeration and rendering live in [`livedisk-core`](https://crates.io/crates/livedisk-core); the acquisition findings come from [`livedisk-forensic`](https://crates.io/crates/livedisk-forensic).\n\nThe findings are observations bearing on a forensically sound acquisition — never verdicts:\n\n| Code | Meaning |\n|---|---|\n| `LIVE-MOUNTED` | a volume is mounted during acquisition (live writes may alter the image) |\n| `LIVE-WRITABLE` | the device **being acquired** is writable — no write-blocker engaged. Shown when you point `disk4n6` at a specific target device, not in the host overview (every live disk is writable, so flagging it there is noise) |\n| `LIVE-REMOVABLE` | removable media |\n| `LIVE-SECTOR-4KN` | logical/physical sector sizes differ (512e / 4Kn) |\n| `LIVE-SYNTHESIZED` | a synthesized container overlay (APFS container, device-mapper/LVM), not a backing physical store |\n\n`LIVE-SYNTHESIZED` is informational, not a recommendation: whether to image the synthesized device or the underlying physical store is a forensic decision for the examiner, not the tool.\n\n## Feed it almost any image — the wrapper is detected by content, not extension\n\n`disk4n6` sniffs the container magic, decodes it to a `Read + Seek` view of the\nraw disk, and analyses that. Rename a `.vmdk` to `.bin` and it still works.\n\n| Input | Handling |\n|---|---|\n| Raw / `dd` | analysed in place |\n| **E01 / EWF** (EnCase) | decoded |\n| **VMDK** (VMware) | decoded — follows snapshot/delta extent chains to the base image |\n| **VHDX** (Hyper-V) | decoded |\n| **VHD** (Virtual PC, fixed + dynamic) | decoded (built-in) |\n| **QCOW2** (QEMU/KVM) | decoded |\n| **DMG** (Apple UDIF) | decoded — pure-Rust codecs (ADC / zlib / bzip2 / LZFSE / LZMA), no C dependencies |\n| **ISO 9660** (optical) | routed to filesystem analysis (see below) |\n| AFF4 | recognised, but decode to raw first — decoder not yet wired |\n\nA corrupt or unsupported-variant container fails **loud** with a clear decode\nerror rather than silently producing wrong output. The same proportional\npartition-layout view shown for live disks renders for images too, so the disk\nunder analysis reads the same way whether it came off the wire or off the\nshelf.\n\n## Optical media gets a filesystem report\n\nAn ISO is a filesystem, not a partitioned disk, so `disk4n6` routes it to\n[`iso9660-forensic`](https://github.com/SecurityRonin/iso9660-forensic) and\nrenders the same normalized findings / provenance / **timeline** view — volume\nidentity, mastering-tool fingerprint, Rock Ridge authoring owners, structural\nanomalies, and the reconstructed authoring window:\n\n```console\n$ disk4n6 image.iso\n```\n\n```text\nFilesystem: ISO 9660\n\nFindings: none (clean)\n\nProvenance:\n  volume label: DFTEST  (iso9660-forensic)\n  system identifier: APPLE INC., TYPE: 0002  (iso9660-forensic)\n  sector mode: Iso2048  (iso9660-forensic)\n  extensions: Rock Ridge: true, Joliet: true  (iso9660-forensic)\n  sessions: 1  (iso9660-forensic)\n  Rock Ridge owners: uids [501], gids [0]  (iso9660-forensic)\n```\n\nA **Timeline** section then reconstructs the volume's authoring window from the\nPVD and file-recorded times — on real media these diverge into a span you can\nreason about (a file dated *after* its own volume, or in the future, becomes a\nfinding).\n\n## Rust library\n\n```toml\n[dependencies]\ndisk-forensic = \"0.8\"\n```\n\n```rust\nuse std::fs::File;\n\n// Decode whatever container the evidence arrived in, then analyse the disk.\nlet opened = disk_forensic::container::open(std::path::Path::new(\"evidence.E01\"))?;\nlet mut img = opened.reader;\n\nmatch disk_forensic::analyse_disk(\u0026mut img, opened.size)? {\n    disk_forensic::DiskReport::Gpt(a) =\u003e println!(\"GPT: {} partitions\", a.partitions.len()),\n    disk_forensic::DiskReport::Mbr(a) =\u003e println!(\"MBR: {} partitions\", a.partitions.len()),\n    disk_forensic::DiskReport::Apm(a) =\u003e println!(\"APM: {} partitions\", a.partitions.len()),\n}\n# Ok::\u003c(), Box\u003cdyn std::error::Error\u003e\u003e(())\n```\n\n`analyse_disk` takes any `Read + Seek`, so you can also feed it a raw image\ndirectly. A disk with no recognised scheme (e.g. a filesystem written straight to\nthe media) returns [`Error::UnknownScheme`] rather than mis-parsing. Each\nanalyzer normalizes into the shared\n[`forensicnomicon::report`](https://github.com/SecurityRonin/forensicnomicon)\nmodel, so findings and provenance render uniformly across every scheme and the\nISO filesystem layer.\n\nFor live enumeration, depend on [`livedisk-core`](https://crates.io/crates/livedisk-core) directly:\n\n```rust\nfor disk in livedisk::enumerate()? {\n    println!(\"{}: {} bytes, {} partitions\", disk.name, disk.size_bytes, disk.partitions.len());\n}\n# Ok::\u003c(), livedisk::Error\u003e(())\n```\n\n## The scheme parsers\n\n`disk-forensic` is pure orchestration — it classifies the scheme using the cited\nmagics in [`forensicnomicon`](https://github.com/SecurityRonin/forensicnomicon)\nand delegates every real parse to a focused, dependency-light sibling. Use them\ndirectly when you already know the scheme, or through this crate when you don't:\n\n| Crate | Scheme |\n|---|---|\n| [`mbr-partition-forensic`](https://github.com/SecurityRonin/mbr-partition-forensic) | Master Boot Record — boot-code fingerprinting, gap/slack carving, **per-partition VBR filesystem fingerprinting**, protective-MBR/GPT detection |\n| [`gpt-partition-forensic`](https://github.com/SecurityRonin/gpt-partition-forensic) | GUID Partition Table — CRC32 integrity, primary/backup reconciliation |\n| [`apm-partition-forensic`](https://github.com/SecurityRonin/apm-partition-forensic) | Apple Partition Map — classic Mac and hybrid optical media |\n\n## Design\n\n- **Secure by default** — one auto-detecting entry point: a caller cannot pick the wrong decoder or parser for a disk, and the zero-config path is the correct one.\n- **Unified across sources and platforms** — live disks and decoded images render through the same partition-layout view; live enumeration speaks IOKit / sysfs / `DeviceIoControl` behind one model.\n- **Fails loud** — a corrupt container or unknown scheme returns a typed error; it never emits silently wrong output.\n- **`#![forbid(unsafe_code)]`** and fuzz-tested (`cargo fuzz`) against crafted/corrupted input.\n- **Validated against real images**, not just synthetic fixtures — real EnCase/qemu/hdiutil containers and a genuine NTFS volume from a public CTF disk. See [`docs/VALIDATION.md`](docs/VALIDATION.md).\n\n---\n\n[Privacy Policy](https://securityronin.github.io/disk-forensic/privacy/) · [Terms of Service](https://securityronin.github.io/disk-forensic/terms/) · © 2026 Security Ronin Ltd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fdisk-forensic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecurityronin%2Fdisk-forensic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fdisk-forensic/lists"}