use std::iter::FusedIterator;
use vmi_core::{Va, VmiError, VmiState, driver::VmiRead};
use crate::{
ArchAdapter, WindowsError, WindowsHive, WindowsHiveCellIndex, WindowsKeyIndex, WindowsKeyNode,
WindowsOs,
};
pub struct KeyNodeIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
hive_va: Va,
remaining: u32,
root: WindowsHiveCellIndex,
outer: Option<Frame>,
inner: Option<Frame>,
initialized: bool,
}
#[derive(Debug, Clone, Copy)]
struct Frame {
signature: u16,
entries_va: Va,
entry_size: u64,
count: u16,
position: u16,
}
impl<'a, Driver> KeyNodeIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
pub fn new(
vmi: VmiState<'a, WindowsOs<Driver>>,
hive_va: Va,
root: WindowsHiveCellIndex,
count: u32,
) -> Self {
Self {
vmi,
hive_va,
remaining: count,
root,
outer: None,
inner: None,
initialized: false,
}
}
fn resolve(&self, index: WindowsHiveCellIndex) -> Result<Va, VmiError> {
let hive = WindowsHive::new(self.vmi, self.hive_va);
match hive.cell(index)? {
Some(va) => Ok(va),
None => Err(WindowsError::CorruptedStruct("CM_KEY_INDEX.List[]").into()),
}
}
fn load_frame(&self, cell_va: Va) -> Result<Frame, VmiError> {
let signature = self.vmi.read_u16(cell_va)?;
if matches!(
signature,
WindowsKeyNode::<Driver>::KEY_NODE_SIGNATURE
| WindowsKeyNode::<Driver>::LINK_NODE_SIGNATURE
) {
return Ok(Frame {
signature,
entries_va: cell_va,
entry_size: 0,
count: 1,
position: 0,
});
}
let index = WindowsKeyIndex::new(self.vmi, cell_va);
let entry_size = WindowsKeyIndex::<Driver>::entry_size_for(signature)?;
let count = index.count()?;
let entries_va = index.list()?;
Ok(Frame {
signature,
entries_va,
entry_size,
count,
position: 0,
})
}
fn yield_from(&self, frame: &Frame) -> Result<Va, VmiError> {
if matches!(
frame.signature,
WindowsKeyNode::<Driver>::KEY_NODE_SIGNATURE
| WindowsKeyNode::<Driver>::LINK_NODE_SIGNATURE
) {
return Ok(frame.entries_va);
}
let entry_va = frame.entries_va + frame.position as u64 * frame.entry_size;
let hcell = self.vmi.read_u32(entry_va)?;
self.resolve(WindowsHiveCellIndex::new(hcell))
}
fn walk_next(&mut self) -> Result<Option<WindowsKeyNode<'a, Driver>>, VmiError> {
if !self.initialized {
self.initialized = true;
if !self.root.is_nil() {
let root_va = self.resolve(self.root)?;
self.outer = Some(self.load_frame(root_va)?);
}
}
loop {
if let Some(mut frame) = self.inner {
if frame.position < frame.count {
let snapshot = frame;
frame.position += 1;
self.inner = Some(frame);
self.remaining = self.remaining.saturating_sub(1);
let va = self.yield_from(&snapshot)?;
return Ok(Some(WindowsKeyNode::new(self.vmi, self.hive_va, va)));
}
self.inner = None;
}
if let Some(mut frame) = self.outer {
if frame.position < frame.count {
if frame.signature == WindowsKeyIndex::<Driver>::INDEX_ROOT_SIGNATURE {
let entry_va = frame.entries_va + frame.position as u64 * frame.entry_size;
frame.position += 1;
self.outer = Some(frame);
let raw = self.vmi.read_u32(entry_va)?;
let sub_va = self.resolve(WindowsHiveCellIndex::new(raw))?;
self.inner = Some(self.load_frame(sub_va)?);
continue;
}
let snapshot = frame;
frame.position += 1;
self.outer = Some(frame);
self.remaining = self.remaining.saturating_sub(1);
let va = self.yield_from(&snapshot)?;
return Ok(Some(WindowsKeyNode::new(self.vmi, self.hive_va, va)));
}
self.outer = None;
}
return Ok(None);
}
}
}
impl<'a, Driver> Iterator for KeyNodeIterator<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
type Item = Result<WindowsKeyNode<'a, Driver>, VmiError>;
fn next(&mut self) -> Option<Self::Item> {
self.walk_next().transpose()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.remaining as usize;
(n, Some(n))
}
}
impl<Driver> FusedIterator for KeyNodeIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
}
impl<Driver> ExactSizeIterator for KeyNodeIterator<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
}