idkkkkkkkkkk

This commit is contained in:
Janis 2022-11-23 08:03:14 +01:00
parent 3c11b23ad8
commit 8b66a135c5

View file

@ -4,9 +4,12 @@
pub mod error { pub mod error {
use core::fmt::Display; use core::fmt::Display;
use crate::Version;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum BaseBlockVerifyError { pub enum BaseBlockVerifyError {
BadSignature, BadSignature,
IncompatibleVersion(Version),
IncompatibleMajorVersion, IncompatibleMajorVersion,
IncompatibleMinorVersion, IncompatibleMinorVersion,
BadFileType, BadFileType,
@ -16,14 +19,21 @@ pub mod error {
impl Display for BaseBlockVerifyError { impl Display for BaseBlockVerifyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self { match self {
BaseBlockVerifyError::BadSignature => "Bad Signature", BaseBlockVerifyError::BadSignature => f.write_str("Bad Signature"),
BaseBlockVerifyError::IncompatibleMajorVersion => "Incompatible Major Version", BaseBlockVerifyError::IncompatibleVersion(version) => {
BaseBlockVerifyError::IncompatibleMinorVersion => "Incompatible Minor Version", f.write_fmt(format_args!("{:?}", version))
BaseBlockVerifyError::BadFileType => "Bad File Type (self.kind)", }
BaseBlockVerifyError::BadFormat => "Bad Format", BaseBlockVerifyError::IncompatibleMajorVersion => {
BaseBlockVerifyError::Cluster => "Not the correct Cluster", f.write_str("Incompatible Major Version")
}) }
BaseBlockVerifyError::IncompatibleMinorVersion => {
f.write_str("Incompatible Minor Version")
}
BaseBlockVerifyError::BadFileType => f.write_str("Bad File Type (self.kind)"),
BaseBlockVerifyError::BadFormat => f.write_str("Bad Format"),
BaseBlockVerifyError::Cluster => f.write_str("Not the correct Cluster"),
}
} }
} }
@ -100,11 +110,27 @@ pub mod cell_data {
data_len: u32, data_len: u32,
data: Offset, data: Offset,
data_type: u32, data_type: u32,
flags: u16, flags: KeyValueFlags,
spare: u16, spare: u16,
value_name: ZstPtr, value_name: ZstPtr,
} }
bitflags! {
#[repr(C)]
#[derive(Zeroable, Pod)]
pub struct KeyValueFlags: u16 {
/// Value name is an ASCII string, possibly an extended ASCII string
/// (otherwise it is a UTF-16LE string)
const VALUE_COMP_NAME = 0x1;
/// Is a tombstone value (the flag is used starting from Insider
/// Preview builds of Windows 10 "Redstone 1"), a tombstone value
/// also has the Data type field set to REG_NONE, the Data size
/// field set to 0, and the Data offset field set to 0xFFFFFFFF
const IS_TOMBSTONE = 0x2;
}
}
/// KeySecurity items form a doubly linked list. A key security item may /// KeySecurity items form a doubly linked list. A key security item may
/// act as a list header or a list entry (the only difference here is the /// act as a list header or a list entry (the only difference here is the
/// meaning of f_link and b_link fields). /// meaning of f_link and b_link fields).
@ -155,6 +181,12 @@ pub mod cell_data {
data: &'a [u8], data: &'a [u8],
} }
impl<'a> Cell<'a> {
pub fn into_any_cell(self) -> AnyCell<'a> {
self.into()
}
}
impl<'a> From<&'a super::RawCell> for Cell<'a> { impl<'a> From<&'a super::RawCell> for Cell<'a> {
fn from(raw: &'a super::RawCell) -> Self { fn from(raw: &'a super::RawCell) -> Self {
let data = unsafe { let data = unsafe {
@ -446,22 +478,29 @@ pub mod cell_data {
impl KeyValue { impl KeyValue {
pub fn data_type(&self) -> DataType { pub fn data_type(&self) -> DataType {
match self.data_type { self.data_type.into()
0x00 => DataType::None, }
0x01 => DataType::Sz,
0x02 => DataType::ExpandSz, pub fn small_data(&self) -> Option<[u8; 4]> {
0x03 => DataType::Binary, let data_len = self.data_len;
0x04 => DataType::DWordLE, let data = self.data.0;
0x05 => DataType::DWordBE,
0x06 => DataType::Link, if data_len.bit(31) && self.data_len() <= 4 {
0x07 => DataType::MultiSz, let mut ret = [0; 4];
0x08 => DataType::ResourceList, ret[..self.data_len()]
0x09 => DataType::FullResourceDescriptor, .copy_from_slice(&bytemuck::bytes_of(&data)[..self.data_len()]);
0x0a => DataType::ResourceRequirementsList,
0x0b => DataType::QWordLE, Some(ret)
_ => DataType::Other(self.data_type), } else {
None
} }
} }
pub fn data_len(&self) -> usize {
let data_len = self.data_len;
BitRange::<u32>::bit_range(&data_len, 0, 31) as usize
}
} }
impl CellHeader { impl CellHeader {
@ -497,6 +536,26 @@ pub mod cell_data {
Other(u32), Other(u32),
} }
impl From<u32> for DataType {
fn from(value: u32) -> Self {
match value {
0x00 => Self::None,
0x01 => Self::Sz,
0x02 => Self::ExpandSz,
0x03 => Self::Binary,
0x04 => Self::DWordLE,
0x05 => Self::DWordBE,
0x06 => Self::Link,
0x07 => Self::MultiSz,
0x08 => Self::ResourceList,
0x09 => Self::FullResourceDescriptor,
0x0a => Self::ResourceRequirementsList,
0x0b => Self::QWordLE,
_ => Self::Other(value),
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -512,8 +571,10 @@ pub mod cell_data {
} }
} }
use core::borrow::Borrow;
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use cell_data::Cell; use cell_data::{AnyCell, Cell, KeyNode};
use error::BaseBlockVerifyError; use error::BaseBlockVerifyError;
use ptr::ZstPtr; use ptr::ZstPtr;
@ -523,35 +584,137 @@ extern crate alloc;
#[repr(C, packed)] #[repr(C, packed)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)] #[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct BaseBlockSequence { pub struct BaseBlockSequence {
/// This number is incremented by 1 in the beginning of a write operation on
/// the primary file
before: u32, before: u32,
/// This number is incremented by 1 at the end of a write operation on the
/// primary file, a primary sequence number and a secondary sequence number
/// should be equal after a successful write operation
after: u32, after: u32,
} }
#[repr(C, packed)] #[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)] #[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct Offset(u32); pub struct Offset(u32);
#[repr(C, packed)] #[derive(Debug)]
pub struct Hive<'a> {
base_block: &'a BaseBlock,
hive_bins: &'a [u8],
}
impl<'a> Hive<'a> {
pub fn new(bytes: &'a [u8]) -> Option<Self> {
(bytes.len() >= 0x1000)
.then_some(())
.and_then(|_| {
let base_block = bytemuck::from_bytes::<BaseBlock>(bytes);
let bytes = &bytes[0x1000..];
let hive_bins_len = base_block.hive_bins_len();
(bytes.len() >= hive_bins_len).then_some((base_block, &bytes[..hive_bins_len]))
})
.map(|(base_block, hive_bins)| Self {
base_block,
hive_bins,
})
}
pub fn root_key(&self) -> Option<&KeyNode> {
let offset = self.base_block.root_cell().offset()?;
let a = bytemuck::from_bytes::<RawCell>(&self.hive_bins[offset..]);
let cell = Cell::from(a);
if let AnyCell::KeyNode(key_node) = cell.into_any_cell() {
Some(key_node)
} else {
None
}
}
}
#[repr(C, packed(2))]
#[derive(Debug, Copy, Clone, Pod, Zeroable)] #[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct BaseBlock { pub struct BaseBlock {
/// ASCII string signature equal to `b"regf"`
signature: u32, signature: u32,
sequence: BaseBlockSequence, sequence: BaseBlockSequence,
time_stmap: u64, /// FILETIME (UTC)
major: u32, time_stamp: u64,
minor: u32, version: Version,
/// file_type, 0 means primary file
kind: u32, kind: u32,
/// 1 means direct memory load
format: u32, format: u32,
/// Offset of a root cell in bytes, relative from the start of the hive bins data
root_cell: Offset, root_cell: Offset,
length: u32, /// Size of the hive bins data in bytes
cluster: u32, hive_bins_len: u32,
/// Logical sector size of the underlying disk in bytes divided by 512
clustering_factor: u32,
/// UTF-16LE string (contains a partial file path to the primary file, or a file name of the primary file), used for debugging purposes
file_name: [u16; 32], file_name: [u16; 32],
reserved: [u32; 99], win10_fields1: Win10BaseBlock1,
reserved: [u32; 83],
/// XOR-32 checksum of the previous 508 bytes
checksum: u32, checksum: u32,
reserved2: [u32; 0x37E], reserved2: [u32; 0x372],
win10_fields2: Win10BaseBlock2,
boot_type: u32, boot_type: u32,
boot_recover: u32, boot_recover: u32,
} }
#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Pod, Zeroable)]
pub struct Win10BaseBlock1 {
rm_id: u128,
log_id: u128,
flags: u32,
tm_id: u128,
guid_signature: [u8; 4],
last_reorganized_timestamp: u64,
}
#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Pod, Zeroable)]
pub struct Win10BaseBlock2 {
thaw_tm_id: u128,
thaw_rm_id: u128,
thaw_log_id: u128,
}
#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Pod, Zeroable)]
pub struct Version {
major: u32,
minor: u32,
}
impl Version {
pub const V1_3: Self = Self::new(1, 3);
pub const V1_4: Self = Self::new(1, 4);
pub const V1_5: Self = Self::new(1, 5);
pub const V1_6: Self = Self::new(1, 6);
pub const fn new(major: u32, minor: u32) -> Self {
Self { major, minor }
}
/// returns true if `&self` is any of `[Self::V1_3, Self::V1_4, Self::V1_5, Self::V1_6]`.
pub fn is_valid(&self) -> bool {
[Self::V1_3, Self::V1_4, Self::V1_5, Self::V1_6].contains(self)
}
pub fn major(&self) -> u32 {
self.major
}
pub fn minor(&self) -> u32 {
self.minor
}
}
#[repr(C, packed)] #[repr(C, packed)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)] #[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct BinHeader { pub struct BinHeader {
@ -662,11 +825,22 @@ impl Offset {
impl BaseBlock { impl BaseBlock {
const SIGNATURE: u32 = 0x66676572; const SIGNATURE: u32 = 0x66676572;
const MAJOR: u32 = 1;
const MINOR: u32 = 3;
const FILE_TYPE_PRIMARY: u32 = 0; const FILE_TYPE_PRIMARY: u32 = 0;
const BASE_FORMAT_MEMORY: u32 = 1; const BASE_FORMAT_MEMORY: u32 = 1;
#[cfg(feature = "alloc")]
pub fn debug_file_name(&self) -> Result<alloc::string::String, alloc::string::FromUtf16Error> {
use alloc::string::String;
let name = &self.file_name;
let name_len = name.iter().take_while(|&&b| b != 0).count();
String::from_utf16(&self.file_name[..name_len])
}
pub fn hive_bins_len(&self) -> usize {
self.hive_bins_len as usize
}
pub fn calculate_checksum(&self) -> u32 { pub fn calculate_checksum(&self) -> u32 {
let bytes = bytemuck::bytes_of(self); let bytes = bytemuck::bytes_of(self);
// let data = bytemuck::cast_slice::<_, u32>(&bytes[..508]); // let data = bytemuck::cast_slice::<_, u32>(&bytes[..508]);
@ -688,12 +862,9 @@ impl BaseBlock {
(self.signature == Self::SIGNATURE) (self.signature == Self::SIGNATURE)
.then_some(()) .then_some(())
.ok_or(BaseBlockVerifyError::BadSignature)?; .ok_or(BaseBlockVerifyError::BadSignature)?;
(self.major == Self::MAJOR) (self.version.is_valid())
.then_some(()) .then_some(())
.ok_or(BaseBlockVerifyError::IncompatibleMajorVersion)?; .ok_or(BaseBlockVerifyError::IncompatibleVersion(self.version))?;
(self.minor == Self::MINOR)
.then_some(())
.ok_or(BaseBlockVerifyError::IncompatibleMinorVersion)?;
(self.kind == Self::FILE_TYPE_PRIMARY) (self.kind == Self::FILE_TYPE_PRIMARY)
.then_some(()) .then_some(())
.ok_or(BaseBlockVerifyError::BadFileType)?; .ok_or(BaseBlockVerifyError::BadFileType)?;
@ -701,7 +872,7 @@ impl BaseBlock {
.then_some(()) .then_some(())
.ok_or(BaseBlockVerifyError::BadFormat)?; .ok_or(BaseBlockVerifyError::BadFormat)?;
(self.cluster == 1) (self.clustering_factor == 1)
.then_some(()) .then_some(())
.ok_or(BaseBlockVerifyError::BadSignature)?; .ok_or(BaseBlockVerifyError::BadSignature)?;
Ok(self.dirty()) Ok(self.dirty())
@ -717,6 +888,10 @@ impl BaseBlock {
pub fn dirty(&self) -> bool { pub fn dirty(&self) -> bool {
self.sequence.dirty() || self.calculate_checksum() != self.checksum self.sequence.dirty() || self.calculate_checksum() != self.checksum
} }
pub fn root_cell(&self) -> Offset {
self.root_cell
}
} }
impl BaseBlockSequence { impl BaseBlockSequence {