Documentation
How it works
The detection pipeline: the backward $LogFile LSN walk, three independent corroboration channels, and the incomplete-inversion guard.
Image parsing: $MFT, $LogFile, $UsnJrnl#
The pipeline parses three NTFS structures with a custom parser and no external NTFS library. Every read is structural, and anything it cannot parse soundly is surfaced rather than guessed.
- $MFT: the FILE record is read with mandatory Update Sequence Array fixup. A USA mismatch is a hard failure, not a best guess, because attribute bytes at sector boundaries are wrong without it.
- $LogFile: restart pages are parsed to locate the record stream, and multi-page records are reassembled by concatenating the data area of each RCRD page, so a record that spans a page boundary is recovered rather than dropped.
- $UsnJrnl: the change journal is parsed for the target file reference as an additional cross-check. When no records match, that is recorded as a possible rollover, never as a clean result.
Parsing stops at the first structurally invalid record. The $LogFile is a circular buffer, so the live region is followed by stale bytes that do not decode as records. Emitting those could seed a false reconstruction, so only the contiguous run of valid records is used.
The backward LSN walk#
NTFS records the before image of metadata operations as undo data so a transaction can be rolled back. logflip replays that undo chain in reverse. It starts from the current, tampered $SI bytes, finds the highest-LSN record that targets the MFT record, and follows the chain backward, applying each record undo bytes at the right offset until it reaches the baseline.
On the canonical run, that walk recovered the pre-tamper creation time for MFT record 24: the stomped 2009-01-01T00:00:00Z resolved back to 2026-06-07T00:38:59.2703686Z.
Note
Three independent channels, by failure mode#
Independence here is about failure modes, not record counts. Two of the channels share a root cause, so they count as one class, not two:
- Reverse-replay inversion and the $UsnJrnl cross-check both live in the journal, so they share the circular-buffer raw-disk-edit failure class. They corroborate each other but do not add up to two independent classes.
- SI-vs-FN delta is the genuinely independent third source. It does not share the circular-buffer failure mode, so it is the channel that lets a finding span two distinct classes.
A nonzero SI-vs-FN delta is a necessary condition for many SI-only timestomping tools but not sufficient for attribution. Many legitimate files carry a nonzero delta because $FILE_NAME is updated only at create, rename, and reparent.
The incomplete-inversion guard#
The walk is only allowed to conclude when it can reconstruct soundly. When it cannot, it returns an explicit incomplete result rather than a guess. Circular-buffer rollover, cross-client log chains, sequence non-monotonicity, and out-of-bounds undo all resolve to INCONCLUSIVE. The tool refuses to reconstruct what it cannot reconstruct soundly.
This guard is the core of the never-false-confirm property. A rolled- over journal yields no reconstructed pre-tamper state to disagree about, so it cannot manufacture a finding. Events older than the live journal window are INCONCLUSIVE, not clean.