use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{self, Cursor, Read, Write};
use crate::error::{Error, Result};
use crate::structures::{decode_ascii_string, decode_utf16le_string, encode_ascii_string,
encode_utf16le_string, signatures, INVALID_OFFSET};
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KeyNodeFlags: u16 {
const KEY_VOLATILE = 0x0001;
const KEY_HIVE_EXIT = 0x0002;
const KEY_HIVE_ENTRY = 0x0004;
const KEY_NO_DELETE = 0x0008;
const KEY_SYM_LINK = 0x0010;
const KEY_COMP_NAME = 0x0020;
const KEY_PREDEF_HANDLE = 0x0040;
const VIRTUAL_SOURCE = 0x0080;
const VIRTUAL_TARGET = 0x0100;
const VIRTUAL_STORE = 0x0200;
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UserFlags: u8 {
const KEY_32BIT = 0x01;
const REFLECTION_CREATED = 0x02;
const DISABLE_REFLECTION = 0x04;
const EXTENDED = 0x08;
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VirtualizationFlags: u8 {
const DONT_VIRTUALIZE = 0x02;
const DONT_SILENT_FAIL = 0x04;
const RECURSE_FLAG = 0x08;
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AccessBits: u8 {
const ACCESSED_BEFORE_INIT = 0x01;
const ACCESSED_AFTER_INIT = 0x02;
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugFlags: u8 {
const BREAK_ON_OPEN = 0x01;
const BREAK_ON_DELETE = 0x02;
const BREAK_ON_SECURITY_CHANGE = 0x04;
const BREAK_ON_CREATE_SUBKEY = 0x08;
const BREAK_ON_DELETE_SUBKEY = 0x10;
const BREAK_ON_SET_VALUE = 0x20;
const BREAK_ON_DELETE_VALUE = 0x40;
const BREAK_ON_KEY_VIRTUALIZE = 0x80;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum LayerSemantics {
None = 0,
IsTombstone = 1,
IsSupersedeLocal = 2,
IsSupersedeTree = 3,
}
impl From<u8> for LayerSemantics {
fn from(value: u8) -> Self {
match value & 0x03 {
0 => LayerSemantics::None,
1 => LayerSemantics::IsTombstone,
2 => LayerSemantics::IsSupersedeLocal,
3 => LayerSemantics::IsSupersedeTree,
_ => unreachable!(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LayeredKeyFlags {
raw: u8,
}
impl LayeredKeyFlags {
pub fn from_raw(raw: u8) -> Self {
Self { raw }
}
pub fn raw(&self) -> u8 {
self.raw
}
pub fn inherit_class(&self) -> bool {
(self.raw & 0x80) != 0
}
pub fn layer_semantics(&self) -> LayerSemantics {
LayerSemantics::from(self.raw & 0x03)
}
}
#[derive(Debug, Clone)]
pub struct KeyNode {
pub signature: [u8; 2],
pub flags: u16,
pub last_written: u64,
pub access_bits: u8,
pub layered_key_flags: u8,
pub access_spare: u16,
pub parent: u32,
pub num_subkeys: u32,
pub num_volatile_subkeys: u32,
pub subkeys_list_offset: u32,
pub volatile_subkeys_list_offset: u32,
pub num_values: u32,
pub values_list_offset: u32,
pub security_offset: u32,
pub class_name_offset: u32,
pub largest_subkey_name_length: u16,
pub virtualization_flags: u8,
pub user_flags: u8,
pub debug: u8,
pub largest_subkey_class_name_length: u32,
pub largest_value_name_length: u32,
pub largest_value_data_size: u32,
pub work_var: u32,
pub key_name_length: u16,
pub class_name_length: u16,
pub key_name: Vec<u8>,
}
impl KeyNode {
pub const FIXED_SIZE: usize = 76;
pub fn parse(data: &[u8]) -> Result<Self> {
if data.len() < Self::FIXED_SIZE {
return Err(Error::BufferTooSmall {
needed: Self::FIXED_SIZE,
available: data.len(),
});
}
let mut cursor = Cursor::new(data);
let mut signature = [0u8; 2];
cursor.read_exact(&mut signature)?;
if &signature != signatures::KEY_NODE {
return Err(Error::InvalidSignature {
expected: "nk".to_string(),
found: String::from_utf8_lossy(&signature).to_string(),
});
}
let flags = cursor.read_u16::<LittleEndian>()?;
let last_written = cursor.read_u64::<LittleEndian>()?;
let access_bits = cursor.read_u8()?;
let layered_key_flags = cursor.read_u8()?;
let access_spare = cursor.read_u16::<LittleEndian>()?;
let parent = cursor.read_u32::<LittleEndian>()?;
let num_subkeys = cursor.read_u32::<LittleEndian>()?;
let num_volatile_subkeys = cursor.read_u32::<LittleEndian>()?;
let subkeys_list_offset = cursor.read_u32::<LittleEndian>()?;
let volatile_subkeys_list_offset = cursor.read_u32::<LittleEndian>()?;
let num_values = cursor.read_u32::<LittleEndian>()?;
let values_list_offset = cursor.read_u32::<LittleEndian>()?;
let security_offset = cursor.read_u32::<LittleEndian>()?;
let class_name_offset = cursor.read_u32::<LittleEndian>()?;
let largest_subkey_name_combined = cursor.read_u32::<LittleEndian>()?;
let largest_subkey_name_length = (largest_subkey_name_combined & 0xFFFF) as u16;
let virtualization_flags = ((largest_subkey_name_combined >> 16) & 0x0F) as u8;
let user_flags = ((largest_subkey_name_combined >> 20) & 0x0F) as u8;
let debug = ((largest_subkey_name_combined >> 24) & 0xFF) as u8;
let largest_subkey_class_name_length = cursor.read_u32::<LittleEndian>()?;
let largest_value_name_length = cursor.read_u32::<LittleEndian>()?;
let largest_value_data_size = cursor.read_u32::<LittleEndian>()?;
let work_var = cursor.read_u32::<LittleEndian>()?;
let key_name_length = cursor.read_u16::<LittleEndian>()?;
let class_name_length = cursor.read_u16::<LittleEndian>()?;
let name_start = Self::FIXED_SIZE;
let name_end = name_start + key_name_length as usize;
if data.len() < name_end {
return Err(Error::BufferTooSmall {
needed: name_end,
available: data.len(),
});
}
let key_name = data[name_start..name_end].to_vec();
Ok(Self {
signature,
flags,
last_written,
access_bits,
layered_key_flags,
access_spare,
parent,
num_subkeys,
num_volatile_subkeys,
subkeys_list_offset,
volatile_subkeys_list_offset,
num_values,
values_list_offset,
security_offset,
class_name_offset,
largest_subkey_name_length,
virtualization_flags,
user_flags,
debug,
largest_subkey_class_name_length,
largest_value_name_length,
largest_value_data_size,
work_var,
key_name_length,
class_name_length,
key_name,
})
}
pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&self.signature)?;
writer.write_u16::<LittleEndian>(self.flags)?;
writer.write_u64::<LittleEndian>(self.last_written)?;
writer.write_u8(self.access_bits)?;
writer.write_u8(self.layered_key_flags)?;
writer.write_u16::<LittleEndian>(self.access_spare)?;
writer.write_u32::<LittleEndian>(self.parent)?;
writer.write_u32::<LittleEndian>(self.num_subkeys)?;
writer.write_u32::<LittleEndian>(self.num_volatile_subkeys)?;
writer.write_u32::<LittleEndian>(self.subkeys_list_offset)?;
writer.write_u32::<LittleEndian>(self.volatile_subkeys_list_offset)?;
writer.write_u32::<LittleEndian>(self.num_values)?;
writer.write_u32::<LittleEndian>(self.values_list_offset)?;
writer.write_u32::<LittleEndian>(self.security_offset)?;
writer.write_u32::<LittleEndian>(self.class_name_offset)?;
let combined = (self.largest_subkey_name_length as u32)
| ((self.virtualization_flags as u32) << 16)
| ((self.user_flags as u32) << 20)
| ((self.debug as u32) << 24);
writer.write_u32::<LittleEndian>(combined)?;
writer.write_u32::<LittleEndian>(self.largest_subkey_class_name_length)?;
writer.write_u32::<LittleEndian>(self.largest_value_name_length)?;
writer.write_u32::<LittleEndian>(self.largest_value_data_size)?;
writer.write_u32::<LittleEndian>(self.work_var)?;
writer.write_u16::<LittleEndian>(self.key_name_length)?;
writer.write_u16::<LittleEndian>(self.class_name_length)?;
writer.write_all(&self.key_name)?;
Ok(())
}
pub fn name(&self) -> String {
let key_flags = self.get_flags();
if key_flags.contains(KeyNodeFlags::KEY_COMP_NAME) {
decode_ascii_string(&self.key_name)
} else {
decode_utf16le_string(&self.key_name).unwrap_or_default()
}
}
pub fn set_name(&mut self, name: &str) {
let can_use_ascii = name.chars().all(|c| c as u32 <= 255);
if can_use_ascii {
self.key_name = encode_ascii_string(name);
self.flags |= KeyNodeFlags::KEY_COMP_NAME.bits();
} else {
self.key_name = encode_utf16le_string(name);
self.key_name.truncate(self.key_name.len() - 2); self.flags &= !KeyNodeFlags::KEY_COMP_NAME.bits();
}
self.key_name_length = self.key_name.len() as u16;
}
pub fn get_flags(&self) -> KeyNodeFlags {
KeyNodeFlags::from_bits_truncate(self.flags)
}
pub fn is_root(&self) -> bool {
self.get_flags().contains(KeyNodeFlags::KEY_HIVE_ENTRY)
}
pub fn is_symlink(&self) -> bool {
self.get_flags().contains(KeyNodeFlags::KEY_SYM_LINK)
}
pub fn has_subkeys(&self) -> bool {
self.num_subkeys > 0 && self.subkeys_list_offset != INVALID_OFFSET
}
pub fn has_values(&self) -> bool {
self.num_values > 0 && self.values_list_offset != INVALID_OFFSET
}
pub fn get_access_bits(&self) -> AccessBits {
AccessBits::from_bits_truncate(self.access_bits)
}
pub fn get_layered_key_flags(&self) -> LayeredKeyFlags {
LayeredKeyFlags::from_raw(self.layered_key_flags)
}
pub fn is_tombstone(&self) -> bool {
self.get_layered_key_flags().layer_semantics() == LayerSemantics::IsTombstone
}
pub fn get_debug_flags(&self) -> DebugFlags {
DebugFlags::from_bits_truncate(self.debug)
}
pub fn get_user_flags(&self) -> UserFlags {
UserFlags::from_bits_truncate(self.user_flags)
}
pub fn get_virtualization_flags(&self) -> VirtualizationFlags {
VirtualizationFlags::from_bits_truncate(self.virtualization_flags)
}
pub fn has_class_name(&self) -> bool {
self.class_name_offset != INVALID_OFFSET && self.class_name_length > 0
}
pub fn is_predef_handle(&self) -> bool {
self.get_flags().contains(KeyNodeFlags::KEY_PREDEF_HANDLE)
}
pub fn get_predef_handle(&self) -> Option<u32> {
if self.is_predef_handle() {
Some(self.num_values)
} else {
None
}
}
pub fn new(name: &str, parent_offset: u32, is_root: bool) -> Self {
let mut node = Self {
signature: *signatures::KEY_NODE,
flags: 0,
last_written: 0,
access_bits: 0,
layered_key_flags: 0,
access_spare: 0,
parent: parent_offset,
num_subkeys: 0,
num_volatile_subkeys: 0,
subkeys_list_offset: INVALID_OFFSET,
volatile_subkeys_list_offset: INVALID_OFFSET,
num_values: 0,
values_list_offset: INVALID_OFFSET,
security_offset: INVALID_OFFSET,
class_name_offset: INVALID_OFFSET,
largest_subkey_name_length: 0,
virtualization_flags: 0,
user_flags: 0,
debug: 0,
largest_subkey_class_name_length: 0,
largest_value_name_length: 0,
largest_value_data_size: 0,
work_var: 0,
key_name_length: 0,
class_name_length: 0,
key_name: Vec::new(),
};
node.set_name(name);
if is_root {
node.flags |= KeyNodeFlags::KEY_HIVE_ENTRY.bits();
}
node
}
pub fn total_size(&self) -> usize {
Self::FIXED_SIZE + self.key_name.len()
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buffer = Vec::new();
self.write(&mut buffer).unwrap();
buffer
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_node_creation() {
let node = KeyNode::new("TestKey", 0, false);
assert_eq!(node.name(), "TestKey");
assert!(!node.is_root());
}
#[test]
fn test_key_node_root() {
let node = KeyNode::new("CMI-CreateHive{...}", INVALID_OFFSET, true);
assert!(node.is_root());
}
#[test]
fn test_key_node_roundtrip() {
let node = KeyNode::new("TestKey", 100, false);
let bytes = node.to_bytes();
let parsed = KeyNode::parse(&bytes).unwrap();
assert_eq!(parsed.name(), node.name());
assert_eq!(parsed.parent, node.parent);
}
}