https://github.com/securityronin/apm-partition-forensic
Read-only Apple Partition Map (APM) reader + forensic anomaly auditor — overlaps, out-of-bounds, residual entries, hidden gaps as graded findings. Pure Rust, no unsafe.
https://github.com/securityronin/apm-partition-forensic
apm apple-partition-map dfir digital-forensics disk-image forensics macintosh partition partition-table rust
Last synced: 27 days ago
JSON representation
Read-only Apple Partition Map (APM) reader + forensic anomaly auditor — overlaps, out-of-bounds, residual entries, hidden gaps as graded findings. Pure Rust, no unsafe.
- Host: GitHub
- URL: https://github.com/securityronin/apm-partition-forensic
- Owner: SecurityRonin
- License: other
- Created: 2026-06-04T09:52:34.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-06-21T08:54:48.000Z (about 2 months ago)
- Last Synced: 2026-06-21T09:21:15.024Z (about 2 months ago)
- Topics: apm, apple-partition-map, dfir, digital-forensics, disk-image, forensics, macintosh, partition, partition-table, rust
- Language: Rust
- Size: 158 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# apm-partition-forensic
[](https://crates.io/crates/apm-partition-core)
[](https://crates.io/crates/apm-partition-forensic)
[](https://docs.rs/apm-partition-forensic)
[](LICENSE)
[](https://github.com/SecurityRonin/apm-partition-forensic/actions)
[](https://github.com/sponsors/h4x0r)
**Read an Apple Partition Map — then grade its structural anomalies into severity-ranked forensic findings.**
A read-only APM reader (Driver Descriptor Map + partition entries: name, type, bounds) paired with an anomaly auditor that flags exactly what a forensic examiner looks for: map-count disagreement, overlapping or out-of-bounds partitions, residual (hidden) entries, and unmapped interior regions that could conceal data. Pure Rust, no `unsafe`.
```rust
use apm_forensic::analyse;
let report = analyse(&std::fs::read("disk.img")?)?;
for a in &report.anomalies {
println!("[{}] {}: {}", a.severity, a.code, a.note);
}
# Ok::<(), apm_forensic::Error>(())
```
```text
APM Forensic Analysis
block size : 512 bytes
device blocks : 6144
Partition map (2 entries):
[0] Apple Apple_partition_map blocks 1..=63
[1] disk image Apple_HFS blocks 64..=6143
Anomalies: none
Highest severity: none (clean)
```
`apm-partition-forensic` is a **library**. For a ready-made command line that
auto-detects the scheme and prints this for *any* disk, install the unified
[`disk4n6`](https://github.com/SecurityRonin/disk-forensic) tool
(`cargo install disk-forensic`).
## Two crates
| Crate | Import as | Role |
|---|---|---|
| [`apm-partition-core`](https://crates.io/crates/apm-partition-core) | `apm` | Read-only reader: Driver Descriptor Map + partition entries (`parse`, `ApplePartitionMap`, `ApmPartition`) |
| [`apm-partition-forensic`](https://crates.io/crates/apm-partition-forensic) | `apm_forensic` | Anomaly auditor: `analyse` / `analyse_reader` → graded `Anomaly` findings, built on the reader |
The forensic crate re-exports the reader's `parse`, `ApplePartitionMap`, `ApmPartition`, and `Error`, so depending on it alone gives you both layers.
## Install
```toml
[dependencies]
apm-partition-forensic = "0.4" # analyzer + re-exported reader
# or, reader only:
apm-partition-core = "0.4"
```
## Quick start
```rust
// `data` begins at the device's first byte (block 0 = Driver Descriptor Map).
let data: Vec = std::fs::read("disk.img")?;
if let Some(map) = apm_forensic::parse(&data) {
println!("{}-byte blocks, {} partitions", map.block_size, map.partitions.len());
for p in &map.partitions {
println!(" {:<24} {} start {} ({} blocks)", p.type_name, p.name, p.start_block, p.block_count);
}
if let Some(hfs) = map.hfs_partition() {
println!("Apple_HFS at block {}", hfs.start_block);
}
}
```
## What it parses
| Capability | Notes |
|---|---|
| Driver Descriptor Map | `ER` signature, device block size |
| Partition entries | `PM` entries: name, type, start block, block count |
| HFS lookup | `hfs_partition()` finds the first `Apple_HFS` slice |
## Forensic anomaly detection
`parse()` gives you the layout; `analyse()` (byte slice) and `analyse_reader()`
(any `Read + Seek`, for composing with container crates) add a severity-ranked
anomaly pass:
```rust
let report = apm_forensic::analyse(&std::fs::read("disk.img")?)?;
for a in &report.anomalies {
println!("[{}] {}: {}", a.severity, a.code, a.note);
}
# Ok::<(), apm_forensic::Error>(())
```
| Anomaly | Code | Severity |
|---|---|---|
| Overlapping partitions | `APM-PART-OVERLAP` | Critical |
| Partition out of bounds | `APM-PART-OOB` | High |
| Residual (deleted) entry | `APM-PART-RESIDUAL` | High |
| Missing `Apple_partition_map` self-entry | `APM-NO-MAP-ENTRY` | High |
| `pmMapBlkCnt` disagreement | `APM-MAP-COUNT` | Medium |
| Unmapped region (possible hidden data) | `APM-UNMAPPED` | Medium |
| Zero-length partition | `APM-PART-ZEROLEN` | Low |
| Unknown partition type | `APM-PART-UNKNOWN` | Info |
Partition-type strings are graded against the
[`forensicnomicon`](https://github.com/SecurityRonin/forensicnomicon) knowledge
base. Each anomaly is an *observation* ("consistent with …"), never a verdict —
the examiner draws the conclusion.
## Trust, but verify
These crates parse untrusted, attacker-controllable disk images, so the bar is
*never panic, never read out of bounds, never trust a length field*:
- **Panic-free** — production code carries no `unwrap`/`expect`/`panic!`, enforced as a hard `deny` by the workspace lints; integers are read through bounds-checked helpers that return `0` rather than panicking on a short slice, and the entry count is capped (`MAX_PARTITIONS`) against a corrupt map.
- **Fuzzed** — `cargo fuzz` targets drive the `parse` reader and the full `analyse` audit pipeline; the invariant is "must not panic" on any input.
- **Independent-oracle tested (Tier 1)** — the reader is cross-checked against a real `hdiutil`-created APM by **two independent decoders**, The Sleuth Kit's `mmls -t mac` and Apple's `pdisk -dump`, which re-decode the same committed bytes; the test reconciles the crate's parse against their actual reported entry count, type, start block, and block count (and asserts the two oracles agree with each other). The anomaly *auditor* detectors are still exercised only by hand-built fixtures (Tier 3). The honest, per-capability validation state is documented at [`docs/validation.md`](https://securityronin.github.io/apm-partition-forensic/validation/).
- **No `unsafe`** — `unsafe_code = "forbid"` across the workspace.
## Related
Part of the [Security Ronin](https://github.com/SecurityRonin) forensic toolkit. Sibling partition readers: [`gpt-forensic`](https://github.com/SecurityRonin/gpt-forensic), [`mbr-forensic`](https://github.com/SecurityRonin/mbr-forensic). The [`disk-forensic`](https://github.com/SecurityRonin/disk-forensic) orchestrator auto-detects the scheme and dispatches to whichever of the three fits. Filesystems: [`hfsplus-forensic`](https://github.com/SecurityRonin/hfsplus-forensic), [`udf-forensic`](https://github.com/SecurityRonin/udf-forensic). Consumed by [`iso9660-forensic`](https://github.com/SecurityRonin/iso9660-forensic) for Apple hybrid discs.
---
[Privacy Policy](https://securityronin.github.io/apm-partition-forensic/privacy/) · [Terms of Service](https://securityronin.github.io/apm-partition-forensic/terms/) · © 2026 Security Ronin Ltd