From 5aa5b3e747997056106d9bdb75640d840cbbd616 Mon Sep 17 00:00:00 2001 From: devttys0 Date: Sat, 26 Oct 2024 16:17:10 -0400 Subject: [PATCH 1/2] Added os type 7 to MBR signature --- src/structures/mbr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/structures/mbr.rs b/src/structures/mbr.rs index 4bdf50c01..73a57129a 100644 --- a/src/structures/mbr.rs +++ b/src/structures/mbr.rs @@ -34,6 +34,7 @@ pub fn parse_mbr_image(mbr_data: &[u8]) -> Result { ]; let known_os_types = HashMap::from([ + (0x07, "NTFS_IFS_HPFS_exFAT"), (0x0B, "FAT32"), (0x0C, "FAT32"), (0x43, "Linux"), From 4a3957282d43794c94c53c0aba8b940b7f0e62c8 Mon Sep 17 00:00:00 2001 From: devttys0 Date: Sat, 26 Oct 2024 16:59:27 -0400 Subject: [PATCH 2/2] Added NTFS support --- src/magic.rs | 11 ++++++++++ src/signatures.rs | 1 + src/signatures/ntfs.rs | 37 ++++++++++++++++++++++++++++++++ src/structures.rs | 1 + src/structures/ntfs.rs | 48 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 src/signatures/ntfs.rs create mode 100644 src/structures/ntfs.rs diff --git a/src/magic.rs b/src/magic.rs index 7e6113925..a728ce7b5 100644 --- a/src/magic.rs +++ b/src/magic.rs @@ -899,6 +899,17 @@ pub fn patterns() -> Vec { description: signatures::autel::DESCRIPTION.to_string(), extractor: Some(extractors::autel::autel_extractor()), }, + // NTFS + signatures::common::Signature { + name: "ntfs".to_string(), + short: false, + magic_offset: 0, + always_display: false, + magic: signatures::ntfs::ntfs_magic(), + parser: signatures::ntfs::ntfs_parser, + description: signatures::ntfs::DESCRIPTION.to_string(), + extractor: Some(extractors::tsk::tsk_extractor()), + }, ]; binary_signatures diff --git a/src/signatures.rs b/src/signatures.rs index 113711ead..3758e2318 100644 --- a/src/signatures.rs +++ b/src/signatures.rs @@ -143,6 +143,7 @@ pub mod lzfse; pub mod lzma; pub mod lzop; pub mod mbr; +pub mod ntfs; pub mod openssl; pub mod packimg; pub mod pcap; diff --git a/src/signatures/ntfs.rs b/src/signatures/ntfs.rs new file mode 100644 index 000000000..6766bd212 --- /dev/null +++ b/src/signatures/ntfs.rs @@ -0,0 +1,37 @@ +use crate::signatures::common::{SignatureError, SignatureResult, CONFIDENCE_MEDIUM}; +use crate::structures::ntfs::parse_ntfs_header; + +/// Human readable description +pub const DESCRIPTION: &str = "NTFS partition"; + +/// NTFS partitions start with these bytes +pub fn ntfs_magic() -> Vec> { + vec![b"\xEb\x52\x90NTFS\x20\x20\x20\x20".to_vec()] +} + +/// Validates the NTFS header +pub fn ntfs_parser(file_data: &[u8], offset: usize) -> Result { + // Successful return value + let mut result = SignatureResult { + offset, + description: DESCRIPTION.to_string(), + confidence: CONFIDENCE_MEDIUM, + ..Default::default() + }; + + if let Ok(ntfs_header) = parse_ntfs_header(&file_data[offset..]) { + // The reported sector count does not include the NTFS boot sector itself + result.size = ntfs_header.sector_size * (ntfs_header.sector_count + 1); + + // Simple sanity check on the reported total size + if result.size > ntfs_header.sector_size { + result.description = format!( + "{}, number of sectors: {}, bytes per sector: {}, total size: {} bytes", + result.description, ntfs_header.sector_count, ntfs_header.sector_size, result.size + ); + return Ok(result); + } + } + + Err(SignatureError) +} diff --git a/src/structures.rs b/src/structures.rs index 8455b32af..e5c55e9b4 100644 --- a/src/structures.rs +++ b/src/structures.rs @@ -124,6 +124,7 @@ pub mod lzfse; pub mod lzma; pub mod lzop; pub mod mbr; +pub mod ntfs; pub mod openssl; pub mod packimg; pub mod pcap; diff --git a/src/structures/ntfs.rs b/src/structures/ntfs.rs new file mode 100644 index 000000000..7da77c00b --- /dev/null +++ b/src/structures/ntfs.rs @@ -0,0 +1,48 @@ +use crate::structures::common::{self, StructureError}; + +/// Struct to store NTFS info +#[derive(Debug, Default, Clone)] +pub struct NTFSPartition { + pub sector_size: usize, + pub sector_count: usize, +} + +/// Parses an NTFS partition header +pub fn parse_ntfs_header(ntfs_data: &[u8]) -> Result { + // https://en.wikipedia.org/wiki/NTFS + let ntfs_structure = vec![ + ("opcodes", "u24"), + ("magic", "u64"), + ("bytes_per_sector", "u16"), + ("sectors_per_cluster", "u8"), + ("unused1", "u16"), + ("unused2", "u24"), + ("unused3", "u16"), + ("media_type", "u8"), + ("unused4", "u16"), + ("sectors_per_track", "u16"), + ("head_count", "u16"), + ("hidden_sector_count", "u32"), + ("unused5", "u32"), + ("unknown", "u32"), + ("sector_count", "u64"), + ]; + + // Parse the NTFS partition header + if let Ok(ntfs_header) = common::parse(ntfs_data, &ntfs_structure, "little") { + // Sanity check to make sure the unused fields are not used + if ntfs_header["unused1"] == 0 + && ntfs_header["unused2"] == 0 + && ntfs_header["unused3"] == 0 + && ntfs_header["unused4"] == 0 + && ntfs_header["unused5"] == 0 + { + return Ok(NTFSPartition { + sector_count: ntfs_header["sector_count"], + sector_size: ntfs_header["bytes_per_sector"], + }); + } + } + + Err(StructureError) +}