From 643c47b3c33e3e9a83eb3c5e3bc793321b2eb463 Mon Sep 17 00:00:00 2001 From: matthew seyer Date: Fri, 19 May 2017 00:05:40 -0500 Subject: Added fullname enumeration --- src/attr_x30.rs | 3 +- src/entry.rs | 72 ++++++++++++++++++++++++++++++++++++---- src/enumerator.rs | 44 +++++++++++++++++++++++++ src/lib.rs | 3 +- src/mft.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 207 insertions(+), 13 deletions(-) create mode 100644 src/enumerator.rs diff --git a/src/attr_x30.rs b/src/attr_x30.rs index 3d4503b..8b99e1e 100644 --- a/src/attr_x30.rs +++ b/src/attr_x30.rs @@ -23,7 +23,8 @@ pub struct FileNameAttribute { pub reparse_value: u32, pub name_length: u8, pub namespace: u8, - pub name: String + pub name: String, + pub fullname: Option } impl FileNameAttribute { pub fn new(mut reader: R) -> Result { diff --git a/src/entry.rs b/src/entry.rs index 0be1a1b..ec9978b 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,4 +1,6 @@ use errors::{MftError}; +use enumerator::{PathEnumerator,PathMapping}; +use mft::{MftHandler}; use attribute; use utils; use attr_x10; @@ -48,7 +50,8 @@ pub struct EntryHeader{ #[serde(skip_serializing)] pub padding: Option, pub record_number: Option, - pub update_sequence_value: u32 + pub update_sequence_value: u32, + pub entry_reference: Option } impl EntryHeader{ pub fn new(mut reader: R, entry: Option) -> Result { @@ -89,6 +92,15 @@ impl EntryHeader{ ) } + if entry_header.record_number.is_some(){ + entry_header.entry_reference = Some( + MftReference::get_from_entry_and_seq( + entry_header.record_number.unwrap() as u64, + entry_header.sequence + ) + ); + } + Ok(entry_header) } } @@ -123,12 +135,43 @@ impl MftEntry{ Ok(mft_entry) } - pub fn buffer_fixup(&self, mut buffer: &mut[u8]){ - // start offset (skip the first value (+2)) - let so = (self.header.usa_offset + 2) as usize; - // array length - let al = (self.header.usa_size - 1 * 2) as usize; + pub fn is_allocated(&self) -> bool { + if self.header.flags.bits() & 0x01 != 0 { + true + } else { + false + } + } + + pub fn is_dir(&self) -> bool { + if self.header.flags.bits() & 0x02 != 0 { + true + } else { + false + } + } + pub fn get_pathmap(&self) -> Option { + match self.attr_filename { + Some(ref attributes) => { + for attribute in attributes { + if attribute.namespace != 2 { + return Some( + PathMapping { + name: attribute.name.clone(), + parent: MftReference(attribute.parent.0) + } + ); + } + } + }, + _ => {} + } + + None + } + + pub fn buffer_fixup(&self, mut buffer: &mut[u8]){ let fixup_values = &buffer[ (self.header.usa_offset + 2) as usize.. ((self.header.usa_offset + 2)+((self.header.usa_size - 1) * 2)) as usize @@ -147,7 +190,7 @@ impl MftEntry{ )?; let attr_count: u32 = 0; - while true { + loop { let attribute_header = attribute::AttributeHeader::new( &mut buffer )?; @@ -189,6 +232,21 @@ impl MftEntry{ } Ok(attr_count) } + + pub fn set_fullnames(&mut self, mft_handler: &mut MftHandler){ + match self.attr_filename { + Some(ref mut attributes) => { + for attribute in attributes { + let fullpath = mft_handler.get_fullpath( + attribute.parent + ); + let fullname = fullpath + "/" + attribute.name.as_str(); + attribute.fullname = Some(fullname); + } + }, + _ => {} + } + } } #[cfg(test)] diff --git a/src/enumerator.rs b/src/enumerator.rs new file mode 100644 index 0000000..70c4403 --- /dev/null +++ b/src/enumerator.rs @@ -0,0 +1,44 @@ +use std::collections::HashMap; +use rwinstructs::reference::{MftReference}; + +#[derive(Hash, Eq, PartialEq, Debug, Clone)] +pub struct PathMapping { + pub name: String, + pub parent: MftReference, +} + +pub struct PathEnumerator { + pub mapping: HashMap +} + +impl PathEnumerator { + pub fn new() -> PathEnumerator { + PathEnumerator{ + mapping: HashMap::new() + } + } + + pub fn get_mapping(&self, reference: MftReference) -> Option { + match self.mapping.get(&reference) { + Some(value) => Some(value.clone()), + None => None + } + } + + pub fn print_mapping(&self){ + println!("{:?}",self.mapping); + } + + pub fn contains_mapping(&self, reference: MftReference) -> bool { + self.mapping.contains_key( + &reference + ) + } + + pub fn set_mapping(&mut self, reference: MftReference, mapping: PathMapping) { + self.mapping.insert( + reference, + mapping + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index dafa329..4a2d5d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,5 @@ #[macro_use] extern crate serde_derive; -#[macro_use] extern crate serde_json; #[macro_use] extern crate bitflags; -#[macro_use] extern crate log; extern crate seek_bufread; extern crate byteorder; extern crate rwinstructs; @@ -12,5 +10,6 @@ pub mod utils; pub mod mft; pub mod entry; pub mod attribute; +pub mod enumerator; pub mod attr_x10; pub mod attr_x30; diff --git a/src/mft.rs b/src/mft.rs index 6654f65..802f381 100644 --- a/src/mft.rs +++ b/src/mft.rs @@ -1,4 +1,6 @@ use seek_bufread::BufReader; +use enumerator::{PathEnumerator,PathMapping}; +use rwinstructs::reference::{MftReference}; use errors::{MftError}; use entry::{MftEntry}; use std::fs::File; @@ -9,6 +11,7 @@ use std::mem; pub struct MftHandler { filehandle: BufReader, + path_enumerator: PathEnumerator, _entry_size: u32, _offset: u64, _size: u64 @@ -55,17 +58,40 @@ impl MftHandler{ ).unwrap(); let mut entry_buffer = vec![0; self._entry_size as usize]; - self.filehandle.read_exact(&mut entry_buffer)?; + self.filehandle.read_exact( + &mut entry_buffer + )?; - let mft_entry = self.entry_from_buffer( + let mut mft_entry = self.entry_from_buffer( entry_buffer, entry )?; + // We need to set the path if dir + match mft_entry.get_pathmap() { + Some(mapping) => { + if mft_entry.is_dir() { + &self.path_enumerator.set_mapping( + mft_entry.header.entry_reference.clone().unwrap(), + mapping.clone() + ); + } + }, + None => {}, + } + + mft_entry.set_fullnames( + self + ); + Ok(mft_entry) } - pub fn entry_from_buffer(&mut self, mut buffer: Vec, entry: u64) -> Result { + pub fn print_mapping(&self){ + self.path_enumerator.print_mapping(); + } + + pub fn entry_from_buffer(&mut self, buffer: Vec, entry: u64) -> Result { let mft_entry = MftEntry::new( buffer, Some(entry) @@ -73,4 +99,70 @@ impl MftHandler{ Ok(mft_entry) } + + pub fn get_fullpath(&mut self, reference: MftReference) -> String { + let mut path_stack = Vec::new(); + self.enumerate_path_stack( + &mut path_stack, + reference + ); + path_stack.join("/") + } + + fn enumerate_path_stack(&mut self, name_stack: &mut Vec, reference: MftReference) { + // 1407374883553285 (5-5) + if reference.0 == 1407374883553285 { + + } + else { + match self.path_enumerator.get_mapping(reference){ + Some(mapping) => { + self.enumerate_path_stack( + name_stack, + mapping.parent.clone() + ); + name_stack.push( + mapping.name.clone() + ); + }, + None => { + // Mapping not exists + // Get entry number for this reference that does not exist + let entry = reference.get_entry_number(); + // Gat mapping for it + match self.get_mapping_from_entry(entry) { + Some(mapping) => { + self.path_enumerator.set_mapping( + reference, + mapping.clone() + ); + self.enumerate_path_stack( + name_stack, + reference + ); + }, + None => {} + } + } + } + } + } + + fn get_mapping_from_entry(&mut self, entry: u64) -> Option{ + self.filehandle.seek( + SeekFrom::Start(entry * self._entry_size as u64) + ); + + let mut entry_buffer = vec![0; self._entry_size as usize]; + self.filehandle.read_exact( + &mut entry_buffer + ); + + let mut mft_entry = self.entry_from_buffer( + entry_buffer, + entry + ); + + mft_entry.unwrap().get_pathmap() + } } -- cgit v1.2.3