#![doc(html_logo_url = "https://colinfinck.de/img/software/nt-load-order.svg")]
mod registry;
mod steps;
use anyhow::{Context, Result};
use dlv_list::VecList;
use crate::registry::RegistryWorker;
use crate::steps::{
add_basic_kernel_binaries, add_imports, add_kernel_binary, load_from_registry,
sort_by_hardcoded_groups, sort_by_hardcoded_service_lists, sort_by_tag_and_group,
};
#[derive(Clone)]
pub struct NtLoadOrder {
system_root: Option<String>,
kd_driver: Option<String>,
cpu_vendor: Option<String>,
sort_by_tag_and_group: bool,
sort_by_hardcoded_groups: bool,
sort_by_hardcoded_service_lists: bool,
add_kernel_binaries: bool,
add_imports: bool,
}
#[derive(Clone)]
pub struct NtLoadOrderEntry {
pub name: String,
pub image_path: String,
pub group: Option<NtLoadOrderEntryGroup>,
pub tag: Option<u32>,
pub reason: String,
pub is_kernel_binary: bool,
}
#[derive(Clone)]
pub struct NtLoadOrderEntryGroup {
pub display_name: String,
pub search_key: String,
}
impl NtLoadOrder {
pub fn new() -> Self {
Self {
system_root: None,
kd_driver: None,
cpu_vendor: None,
sort_by_tag_and_group: true,
sort_by_hardcoded_groups: true,
sort_by_hardcoded_service_lists: true,
add_kernel_binaries: true,
add_imports: true,
}
}
pub fn add_imports(mut self, value: bool) -> Self {
self.add_imports = value;
self
}
pub fn add_kernel_binaries(mut self, value: bool) -> Self {
self.add_kernel_binaries = value;
self
}
pub fn cpu_vendor(mut self, cpu_vendor: Option<String>) -> Self {
self.cpu_vendor = cpu_vendor;
self
}
pub fn kd_driver(mut self, kd_driver: Option<String>) -> Self {
self.kd_driver = kd_driver;
self
}
pub fn sort_by_hardcoded_groups(mut self, value: bool) -> Self {
self.sort_by_hardcoded_groups = value;
self
}
pub fn sort_by_hardcoded_service_lists(mut self, value: bool) -> Self {
self.sort_by_hardcoded_service_lists = value;
self
}
pub fn sort_by_tag_and_group(mut self, value: bool) -> Self {
self.sort_by_tag_and_group = value;
self
}
pub fn system_root(mut self, system_root: Option<String>) -> Self {
self.system_root = system_root;
self
}
pub fn get(self) -> Result<Vec<NtLoadOrderEntry>> {
const BOOT_FILE_SYSTEM: &str = "ntfs";
const CONTROL_SET: u8 = 1;
let registry_worker = if let Some(system_root) = &self.system_root {
RegistryWorker::new_target(system_root)?
} else {
RegistryWorker::new_local()
};
let registry_info = load_from_registry(®istry_worker, BOOT_FILE_SYSTEM, CONTROL_SET)?;
let mut entries = if self.sort_by_tag_and_group {
sort_by_tag_and_group(registry_info)
} else {
registry_info.entries.into_iter().collect::<VecList<_>>()
};
if self.sort_by_hardcoded_groups {
sort_by_hardcoded_groups(&mut entries);
}
if self.sort_by_hardcoded_service_lists {
sort_by_hardcoded_service_lists(&mut entries);
}
if self.add_kernel_binaries {
let mut last = add_basic_kernel_binaries(&mut entries);
if let Some(kd_driver) = &self.kd_driver {
last = add_kernel_binary(
&mut entries,
last,
kd_driver.clone(),
format!("System32\\{kd_driver}.dll"),
);
}
if let Some(cpu_vendor) = &self.cpu_vendor {
add_kernel_binary(
&mut entries,
last,
"mcupdate".to_string(),
format!("System32\\mcupdate_{cpu_vendor}.dll"),
);
}
}
if self.add_imports {
let system_root = if let Some(system_root) = &self.system_root {
system_root.clone()
} else {
std::env::var("SystemRoot")
.context("Could not read SystemRoot environment variable")?
};
entries = add_imports(entries, system_root)?;
}
Ok(entries.into_iter().collect())
}
}
impl Default for NtLoadOrder {
fn default() -> Self {
Self::new()
}
}