Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/mft.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorforensicmatt <matthew.seyer@gmail.com>2020-03-23 22:18:51 +0300
committerforensicmatt <matthew.seyer@gmail.com>2020-03-23 22:18:51 +0300
commita46d9c9702f1de78ac1be88b525fecc7db03f612 (patch)
treeba3edc2ebc0e4de510036e0e5734a0346c15e9e9
parent7aaf855db0f5bfe95dc651c6f61dc5d992b4ded5 (diff)
Warn on fixup validation instead of fail
Warn that not all fixup array items were validated, but continue parsing. Added `valid_fixup` to MftEntry. Added tests.
-rw-r--r--CHANGELOG.md4
-rw-r--r--samples/entry_102130_fixup_issuebin0 -> 1024 bytes
-rw-r--r--src/entry.rs37
-rw-r--r--tests/test_entry.rs17
4 files changed, 48 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 75c4f1d..dd589d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,8 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Attribute list parsing
+### Changed
+- Warn on fixup mismatch instead of fail
+
### Added
- Additional File Attribute flags
+- `valid_fixup` field to MftEntry
## [0.5.1] - 2020-02-06
diff --git a/samples/entry_102130_fixup_issue b/samples/entry_102130_fixup_issue
new file mode 100644
index 0000000..60d1b7c
--- /dev/null
+++ b/samples/entry_102130_fixup_issue
Binary files differ
diff --git a/src/entry.rs b/src/entry.rs
index f1a0b53..0c0bb48 100644
--- a/src/entry.rs
+++ b/src/entry.rs
@@ -1,7 +1,7 @@
use crate::err::{Error, Result};
use crate::impl_serialize_for_bitflags;
-use log::trace;
+use log::{trace, warn};
use winstructs::ntfs::mft_reference::MftReference;
@@ -29,6 +29,10 @@ pub const FILE_HEADER: &[u8; 4] = b"FILE";
pub struct MftEntry {
pub header: EntryHeader,
pub data: Vec<u8>,
+ /// Valid fixup allows you to check if the fixup value in the entry's blocks
+ /// matched the fixup array value. It is optional because in the case of
+ /// from_buffer_skip_fixup(), no fixup is even checked, thus, valid_fixup is None
+ pub valid_fixup: Option<bool>
}
impl ser::Serialize for MftEntry {
@@ -40,6 +44,7 @@ impl ser::Serialize for MftEntry {
let attributes: Vec<MftAttribute> = self.iter_attributes().filter_map(Result::ok).collect();
state.serialize_field("header", &self.header)?;
state.serialize_field("attributes", &attributes)?;
+ state.serialize_field("valid_fixup", &self.valid_fixup)?;
state.end()
}
}
@@ -175,13 +180,16 @@ impl MftEntry {
let entry_header = EntryHeader::from_reader(&mut cursor, entry_number)?;
trace!("Number of sectors: {:#?}", entry_header);
- if entry_header.is_valid() {
- Self::apply_fixups(&entry_header, &mut buffer)?;
- }
+ let valid_fixup = if entry_header.is_valid() {
+ Some(Self::apply_fixups(&entry_header, &mut buffer)?)
+ } else {
+ None
+ };
Ok(MftEntry {
header: entry_header,
data: buffer,
+ valid_fixup
})
}
@@ -203,6 +211,7 @@ impl MftEntry {
Ok(MftEntry {
header: entry_header,
data: buffer,
+ valid_fixup: None
})
}
@@ -236,7 +245,10 @@ impl MftEntry {
/// https://docs.microsoft.com/en-us/windows/desktop/devnotes/multi-sector-header
/// **Note**: The fixup will be written at the end of each 512-byte stride,
/// even if the device has more (or less) than 512 bytes per sector.
- fn apply_fixups(header: &EntryHeader, buffer: &mut [u8]) -> Result<()> {
+ /// The returned result is true if all fixup blocks had the fixup array value, or
+ /// false if a block's fixup value did not match the array's value.
+ fn apply_fixups(header: &EntryHeader, buffer: &mut [u8]) -> Result<bool> {
+ let mut valid_fixup = true;
let number_of_fixups = u32::from(header.usa_size - 1);
trace!("Number of fixups: {}", number_of_fixups);
@@ -262,17 +274,22 @@ impl MftEntry {
&mut buffer[end_of_sector_bytes_start_offset..end_of_sector_bytes_end_offset];
if end_of_sector_bytes != update_sequence {
- return Err(Error::FailedToApplyFixup {
+ // An item in the block did not match the fixup array value
+ warn!(
+ "[entry: {}] fixup bytes are not equal to update sequence value - stride_number: {}, end_of_sector_bytes: {:?}, fixup_bytes: {:?}",
+ header.record_number,
stride_number,
- end_of_sector_bytes: end_of_sector_bytes.to_vec(),
- fixup_bytes: fixup_bytes.to_vec(),
- });
+ end_of_sector_bytes.to_vec(),
+ fixup_bytes.to_vec()
+ );
+
+ valid_fixup = false;
}
end_of_sector_bytes.copy_from_slice(&fixup_bytes);
}
- Ok(())
+ Ok(valid_fixup)
}
pub fn is_allocated(&self) -> bool {
diff --git a/tests/test_entry.rs b/tests/test_entry.rs
new file mode 100644
index 0000000..c95f2c7
--- /dev/null
+++ b/tests/test_entry.rs
@@ -0,0 +1,17 @@
+use mft::entry::MftEntry;
+use serde_json;
+
+#[test]
+fn test_entry_invalid_fixup_value() {
+ let mft_entry_buffer = include_bytes!("../samples/entry_102130_fixup_issue");
+
+ let entry = MftEntry::from_buffer(
+ mft_entry_buffer.to_vec(),
+ 102130
+ ).expect("Failed to parse entry");
+
+ assert_eq!(entry.valid_fixup, Some(false));
+
+ let mft_json_value = serde_json::to_value(&entry).expect("Error serializing MftEntry");
+ assert_eq!(mft_json_value["valid_fixup"], serde_json::value::Value::from(false));
+} \ No newline at end of file