Skip to main content

forensicnomicon_core/
volatility.rs

1//! Artifact volatility model — RFC 3227 Order of Volatility encoded as data.
2//!
3//! [`VolatilityClass`] is the rating type stored on
4//! [`crate::catalog::ArtifactDescriptor::volatility`]. The catalog-querying helpers
5//! (`volatility_for`, `acquisition_order`) live in the umbrella `forensicnomicon`
6//! crate, where the assembled global catalog is wired.
7
8/// Acquisition urgency for a forensic artifact under RFC 3227 Order of Volatility.
9///
10/// Values run from 0 (lowest urgency / most stable) to 4 (highest urgency / most
11/// ephemeral). `acquisition_order` (umbrella crate) returns artifacts sorted 4→0
12/// (most ephemeral first), matching live-response triage practice.
13///
14/// ## Choosing the right class
15///
16/// | Class | Collect when | Rationale |
17/// |---|---|---|
18/// | `Volatile` | Immediately — before reboot | Only in RAM |
19/// | `RotatingBuffer` | Before buffer fills | Fixed-size circular store |
20/// | `ActivityDriven` | Before more user activity | Overwritten by normal use |
21/// | `Persistent` | Standard scheduled collection | Present until explicit deletion |
22/// | `Residual` | Last — always present on a live volume | Storage-level structure |
23///
24/// ## What `Residual` means — and what it does NOT mean
25///
26/// `Residual` is the **lowest acquisition urgency** class. Use it only for artifacts
27/// that are **structurally present on any live mounted volume** and cannot be
28/// destroyed by normal system operation (only by reformatting, physical destruction,
29/// or deliberate forensic manipulation). The canonical example is `$MFT` — any
30/// mounted NTFS volume always has an MFT; it is the last artifact you need to rush
31/// to collect.
32///
33/// **`Residual` does NOT mean "recoverable via .LOG1/.LOG2, VSS, or $UsnJrnl after
34/// deletion."** That property applies to virtually every NTFS artifact and provides
35/// no discrimination between classes. A registry key that *could* be recovered from
36/// a transaction log after deletion is `Persistent` while it exists — use `Persistent`
37/// for all live registry keys and files regardless of post-deletion recoverability.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
39#[non_exhaustive]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub enum VolatilityClass {
42    /// Storage-level artifact inherently present on any live mounted volume — cannot
43    /// be destroyed by normal system operation. Lowest acquisition urgency: collect
44    /// last. Example: `$MFT` (always present on NTFS), Volume Boot Record.
45    ///
46    /// **Not** a synonym for "recoverable via VSS/.LOG1/.LOG2 after deletion" — that
47    /// applies to virtually all NTFS artifacts and is not discriminating.
48    Residual = 0,
49    /// Present in its primary location until explicitly deleted. Default class for
50    /// registry keys, configuration files, and most forensic artifacts on a live
51    /// system. Examples: Run keys, NTDS.dit, event log files (the file itself, not
52    /// its contents — for contents see `RotatingBuffer`).
53    Persistent = 1,
54    /// Overwritten by ordinary user activity; degrades with normal system use.
55    /// Examples: MRU lists, Recent Documents, browser history, typed URL cache.
56    ActivityDriven = 2,
57    /// Overwritten when a fixed-size circular buffer fills; oldest entries lost.
58    /// Examples: Windows Event Log records (when log reaches max size), Prefetch
59    /// files (128-entry limit), $UsnJrnl (wraps based on configured max size).
60    RotatingBuffer = 3,
61    /// Lost on reboot or process termination; exists only in volatile memory.
62    /// Collect immediately in a live response before system shutdown.
63    /// Examples: RAM contents, process handles, network connections, open file
64    /// handles, the in-memory ShimCache state not yet flushed to registry.
65    Volatile = 4,
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn volatility_ordering_is_consistent() {
74        assert!(VolatilityClass::Volatile > VolatilityClass::RotatingBuffer);
75        assert!(VolatilityClass::RotatingBuffer > VolatilityClass::ActivityDriven);
76        assert!(VolatilityClass::ActivityDriven > VolatilityClass::Persistent);
77        assert!(VolatilityClass::Persistent > VolatilityClass::Residual);
78    }
79}