Skip to content

Commit

Permalink
Merge pull request #720 from ReFirmLabs/ntfs_support
Browse files Browse the repository at this point in the history
Ntfs support
  • Loading branch information
devttys0 authored Oct 26, 2024
2 parents 10d233d + 4a39572 commit 5ef95bf
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/magic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,17 @@ pub fn patterns() -> Vec<signatures::common::Signature> {
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
Expand Down
1 change: 1 addition & 0 deletions src/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
37 changes: 37 additions & 0 deletions src/signatures/ntfs.rs
Original file line number Diff line number Diff line change
@@ -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<u8>> {
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<SignatureResult, SignatureError> {
// 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)
}
1 change: 1 addition & 0 deletions src/structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/structures/mbr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub fn parse_mbr_image(mbr_data: &[u8]) -> Result<MBRHeader, StructureError> {
];

let known_os_types = HashMap::from([
(0x07, "NTFS_IFS_HPFS_exFAT"),
(0x0B, "FAT32"),
(0x0C, "FAT32"),
(0x43, "Linux"),
Expand Down
48 changes: 48 additions & 0 deletions src/structures/ntfs.rs
Original file line number Diff line number Diff line change
@@ -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<NTFSPartition, StructureError> {
// 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)
}

0 comments on commit 5ef95bf

Please sign in to comment.