Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added pbs parser for disk info #24

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod cli;
mod errors;
mod reader;
mod undelete_entry;
mod util;

fn main() -> Result<()> {
env_logger::builder()
Expand Down
65 changes: 34 additions & 31 deletions src/reader.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use log::info;
use mft::{
attribute::{
non_resident_attr::NonResidentAttr, x80::DataAttr, MftAttributeContent, MftAttributeType,
},
MftEntry,
};

use crate::errors::Result;
use crate::{
errors::Result,
util::{detect_file_system, FileSystems},
};
use std::{
fs::File,
io::{BufRead, BufReader, Read, Seek, SeekFrom},
Expand All @@ -15,14 +19,6 @@ use std::{
#[derive(Debug)]
pub struct Reader {
path: PathBuf,
reader_type: ReaderType,
}

#[derive(Debug)]
enum ReaderType {
Directory,
Image,
BlockDevice,
}

const CLUSTER_SIZE: usize = 4096; // 4 KiB
Expand All @@ -31,31 +27,48 @@ const SIGNATURES: [&[u8]; 3] = [b"FILE", b"BAAD", b"0000"];

impl Reader {
pub fn from_path(path: PathBuf) -> Result<Self> {
let reader_type = if path.is_dir() {
ReaderType::Directory
let path = if path.is_dir() {
let configued_path =
find_block_device(&path)?.ok_or_else(|| crate::errors::Error::Any {
detail: "Couldn't find block device for directory".to_string(),
})?;
info!(
"Running in dir mode, will map to block device: {}",
configued_path.display()
);
configued_path
} else if path.is_file() {
ReaderType::Image
info!("Running in image mode");
path
} else if path.starts_with("/dev/") {
ReaderType::BlockDevice
info!("Running in block mode");
path
} else {
return Err(crate::errors::Error::FailedToOpenFile {
path,
source: std::io::Error::new(std::io::ErrorKind::NotFound, "File not found"),
});
};

Ok(Self { path, reader_type })
let boot_sector = match detect_file_system(&path)? {
FileSystems::Ntfs(boot_sector) => boot_sector,
fs => {
return Err(crate::errors::Error::Any {
detail: format!("Detected an unsupported file system: {}", fs),
})
}
};

info!("Parsed boot sector: \n{:#?}", boot_sector);

Ok(Self { path })
}

pub fn read_mft(&self) -> Result<Vec<u8>> {
match self.reader_type {
ReaderType::Directory => self.read_mft_dir(),
ReaderType::Image => self.read_mft_bytes(),
ReaderType::BlockDevice => self.read_mft_bytes(),
}
self.read_mft_bytes()
}

fn read_mft_dir(&self) -> Result<Vec<u8>> {
fn _read_mft_dir(&self) -> Result<Vec<u8>> {
let path = self.path.join("$MFT");

if !path.exists() {
Expand Down Expand Up @@ -115,17 +128,7 @@ impl Reader {
}

fn read_from_data_run(&self, data: NonResidentAttr) -> Result<Vec<u8>> {
let mut file = match self.reader_type {
ReaderType::Directory => {
let block_device = find_block_device(&self.path)?;
let block_device = block_device.ok_or_else(|| crate::errors::Error::Any {
detail: "Couldn't find block device for directory".to_string(),
})?;

File::open(block_device)?
}
_ => File::open(&self.path)?,
};
let mut file = File::open(&self.path)?;
let mut bytes = vec![];
for dr in data.data_runs {
let mut cluster = vec![0; dr.lcn_length as usize * CLUSTER_SIZE];
Expand Down
164 changes: 164 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use crate::errors::Result;
use std::{
fmt::Display,
fs::File,
io::{Read, Seek},
path::Path,
};
#[derive(PartialEq, Clone)]
pub enum FileSystems {
Ntfs(NtfsBootSector),
Fat,
Ext,
Iso9660,
Hfs,
Unknown,
}

impl From<FileSystems> for &str {
fn from(value: FileSystems) -> Self {
match value {
FileSystems::Ntfs(_) => "Ntfs",
FileSystems::Fat => "Fat",
FileSystems::Ext => "Ext",
FileSystems::Iso9660 => "Iso9660",
FileSystems::Hfs => "Hfs",
FileSystems::Unknown => "Unknown",
}
}
}

impl Display for FileSystems {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.clone().into())
}
}

pub fn detect_file_system<P>(path: P) -> Result<FileSystems>
where
P: AsRef<Path>,
{
let mut file = File::open(path)?;
let mut boot_sector = [0u8; 512];

file.read_exact(&mut boot_sector)?;

if &boot_sector[3..7] == b"Ntfs" {
return Ok(FileSystems::Ntfs(NtfsBootSector::from_bytes(&boot_sector)?));
}

if &boot_sector[36..39] == b"Fat" {
return Ok(FileSystems::Fat);
}

if &boot_sector[0..2] == b"H+" || &boot_sector[0..4] == b"HfsJ" || &boot_sector[0..4] == b"Hfs+"
{
return Ok(FileSystems::Hfs);
}

if &boot_sector[56..58] == b"\x53\xEF" {
return Ok(FileSystems::Ext);
}

let mut iso_buffer = [0u8; 5];
file.seek(std::io::SeekFrom::Start(32769))?;
file.read_exact(&mut iso_buffer)?;

if &iso_buffer[..] == b"CD001" {
return Ok(FileSystems::Iso9660);
}

Ok(FileSystems::Unknown)
}

#[derive(Debug, Clone, PartialEq)]
pub struct NtfsBootSector {
oem_id: String,
bytes_per_sector: u16,
sectors_per_cluster: u8,
reserved_sectors: u16,
media_descriptor: u8,
sectors_per_track: u16,
num_heads: u16,
hidden_sectors: u32,
total_sectors: u64,
logical_cluster_mft: u64,
logical_cluster_mft_mirror: u64,
clusters_per_file_record_segment: u32,
clusters_per_index_buffer: u8,
volume_serial_number: u64,
checksum: u32,
}

impl NtfsBootSector {
fn from_bytes(boot_sector_data: &[u8]) -> Result<Self> {
Ok(Self {
oem_id: String::from_utf8_lossy(&boot_sector_data[3..11]).to_string(),
bytes_per_sector: u16::from_le_bytes([boot_sector_data[0x0B], boot_sector_data[0x0C]]),
sectors_per_cluster: boot_sector_data[0x0D],
reserved_sectors: u16::from_le_bytes([boot_sector_data[0x0E], boot_sector_data[0x0F]]),
media_descriptor: boot_sector_data[0x15],
sectors_per_track: u16::from_le_bytes([boot_sector_data[0x18], boot_sector_data[0x19]]),
num_heads: u16::from_le_bytes([boot_sector_data[0x1A], boot_sector_data[0x1B]]),
hidden_sectors: u32::from_le_bytes([
boot_sector_data[0x1C],
boot_sector_data[0x1D],
boot_sector_data[0x1E],
boot_sector_data[0x1F],
]),
total_sectors: u64::from_le_bytes([
boot_sector_data[0x28],
boot_sector_data[0x29],
boot_sector_data[0x2A],
boot_sector_data[0x2B],
boot_sector_data[0x2C],
boot_sector_data[0x2D],
boot_sector_data[0x2E],
boot_sector_data[0x2F],
]),
logical_cluster_mft: u64::from_le_bytes([
boot_sector_data[0x30],
boot_sector_data[0x31],
boot_sector_data[0x32],
boot_sector_data[0x33],
boot_sector_data[0x34],
boot_sector_data[0x35],
boot_sector_data[0x36],
boot_sector_data[0x37],
]),
logical_cluster_mft_mirror: u64::from_le_bytes([
boot_sector_data[0x38],
boot_sector_data[0x39],
boot_sector_data[0x3A],
boot_sector_data[0x3B],
boot_sector_data[0x3C],
boot_sector_data[0x3D],
boot_sector_data[0x3E],
boot_sector_data[0x3F],
]),
clusters_per_file_record_segment: u32::from_le_bytes([
boot_sector_data[0x40],
boot_sector_data[0x41],
boot_sector_data[0x42],
boot_sector_data[0x43],
]),
clusters_per_index_buffer: boot_sector_data[0x44],
volume_serial_number: u64::from_le_bytes([
boot_sector_data[0x48],
boot_sector_data[0x49],
boot_sector_data[0x4A],
boot_sector_data[0x4B],
boot_sector_data[0x4C],
boot_sector_data[0x4D],
boot_sector_data[0x4E],
boot_sector_data[0x4F],
]),
checksum: u32::from_le_bytes([
boot_sector_data[0x50],
boot_sector_data[0x51],
boot_sector_data[0x52],
boot_sector_data[0x53],
]),
})
}
}
Loading