# vmspect
[](https://crates.io/crates/vmspect)
[](LICENSE)
[]()
`vmspect` is a Rust library and CLI tool for **ultra-fast static inspection, forensic analysis and information extraction of virtual machine disk images** (VMDK, RAW, QCOW2, VHD, VHDX, VDI, etc.).
It can examine partition-table structures (MBR/GPT), identify the guest operating system (Windows/Linux), extract complete lists of installed software and detect integration tools (Guest Tools) in a **non-invasive** way (without booting the virtual machine or requiring mount privileges on the host) in **less than 70 ms** even for virtual disks larger than 80 GiB.
---
## π Key Features
- **Extreme performance and lightweight streaming (<70 ms for 80 GiB images):**
- **Native Rust parser:** Direct, ultra-low-latency reading for `RAW` and `VMDK` images (`monolithicSparse`, `monolithicFlat`, `twoGbMaxExtentFlat/Sparse`, etc.) without external dependencies or child processes.
- **Integrated `qemu-nbd` server:** For complex formats (`QCOW2`, `VHDX`, `VDI`, compressed/streamOptimized VMDK), connects over a local TCP socket (`127.0.0.1`) or UNIX sockets using the standard NBD protocol, with direct block streaming and no temporary files on disk.
- **Resilience against dirty registries and NTFS fallback (Graceful Degradation):**
- **Permissive Windows Registry reading:** Tolerance for dirty or damaged registry hives (`SequenceNumberMismatch` caused by abrupt shutdowns or hot snapshots) using `Hive::without_validation` and isolating internal panics from third-party libraries via `catch_unwind`.
- **NTFS fallback inspection:** If the Registry hives are totally inaccessible, `vmspect` gracefully degrades by inspecting the PE header of `\Windows\System32\ntoskrnl.exe` directly to extract the OS build and version, and scans `\Program Files`, tagging applications as `source: Some("FallbackFS")`.
- **Non-fatal warnings list:** Reports issues in the `warnings` field of the report without aborting the inspection pipeline.
- **Multi-hypervisor, hypervisor-agnostic Guest Tools detection:**
- Full and typed support in the `GuestTools` struct to identify and extract the version of:
- **VMware Tools / open-vm-tools**
- **VirtualBox Guest Additions**
- **QEMU Guest Agent**
- **Hyper-V Integration Services**
- **Supported guest operating systems:**
- **Windows (NTFS):** Extracts Registry hives (`SOFTWARE` and `SYSTEM`) by parsing uninstall keys (32 and 64-bit), operating system version, build number, Service Pack and Guest Tools.
- **Linux (ext2 / ext3 / ext4):** Reads `/etc/os-release`, `/etc/hostname` and analyzes the `/var/lib/dpkg/status` package database along with virtualization agents.
- **Scheme and file-system detection:**
- Partition schemes: **MBR**, **GPT** and **Volumes without a partition table**.
- Signature recognition: **NTFS**, **FAT12/16/32**, **ext2/3/4**, **XFS**, **Btrfs**, **LVM2 PV**, **Linux Swap**.
- **Agnostic and complete extraction:**
- Default, complete collection of all applications and system information without noise filters or proprietary categorizations.
- Support for `--no-apps` (disables application collection) and `--no-system` (disables OS metadata collection) flags.
- **Designed for UI and CLI:**
- Emits progress events in structured percentages (`0%` to `100%`) ideal for **Tauri**, **egui** or **Electron**.
- Cancellation support via atomic tokens (`Arc<AtomicBool>` / `CancellationToken`) while preserving partial results.
---
## DiagnΓ³stico de discos VMDK y `qemu-nbd`
Un descriptor VMDK no siempre contiene los datos del disco. Puede declarar varios extents
(`FLAT`, `VMFS`, `VMFSRAW`, `SPARSE` o `VMFSSPARSE`) y tambiΓ©n puede apuntar a un disco padre
mediante `parentFileNameHint`. Todos esos archivos forman parte de la entrada que debe estar
disponible para la inspecciΓ³n.
Cuando falta un componente, `vmspect` devuelve `VmSpectError::MissingDiskComponent` en lugar de
`VmSpectError::QemuNotFound`. El error conserva el nombre declarado, el descriptor principal,
la ruta resuelta y el error original del sistema operativo. Por ejemplo:
```text
Missing VMDK extent 'drive-0-cl2-s001.vmdk' referenced by 'D:\PLC NΒ°4\MΓ‘quinas Virtuales\Windows UE 6.0 ROckWell Revs 9\drive-0-cl2.vmdk'. Resolved path: 'D:\PLC NΒ°4\MΓ‘quinas Virtuales\Windows UE 6.0 ROckWell Revs 9\drive-0-cl2-s001.vmdk'. OS error: The system cannot find the file specified.
```
`qemu-nbd` no puede reparar una cadena VMDK incompleta: solo proporciona acceso a una imagen
que ya es coherente. Si falta un extent o un disco padre, hay que recuperar el archivo correcto
desde el almacenamiento original o desde una copia consistente. No se debe renombrar otro
extent para sustituir al faltante, porque eso puede mezclar segmentos distintos y producir una
imagen silenciosamente corrupta.
Los errores de resoluciΓ³n del ejecutable (`qemu_nbd`, `QEMU_NBD` o `PATH`) se reportan como
`QemuNotFound`. Los fallos del proceso ya iniciado βcΓ³digo de salida distinto de cero,
`stderr`, handshake o timeout NBDβ se reportan como `Nbd` y conservan el contexto de ejecuciΓ³n.
---
## π Crate Structure
The project follows the standard Rust library package convention:
```text
vmspect/
βββ Cargo.toml # Crate configuration, metadata and dependencies
βββ readme.md # Main documentation
βββ LICENSE # MIT / Apache-2.0 license
βββ src/
β βββ lib.rs # Library entry point (public API and re-exports)
β βββ models/ # Domain types (InspectionReport, GuestInfo, Partition, etc.)
β β βββ image.rs
β β βββ options.rs # Inspection options, progress and cancellation
β β βββ partition.rs
β β βββ software.rs # Program and GuestInfo models
β β βββ traits.rs # Abstract traits (OsInspector, VmDriver, MemoryMapper)
β βββ parsers/ # Per-OS analyzers
β β βββ mod.rs # OsInspector trait and polymorphic factory
β β βββ windows.rs # NTFS extraction and Registry parsing (nt-hive)
β β βββ linux.rs # ext4 superblock reading and DPKG database
β β βββ desconocido.rs # Handling of unrecognized operating systems
β βββ vms/ # Disk access and virtualization layer
β βββ mod.rs # Disk access module
β βββ detector.rs # MBR/GPT detection and FS signatures
β βββ nbd.rs # Native NBD client and qemu-nbd connector
β βββ stream.rs # DiskReader facade and VirtualDisk view (Read + Seek)
β βββ vmdk.rs # Native VMDK parser (sparse and descriptors)
βββ tests/ # Integration tests
β βββ integration_test.rs
βββ examples/ # Ready-to-run usage examples
βββ basic_inspection.rs
```
---
## π¦ Installation
Add `vmspect` to your `Cargo.toml`:
```toml
[dependencies]
vmspect = "0.5.0"
```
---
## π‘ Examples as a Library
### 1. Full Inspection with Guest Tools, Warnings and Progress
```rust
use std::path::Path;
use vmspect::{inspect_with_progress, Options, InspectionProgressEvent};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = Path::new("virtual_disk.vmdk");
// Options configuration (e.g. full OS and application analysis)
let options = Options::default();
let report = inspect_with_progress(path, &options, |p: InspectionProgressEvent| {
println!("[{:>3}%] {} - {}", p.percentage, p.stage, p.detail.unwrap_or_default());
})?;
println!("Disk format: {}", report.image.format);
println!("Operating system: {:?}", report.operating_system);
println!("OS details: {}", report.guest_info.formatted_os_string());
// Hypervisor-agnostic Guest Tools detection (VMware, VirtualBox, QEMU, Hyper-V)
if let Some(ref tools) = report.guest_info.guest_tools {
if tools.present {
println!("Guest tools: {} (version: {})", tools.kind, tools.version.as_deref().unwrap_or("N/A"));
}
}
// Non-fatal warnings (graceful Registry/FS degradation)
if !report.warnings.is_empty() {
println!("Inspection warnings:");
for w in &report.warnings {
println!(" [!] {}", w);
}
}
println!("Partitions detected: {}", report.partitions.len());
println!("Installed software found: {}", report.installed_programs.len());
for prog in report.installed_programs.iter().take(10) {
let source = prog.source.as_deref().map(|s| format!(" [{}]", s)).unwrap_or_default();
println!(
" - {} (v{}) [Publisher: {}]{}",
prog.name,
prog.version.as_deref().unwrap_or("N/A"),
prog.publisher.as_deref().unwrap_or("N/A"),
source
);
}
Ok(())
}
```
### 2. Advanced Extraction Options
```rust
use vmspect::Options;
// Disable application or system extraction depending on performance needs:
let light_options = Options {
no_apps: true, // Skip installed-software scan
no_system: false, // Keep OS detection and Guest Tools
force_nbd: false, // Use the ultra-fast native parser when available
..Options::default()
};
assert!(!light_options.should_analyze_apps());
assert!(light_options.should_analyze_system());
```
### 3. Concurrent Processing and Result Preservation on Cancellation
`ConcurrentProcessor` and `InspectionEngine` provide clean shutdown (Graceful Shutdown) with **partial-result preservation**. When the cancellation token is triggered, worker threads do not accept new images, safely finish the in-progress analysis and return all successfully processed reports:
```rust
use std::path::PathBuf;
use vmspect::prelude::*;
fn main() -> Result<()> {
let paths = vec![
PathBuf::from("srv1.vmdk"),
PathBuf::from("srv2.raw"),
PathBuf::from("srv3.qcow2"),
PathBuf::from("srv4.vhdx"),
];
let cancel = CancellationToken::new();
let options = Options::default()
.with_cancellation_token(&cancel);
let engine = InspectionEngine::new(options);
// Cancel at any time from another thread or callback:
// cancel.cancel();
// Returns all reports completed before and during cancellation:
let completed_reports = engine.inspect_batch(paths, 4)?;
println!("Total reports recovered: {}", completed_reports.len());
for r in &completed_reports {
println!(" - {} (OS: {:?})", r.image.path.display(), r.operating_system);
}
Ok(())
}
```
### 4. Tauri / Async Runtime Integration
```rust,ignore
use tauri::Emitter;
use vmspect::{inspect_with_progress, InspectionReport, InspectionProgressEvent, Options};
#[tauri::command]
async fn inspect_vm(app_handle: tauri::AppHandle, path: String) -> Result<InspectionReport, String> {
let path = std::path::PathBuf::from(path);
let options = Options::default();
tauri::async_runtime::spawn_blocking(move || {
inspect_with_progress(&path, &options, |p: InspectionProgressEvent| {
let _ = app_handle.emit("inspection_progress", p);
})
.map_err(|e| e.to_string())
})
.await
.map_err(|e| e.to_string())?
}
```
---
## π₯οΈ Command-Line Interface (CLI) Usage
`vmspect` ships a high-performance terminal binary:
```bash
# Standard inspection with human-formatted output:
vmspect /path/to/disk.vmdk
# Structured JSON output (ideal for scripts, CI/CD pipelines and forensic analysis):
vmspect /path/to/disk.qcow2 --json
# Concurrent recursive scan of a full VM directory:
vmspect /var/lib/libvirt/images/ --concurrent --recursive --workers 8
# Fast inspection skipping application extraction:
vmspect /path/to/disk.vhdx --no-apps
# Inspection skipping OS metadata:
vmspect /path/to/disk.raw --no-system
```
---
## π οΈ Running Tests and Examples
### Run Unit and Integration Tests:
```bash
cargo test
```
### Run Example with a Real Disk:
```bash
cargo run --example basic_inspection -- /path/to/your/disk.vmdk
```
---
## π License
This project is licensed under the **MIT** or **Apache-2.0** license at your option.