Run rustfmt

This commit is contained in:
nganhkhoa 2020-07-02 02:47:15 +07:00
parent b1c3107c74
commit a154c71f9b
15 changed files with 2294 additions and 1979 deletions

View File

@ -1,7 +1,7 @@
use std::rc::Rc;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::rc::Rc;
// pub struct Object { // pub struct Object {
// name: String, // name: String,
@ -43,41 +43,40 @@ impl Address {
} }
} }
fn deref<F>(&self, resolver: &F) -> Address fn deref<F>(&self, resolver: &F) -> Address
where F: Fn(u64) -> u64 { where
F: Fn(u64) -> u64,
{
match &self.pointer { match &self.pointer {
Some(p) => { Some(p) => {
let addr = p.deref(resolver); let addr = p.deref(resolver);
// println!("deref: {} -> {}; resolve: 0x{:x}", self, addr, addr.base + addr.offset); // println!("deref: {} -> {}; resolve: 0x{:x}", self, addr, addr.base + addr.offset);
let base = let base = if addr.base != 0 {
if addr.base != 0 { resolver(addr.base + addr.offset)
resolver(addr.base + addr.offset) } else {
} else { 0
0 };
};
Address { Address {
base: base, base: base,
pointer: None, pointer: None,
offset: self.offset, offset: self.offset,
} }
},
None => {
Address {
base: self.base,
pointer: None,
offset: self.offset,
}
} }
None => Address {
base: self.base,
pointer: None,
offset: self.offset,
},
} }
} }
pub fn get<F>(&self, resolver: &F) -> u64 pub fn get<F>(&self, resolver: &F) -> u64
where F: Fn(u64) -> u64 { where
F: Fn(u64) -> u64,
{
if self.pointer.is_some() { if self.pointer.is_some() {
self.deref(resolver).get(resolver) self.deref(resolver).get(resolver)
} } else if self.base == 0 {
else if self.base == 0 {
0 0
} } else {
else {
self.base + self.offset self.base + self.offset
} }
} }
@ -136,9 +135,10 @@ impl SubAssign<u64> for Address {
impl PartialEq for Address { impl PartialEq for Address {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.pointer.is_none() && other.pointer.is_none() self.pointer.is_none()
&& self.base == other.base && other.pointer.is_none()
&& self.offset == other.offset && self.base == other.base
&& self.offset == other.offset
} }
} }
@ -146,8 +146,7 @@ impl PartialOrd for Address {
fn partial_cmp(&self, other: &Address) -> Option<Ordering> { fn partial_cmp(&self, other: &Address) -> Option<Ordering> {
if self.pointer.is_some() || other.pointer.is_some() { if self.pointer.is_some() || other.pointer.is_some() {
None None
} } else {
else {
let this = self.base + self.offset; let this = self.base + self.offset;
let that = other.base + other.offset; let that = other.base + other.offset;
Some(this.cmp(&that)) Some(this.cmp(&that))
@ -159,11 +158,9 @@ impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(p) = &self.pointer { if let Some(p) = &self.pointer {
write!(f, "*({}) + 0x{:x}", *p, self.offset) write!(f, "*({}) + 0x{:x}", *p, self.offset)
} } else if self.offset != 0 {
else if self.offset != 0 {
write!(f, "0x{:x} + 0x{:x}", self.base, self.offset) write!(f, "0x{:x} + 0x{:x}", self.base, self.offset)
} } else {
else {
write!(f, "0x{:x}", self.base) write!(f, "0x{:x}", self.base)
} }
} }
@ -174,7 +171,7 @@ impl Clone for Address {
Address { Address {
base: self.base, base: self.base,
pointer: self.pointer.clone(), pointer: self.pointer.clone(),
offset: self.offset offset: self.offset,
} }
} }
} }

View File

@ -1,14 +1,15 @@
use std::error::Error; use std::error::Error;
use lpus::{ use lpus::{driver_state::DriverState, scan_driver};
driver_state::{DriverState},
scan_driver
};
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
if !driver.is_supported() { if !driver.is_supported() {
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); return Err(format!(
"Windows version {:?} is not supported",
driver.windows_ffi.short_version
)
.into());
} }
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); println!("NtLoadDriver() -> 0x{:x}", driver.startup());
@ -21,4 +22,3 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(()) Ok(())
} }

View File

@ -1,24 +1,30 @@
use std::error::Error; use std::error::Error;
use lpus::{ use lpus::{
driver_state::{DriverState}, driver_state::DriverState, scan_eprocess, traverse_activehead, traverse_handletable,
scan_eprocess traverse_kiprocesslist,
}; };
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
if !driver.is_supported() { if !driver.is_supported() {
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); return Err(format!(
} "Windows version {:?} is not supported",
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); driver.windows_ffi.short_version
)
let result = scan_eprocess(&driver).unwrap_or(Vec::new()); .into());
}
for r in result.iter() { println!("NtLoadDriver() -> 0x{:x}", driver.startup());
println!("{:#}", r.to_string());
} let scan = scan_eprocess(&driver).unwrap_or(Vec::new());
let activehead = traverse_activehead(&driver).unwrap_or(Vec::new());
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new());
Ok(()) let handletable = traverse_handletable(&driver).unwrap_or(Vec::new());
}
for r in scan.iter() {
println!("{:#}", r.to_string());
}
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())
}

View File

@ -1,16 +1,17 @@
use std::error::Error; use std::error::Error;
use lpus::{ use lpus::{
driver_state::{DriverState}, driver_state::DriverState, traverse_activehead, traverse_handletable, traverse_kiprocesslist,
traverse_activehead,
traverse_kiprocesslist,
traverse_handletable
}; };
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
if !driver.is_supported() { if !driver.is_supported() {
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); return Err(format!(
"Windows version {:?} is not supported",
driver.windows_ffi.short_version
)
.into());
} }
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); println!("NtLoadDriver() -> 0x{:x}", driver.startup());
@ -33,4 +34,3 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(()) Ok(())
} }

View File

@ -1,25 +1,24 @@
use std::error::Error; use std::error::Error;
use lpus::{ use lpus::{driver_state::DriverState, scan_file};
driver_state::{DriverState},
scan_file fn main() -> Result<(), Box<dyn Error>> {
}; let mut driver = DriverState::new();
if !driver.is_supported() {
fn main() -> Result<(), Box<dyn Error>> { return Err(format!(
let mut driver = DriverState::new(); "Windows version {:?} is not supported",
if !driver.is_supported() { driver.windows_ffi.short_version
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); )
} .into());
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); }
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
let result = scan_file(&driver).unwrap_or(Vec::new());
let result = scan_file(&driver).unwrap_or(Vec::new());
for r in result.iter() {
println!("{:#}", r.to_string()); for r in result.iter() {
} println!("{:#}", r.to_string());
}
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(()) println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
} Ok(())
}

View File

@ -1,14 +1,15 @@
use std::error::Error; use std::error::Error;
use lpus::{ use lpus::{driver_state::DriverState, scan_kernel_module};
driver_state::{DriverState},
scan_kernel_module
};
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
if !driver.is_supported() { if !driver.is_supported() {
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); return Err(format!(
"Windows version {:?} is not supported",
driver.windows_ffi.short_version
)
.into());
} }
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); println!("NtLoadDriver() -> 0x{:x}", driver.startup());
@ -21,5 +22,3 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(()) Ok(())
} }

View File

@ -2,16 +2,16 @@ use std::error::Error;
use parse_int::parse; use parse_int::parse;
use lpus::{ use lpus::{driver_state::DriverState, traverse_loadedmodulelist, traverse_unloadeddrivers};
driver_state::{DriverState},
traverse_loadedmodulelist,
traverse_unloadeddrivers
};
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
if !driver.is_supported() { if !driver.is_supported() {
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); return Err(format!(
"Windows version {:?} is not supported",
driver.windows_ffi.short_version
)
.into());
} }
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); println!("NtLoadDriver() -> 0x{:x}", driver.startup());
@ -26,10 +26,11 @@ fn main() -> Result<(), Box<dyn Error>> {
let servicelimit_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceLimit")?; let servicelimit_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceLimit")?;
let servicelimit = driver.deref_addr_new::<u32>(servicelimit_ptr.address()) as u64; let servicelimit = driver.deref_addr_new::<u32>(servicelimit_ptr.address()) as u64;
let ssdt: Vec<u64> = driver.deref_array::<u32>(&servicetable, servicelimit) let ssdt: Vec<u64> = driver
.iter().map(|entry| { .deref_array::<u32>(&servicetable, servicelimit)
servicetable.address() + ((entry >> 4) as u64) .iter()
}).collect(); .map(|entry| servicetable.address() + ((entry >> 4) as u64))
.collect();
for r in loaded.iter() { for r in loaded.iter() {
println!("{:#}", r.to_string()); println!("{:#}", r.to_string());
@ -41,8 +42,14 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("============================================="); println!("=============================================");
for func in ssdt { for func in ssdt {
for r in loaded.iter() { for r in loaded.iter() {
let base = r["dllbase"].as_str().and_then(|b| parse::<u64>(b).ok()).unwrap_or(0); let base = r["dllbase"]
let size = r["size"].as_str().and_then(|s| parse::<u64>(s).ok()).unwrap_or(0); .as_str()
.and_then(|b| parse::<u64>(b).ok())
.unwrap_or(0);
let size = r["size"]
.as_str()
.and_then(|s| parse::<u64>(s).ok())
.unwrap_or(0);
if func > base && func < base + size { if func > base && func < base + size {
let offset = func - ntosbase.address(); let offset = func - ntosbase.address();
@ -55,8 +62,7 @@ fn main() -> Result<(), Box<dyn Error>> {
} }
if n == "" { if n == "" {
"(??)".to_string() "(??)".to_string()
} } else {
else {
n n
} }
}; };

View File

@ -1,63 +1,61 @@
use std::error::Error; use std::error::Error;
// use std::time::{SystemTime, UNIX_EPOCH}; // use std::time::{SystemTime, UNIX_EPOCH};
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::Editor; use rustyline::Editor;
use lpus::{ use lpus::driver_state::DriverState;
driver_state::{DriverState},
}; pub fn to_epoch(filetime: u64) -> u64 {
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
pub fn to_epoch(filetime: u64) -> u64 { let windows_epoch_diff = 11644473600000 * 10000;
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ if filetime < windows_epoch_diff {
let windows_epoch_diff = 11644473600000 * 10000; return 0;
if filetime < windows_epoch_diff { }
return 0; let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
} // let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
// let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64; process_time_epoch
}
process_time_epoch
} fn main() -> Result<(), Box<dyn Error>> {
let driver = DriverState::new();
fn main() -> Result<(), Box<dyn Error>> { driver.windows_ffi.print_version();
let driver = DriverState::new(); driver.pdb_store.print_default_information();
driver.windows_ffi.print_version();
driver.pdb_store.print_default_information(); println!("{}", to_epoch(0xfffffa80018cb688));
println!("{}", to_epoch(0x01d64ecd8b295318));
println!("{}", to_epoch(0xfffffa80018cb688));
println!("{}", to_epoch(0x01d64ecd8b295318)); let mut rl = Editor::<()>::new();
if rl.load_history("history.lpus").is_err() {
let mut rl = Editor::<()>::new(); println!("No previous history.");
if rl.load_history("history.lpus").is_err() { }
println!("No previous history."); loop {
} let readline = rl.readline(">> ");
loop { match readline {
let readline = rl.readline(">> "); Ok(line) => {
match readline { rl.add_history_entry(line.as_str());
Ok(line) => { println!("Line: {}", line);
rl.add_history_entry(line.as_str()); // TODO: add parser here
println!("Line: {}", line); if let Err(e) = driver.pdb_store.dt(&line) {
// TODO: add parser here println!("{}", e);
if let Err(e) = driver.pdb_store.dt(&line) { }
println!("{}", e); }
} Err(ReadlineError::Interrupted) => {
}, println!("CTRL-C");
Err(ReadlineError::Interrupted) => { break;
println!("CTRL-C"); }
break Err(ReadlineError::Eof) => {
}, println!("CTRL-D");
Err(ReadlineError::Eof) => { break;
println!("CTRL-D"); }
break Err(err) => {
}, println!("Error: {:?}", err);
Err(err) => { break;
println!("Error: {:?}", err); }
break }
} }
} rl.save_history("history.lpus").unwrap();
}
rl.save_history("history.lpus").unwrap(); Ok(())
}
Ok(())
}

View File

@ -1,14 +1,15 @@
use std::error::Error; use std::error::Error;
use lpus::{ use lpus::{driver_state::DriverState, scan_ethread /* scan_mutant */};
driver_state::{DriverState},
scan_ethread, /* scan_mutant */
};
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
if !driver.is_supported() { if !driver.is_supported() {
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); return Err(format!(
"Windows version {:?} is not supported",
driver.windows_ffi.short_version
)
.into());
} }
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); println!("NtLoadDriver() -> 0x{:x}", driver.startup());
@ -25,5 +26,3 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(()) Ok(())
} }

View File

@ -1,331 +1,374 @@
use std::default::Default; use std::clone::Clone;
use std::clone::Clone; use std::default::Default;
use std::error::Error; use std::error::Error;
// use std::io::{Error, ErrorKind}; // use std::io::{Error, ErrorKind};
use std::ffi::c_void; use std::ffi::c_void;
use std::mem::{size_of_val, size_of}; use std::mem::{size_of, size_of_val};
use winapi::shared::ntdef::{NTSTATUS}; use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::{DWORD}; use winapi::shared::ntdef::NTSTATUS;
use winapi::um::winioctl::{ use winapi::um::winioctl::{
CTL_CODE, FILE_ANY_ACCESS, CTL_CODE, FILE_ANY_ACCESS, METHOD_IN_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER,
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER METHOD_OUT_DIRECT,
}; };
use crate::address::Address; use crate::address::Address;
use crate::pdb_store::{PdbStore, parse_pdb}; use crate::ioctl_protocol::{
use crate::windows::{WindowsFFI, WindowsVersion}; DerefAddr, InputData, /* OutputData, */ Nothing, OffsetData,
use crate::ioctl_protocol::{ ScanPoolData, /* HideProcess, */
InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */ };
/* OutputData, */ Nothing use crate::pdb_store::{parse_pdb, PdbStore};
}; use crate::windows::{WindowsFFI, WindowsVersion};
type BoxResult<T> = Result<T, Box<dyn Error>>; type BoxResult<T> = Result<T, Box<dyn Error>>;
const SIOCTL_TYPE: DWORD = 40000; const SIOCTL_TYPE: DWORD = 40000;
pub fn to_epoch(filetime: u64) -> u64 { pub fn to_epoch(filetime: u64) -> u64 {
let windows_epoch_diff: u64 = 11644473600000 * 10000; let windows_epoch_diff: u64 = 11644473600000 * 10000;
if filetime < windows_epoch_diff { if filetime < windows_epoch_diff {
return 0; return 0;
} }
let process_time_epoch: u64 = (filetime - windows_epoch_diff) / 10000; let process_time_epoch: u64 = (filetime - windows_epoch_diff) / 10000;
process_time_epoch process_time_epoch
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum DriverAction { pub enum DriverAction {
SetupOffset, SetupOffset,
GetKernelBase, GetKernelBase,
ScanPsActiveHead, ScanPsActiveHead,
ScanPool, ScanPool,
ScanPoolRemote, ScanPoolRemote,
DereferenceAddress, DereferenceAddress,
HideProcess HideProcess,
} }
impl DriverAction { impl DriverAction {
pub fn get_code(&self) -> DWORD { pub fn get_code(&self) -> DWORD {
match self { match self {
DriverAction::SetupOffset => CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS), DriverAction::SetupOffset => {
DriverAction::GetKernelBase => CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS), CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
DriverAction::ScanPsActiveHead => CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS), }
DriverAction::ScanPool => CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS), DriverAction::GetKernelBase => {
DriverAction::ScanPoolRemote => CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS), CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS), }
DriverAction::HideProcess => CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS) DriverAction::ScanPsActiveHead => {
} CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS)
} }
} DriverAction::ScanPool => {
CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#[derive(Debug)] }
pub struct EprocessPoolChunk { DriverAction::ScanPoolRemote => {
pub pool_addr: u64, CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
pub eprocess_addr: u64, }
pub eprocess_name: String, DriverAction::DereferenceAddress => {
pub create_time: u64, CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
pub exit_time: u64 }
} DriverAction::HideProcess => {
CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
impl PartialEq for EprocessPoolChunk { }
fn eq(&self, other: &Self) -> bool { }
self.eprocess_addr == other.eprocess_addr }
} }
}
#[derive(Debug)]
#[allow(dead_code)] pub struct EprocessPoolChunk {
pub struct DriverState { pub pool_addr: u64,
// TODO: Make private, only call methods of DriverState pub eprocess_addr: u64,
pub pdb_store: PdbStore, pub eprocess_name: String,
pub windows_ffi: WindowsFFI, pub create_time: u64,
} pub exit_time: u64,
}
impl DriverState {
pub fn new() -> Self { impl PartialEq for EprocessPoolChunk {
Self { fn eq(&self, other: &Self) -> bool {
pdb_store: parse_pdb().expect("Cannot get PDB file"), self.eprocess_addr == other.eprocess_addr
windows_ffi: WindowsFFI::new() }
} }
}
#[allow(dead_code)]
pub fn startup(&mut self) -> NTSTATUS { pub struct DriverState {
let s = self.windows_ffi.load_driver(); // TODO: Make private, only call methods of DriverState
let mut input = InputData { pub pdb_store: PdbStore,
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version) pub windows_ffi: WindowsFFI,
}; }
self.windows_ffi.device_io(DriverAction::SetupOffset.get_code(),
&mut input, &mut Nothing); impl DriverState {
s pub fn new() -> Self {
} Self {
pdb_store: parse_pdb().expect("Cannot get PDB file"),
pub fn shutdown(&self) -> NTSTATUS { windows_ffi: WindowsFFI::new(),
self.windows_ffi.unload_driver() }
} }
pub fn is_supported(&self) -> bool { pub fn startup(&mut self) -> NTSTATUS {
self.windows_ffi.short_version.is_supported() let s = self.windows_ffi.load_driver();
} let mut input = InputData {
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version),
pub fn use_old_tag(&self) -> bool { };
// use old tag to scan, for Window < 8 self.windows_ffi.device_io(
if self.windows_ffi.short_version < WindowsVersion::Windows8 { DriverAction::SetupOffset.get_code(),
true &mut input,
} &mut Nothing,
else { );
false s
} }
}
pub fn shutdown(&self) -> NTSTATUS {
pub fn get_kernel_base(&self) -> Address { self.windows_ffi.unload_driver()
let mut ntosbase = 0u64; }
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(),
&mut Nothing, &mut ntosbase); pub fn is_supported(&self) -> bool {
Address::from_base(ntosbase) self.windows_ffi.short_version.is_supported()
} }
pub fn scan_pool<F>(&self, tag: &[u8; 4], expected_struct: &str, mut handler: F) -> BoxResult<bool> pub fn use_old_tag(&self) -> bool {
where F: FnMut(Address, &[u8], Address) -> BoxResult<bool> // use old tag to scan, for Window < 8
// F(Pool Address, Pool Header Data, Pool Data Address) if self.windows_ffi.short_version < WindowsVersion::Windows8 {
// TODO: Pool Header as a real struct true
{ } else {
// TODO: scan large pool false
// TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122 }
// Making this function a generator will turn the call to a for loop }
// https://docs.rs/gen-iter/0.2.0/gen_iter/
// >> More flexibility in code pub fn get_kernel_base(&self) -> Address {
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?; let mut ntosbase = 0u64;
let minimum_block_size = self.pdb_store.get_offset_r(&format!("{}.struct_size", expected_struct))? self.windows_ffi.device_io(
+ pool_header_size; DriverAction::GetKernelBase.get_code(),
let code = DriverAction::ScanPoolRemote.get_code(); &mut Nothing,
let ntosbase = self.get_kernel_base(); &mut ntosbase,
let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?; );
Address::from_base(ntosbase)
println!("kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}", }
ntosbase, start_address, end_address, tag, expected_struct);
pub fn scan_pool<F>(
let mut ptr = start_address; &self,
while ptr < end_address { tag: &[u8; 4],
let mut next_found = 0u64; expected_struct: &str,
let mut input = InputData { mut handler: F,
scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag) ) -> BoxResult<bool>
}; where
self.windows_ffi.device_io(code, &mut input, &mut next_found); F: FnMut(Address, &[u8], Address) -> BoxResult<bool>, // F(Pool Address, Pool Header Data, Pool Data Address)
ptr = Address::from_base(next_found); // TODO: Pool Header as a real struct
if ptr >= end_address { {
break; // TODO: scan large pool
} // TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122
// Making this function a generator will turn the call to a for loop
let pool_addr = Address::from_base(ptr.address()); // https://docs.rs/gen-iter/0.2.0/gen_iter/
let header: Vec<u8> = self.deref_array(&pool_addr, pool_header_size); // >> More flexibility in code
let chunk_size = (header[2] as u64) * 16u64; let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
let minimum_block_size = self
if pool_addr.address() + chunk_size > end_address.address() { .pdb_store
// the chunk surpasses the non page pool range .get_offset_r(&format!("{}.struct_size", expected_struct))?
break; + pool_header_size;
} let code = DriverAction::ScanPoolRemote.get_code();
let ntosbase = self.get_kernel_base();
// automatically reject bad chunk let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?;
if chunk_size < minimum_block_size {
ptr += 0x4; println!(
continue; "kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}",
} ntosbase, start_address, end_address, tag, expected_struct
);
let data_addr = Address::from_base(pool_addr.address() + pool_header_size);
let success = handler(pool_addr, &header, data_addr).unwrap_or(false); let mut ptr = start_address;
if success { while ptr < end_address {
ptr += chunk_size; // skip this chunk let mut next_found = 0u64;
} let mut input = InputData {
else { scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag),
ptr += 0x4; // search next };
} self.windows_ffi
} .device_io(code, &mut input, &mut next_found);
Ok(true) ptr = Address::from_base(next_found);
} if ptr >= end_address {
break;
pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> { }
let resolver = |p| { self.deref_addr_new(p) };
let r = self.pdb_store.decompose(&addr, &name)?; let pool_addr = Address::from_base(ptr.address());
Ok(r.get(&resolver)) let header: Vec<u8> = self.deref_array(&pool_addr, pool_header_size);
} let chunk_size = (header[2] as u64) * 16u64;
pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> { if pool_addr.address() + chunk_size > end_address.address() {
// interface to pdb_store.decompose // the chunk surpasses the non page pool range
let resolver = |p| { self.deref_addr_new(p) }; break;
let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver)); }
Ok(r)
} // automatically reject bad chunk
if chunk_size < minimum_block_size {
pub fn decompose_array<T: Default + Clone>(&self, addr: &Address, name: &str, len: u64) -> BoxResult<Vec<T>> { ptr += 0x4;
// interface to pdb_store.decompose for array continue;
let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len); }
Ok(r)
} let data_addr = Address::from_base(pool_addr.address() + pool_header_size);
let success = handler(pool_addr, &header, data_addr).unwrap_or(false);
pub fn deref_addr_new<T: Default>(&self, addr: u64) -> T { if success {
let mut r: T = Default::default(); ptr += chunk_size; // skip this chunk
if addr != 0 { } else {
self.deref_addr(addr, &mut r); ptr += 0x4; // search next
} }
r }
} Ok(true)
}
pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> {
let resolver = |p| { self.deref_addr_new(p) }; pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> {
let mut r: Vec<T> = vec![Default::default(); len as usize]; let resolver = |p| self.deref_addr_new(p);
let size_in_byte = (len as usize) * size_of::<T>(); let r = self.pdb_store.decompose(&addr, &name)?;
self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64); Ok(r.get(&resolver))
r }
}
pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> {
// #[deprecated(note="use deref_addr_new<T>")] // interface to pdb_store.decompose
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) { let resolver = |p| self.deref_addr_new(p);
let code = DriverAction::DereferenceAddress.get_code(); let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver));
let size: usize = size_of_val(outbuf); Ok(r)
let mut input = InputData { }
deref_addr: DerefAddr {
addr, pub fn decompose_array<T: Default + Clone>(
size: size as u64 &self,
} addr: &Address,
}; name: &str,
self.windows_ffi.device_io(code, &mut input, outbuf); len: u64,
} ) -> BoxResult<Vec<T>> {
// interface to pdb_store.decompose for array
// #[deprecated(note="use deref_array<T>")] let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len);
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len_as_byte: u64) { Ok(r)
let code = DriverAction::DereferenceAddress.get_code(); }
let mut input = InputData {
deref_addr: DerefAddr { pub fn deref_addr_new<T: Default>(&self, addr: u64) -> T {
addr, let mut r: T = Default::default();
size: output_len_as_byte if addr != 0 {
} self.deref_addr(addr, &mut r);
}; }
self.windows_ffi.device_io_raw(code, r
&mut input as *mut _ as *mut c_void, size_of_val(&input) as DWORD, }
outptr as *mut c_void, output_len_as_byte as DWORD);
} pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> {
let resolver = |p| self.deref_addr_new(p);
pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> { let mut r: Vec<T> = vec![Default::default(); len as usize];
if unicode_str_addr == 0 { let size_in_byte = (len as usize) * size_of::<T>();
return Err("Not a valid address".into()); self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64);
} r
}
let mut strlen = 0u16;
let mut capacity = 0u16; // #[deprecated(note="use deref_addr_new<T>")]
let mut bufaddr = 0u64; pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?; let code = DriverAction::DereferenceAddress.get_code();
let capacity_addr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.MaximumLength")?; let size: usize = size_of_val(outbuf);
let mut input = InputData {
self.deref_addr(unicode_str_addr, &mut strlen); deref_addr: DerefAddr {
self.deref_addr(capacity_addr, &mut capacity); addr,
self.deref_addr(buffer_ptr, &mut bufaddr); size: size as u64,
},
if bufaddr == 0 || strlen > capacity || strlen == 0 || strlen % 2 != 0 { };
return Err("Unicode string is empty".into()); self.windows_ffi.device_io(code, &mut input, outbuf);
} }
let mut buf = vec![0u16; (strlen / 2) as usize]; // #[deprecated(note="use deref_array<T>")]
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64); pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len_as_byte: u64) {
// TODO: BUG with deref_array, len is wrong, let code = DriverAction::DereferenceAddress.get_code();
// >> the size of vector is strlen / 2 let mut input = InputData {
// >> the size to dereference is strlen deref_addr: DerefAddr {
// XXX: use Vec<u8> and turn to Vec<u16> addr,
// let buf: Vec<u16> = self.deref_array(&Address::from_base(bufaddr), (strlen / 2) as u64); size: output_len_as_byte,
},
Ok(String::from_utf16(&buf)?) };
} self.windows_ffi.device_io_raw(
code,
pub fn get_nonpaged_range(&self, ntosbase: &Address) -> BoxResult<[Address; 2]> { &mut input as *mut _ as *mut c_void,
// TODO: Add support for other Windows version here size_of_val(&input) as DWORD,
match self.windows_ffi.short_version { outptr as *mut c_void,
WindowsVersion::WindowsFastRing => { output_len_as_byte as DWORD,
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?; );
let path_first_va: String = vec![ }
"_MI_SYSTEM_INFORMATION",
"Hardware", pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
"SystemNodeNonPagedPool", if unicode_str_addr == 0 {
"NonPagedPoolFirstVa" return Err("Not a valid address".into());
].join("."); }
let path_last_va: String = vec![
"_MI_SYSTEM_INFORMATION", let mut strlen = 0u16;
"Hardware", let mut capacity = 0u16;
"SystemNodeNonPagedPool", let mut bufaddr = 0u64;
"NonPagedPoolLastVa" let buffer_ptr =
].join("."); unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?); let capacity_addr = unicode_str_addr
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?); + self
Ok([first_va, last_va]) .pdb_store
}, .get_offset_r("_UNICODE_STRING.MaximumLength")?;
WindowsVersion::Windows10_2019 |
WindowsVersion::Windows10_2018 => { self.deref_addr(unicode_str_addr, &mut strlen);
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?; self.deref_addr(capacity_addr, &mut capacity);
let path_first_va: String = vec![ self.deref_addr(buffer_ptr, &mut bufaddr);
"_MI_SYSTEM_INFORMATION",
"Hardware", if bufaddr == 0 || strlen > capacity || strlen == 0 || strlen % 2 != 0 {
"SystemNodeInformation", return Err("Unicode string is empty".into());
"NonPagedPoolFirstVa" }
].join(".");
let path_last_va: String = vec![ let mut buf = vec![0u16; (strlen / 2) as usize];
"_MI_SYSTEM_INFORMATION", self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
"Hardware", // TODO: BUG with deref_array, len is wrong,
"SystemNodeInformation", // >> the size of vector is strlen / 2
"NonPagedPoolLastVa" // >> the size to dereference is strlen
].join("."); // XXX: use Vec<u8> and turn to Vec<u16>
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?); // let buf: Vec<u16> = self.deref_array(&Address::from_base(bufaddr), (strlen / 2) as u64);
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
Ok([first_va, last_va]) Ok(String::from_utf16(&buf)?)
}, }
WindowsVersion::Windows7 => {
let path_first_va = ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?; pub fn get_nonpaged_range(&self, ntosbase: &Address) -> BoxResult<[Address; 2]> {
let path_last_va = ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?; // TODO: Add support for other Windows version here
let first_va = Address::from_base(self.deref_addr_new(path_first_va.address())); match self.windows_ffi.short_version {
let last_va = Address::from_base(self.deref_addr_new(path_last_va.address())); WindowsVersion::WindowsFastRing => {
Ok([first_va, last_va]) let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
}, let path_first_va: String = vec![
_ => { "_MI_SYSTEM_INFORMATION",
Err("Windows version for nonpaged pool algorithm is not implemented".into()) "Hardware",
} "SystemNodeNonPagedPool",
} "NonPagedPoolFirstVa",
} ]
.join(".");
} let path_last_va: String = vec![
"_MI_SYSTEM_INFORMATION",
"Hardware",
"SystemNodeNonPagedPool",
"NonPagedPoolLastVa",
]
.join(".");
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
Ok([first_va, last_va])
}
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => {
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
let path_first_va: String = vec![
"_MI_SYSTEM_INFORMATION",
"Hardware",
"SystemNodeInformation",
"NonPagedPoolFirstVa",
]
.join(".");
let path_last_va: String = vec![
"_MI_SYSTEM_INFORMATION",
"Hardware",
"SystemNodeInformation",
"NonPagedPoolLastVa",
]
.join(".");
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
Ok([first_va, last_va])
}
WindowsVersion::Windows7 => {
let path_first_va =
ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?;
let path_last_va =
ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?;
let first_va = Address::from_base(self.deref_addr_new(path_first_va.address()));
let last_va = Address::from_base(self.deref_addr_new(path_last_va.address()));
Ok([first_va, last_va])
}
_ => Err("Windows version for nonpaged pool algorithm is not implemented".into()),
}
}
}

View File

@ -1,137 +1,184 @@
use crate::pdb_store::PdbStore; use crate::pdb_store::PdbStore;
use crate::windows::WindowsVersion; use crate::windows::WindowsVersion;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct OffsetData { pub struct OffsetData {
eprocess_name_offset: u64, eprocess_name_offset: u64,
eprocess_link_offset: u64, eprocess_link_offset: u64,
list_blink_offset: u64, list_blink_offset: u64,
process_head_offset: u64, process_head_offset: u64,
mistate_offset: u64, mistate_offset: u64,
hardware_offset: u64, hardware_offset: u64,
system_node_offset: u64, system_node_offset: u64,
first_va_offset: u64, first_va_offset: u64,
last_va_offset: u64, last_va_offset: u64,
large_page_table_offset: u64, large_page_table_offset: u64,
large_page_size_offset: u64, large_page_size_offset: u64,
pool_chunk_size: u64, pool_chunk_size: u64,
} }
// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version // TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version
impl OffsetData { impl OffsetData {
pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self { pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self {
// TODO: Fix the backend so that only neccessary fields are used // TODO: Fix the backend so that only neccessary fields are used
// This is too much, most of the functionality has been move to the frontend // This is too much, most of the functionality has been move to the frontend
match windows_version { match windows_version {
WindowsVersion::WindowsFastRing => Self { WindowsVersion::WindowsFastRing => Self {
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64), eprocess_name_offset: pdb_store
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64), .get_offset("_EPROCESS.ImageFileName")
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), .unwrap_or(0u64),
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), eprocess_link_offset: pdb_store
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), .get_offset("_EPROCESS.ActiveProcessLinks")
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), .unwrap_or(0u64),
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool").unwrap_or(0u64), list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64), process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64), mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), hardware_offset: pdb_store
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), .get_offset("_MI_SYSTEM_INFORMATION.Hardware")
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), .unwrap_or(0u64),
}, system_node_offset: pdb_store
WindowsVersion::Windows10_2019 | .get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool")
WindowsVersion::Windows10_2018 => Self { .unwrap_or(0u64),
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64), first_va_offset: pdb_store
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64), .get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), .unwrap_or(0u64),
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), last_va_offset: pdb_store
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), .get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), .unwrap_or(0u64),
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64), large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64), large_page_size_offset: pdb_store
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64), .get_offset("PoolBigPageTableSize")
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), .unwrap_or(0u64),
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), pool_chunk_size: pdb_store
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), .get_offset("_POOL_HEADER.struct_size")
}, .unwrap_or(0u64),
WindowsVersion::Windows7 => Self { },
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64), WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => Self {
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64), eprocess_name_offset: pdb_store
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), .get_offset("_EPROCESS.ImageFileName")
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), .unwrap_or(0u64),
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), eprocess_link_offset: pdb_store
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), .get_offset("_EPROCESS.ActiveProcessLinks")
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64), .unwrap_or(0u64),
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64), list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64), process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), hardware_offset: pdb_store
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), .get_offset("_MI_SYSTEM_INFORMATION.Hardware")
}, .unwrap_or(0u64),
// TODO: Add other version of Windows here system_node_offset: pdb_store
// TODO: Warn user of unknown windows version, because BSOD will occur .get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
_ => Self { .unwrap_or(0u64),
eprocess_name_offset: 0u64, first_va_offset: pdb_store
eprocess_link_offset: 0u64, .get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
list_blink_offset: 0u64, .unwrap_or(0u64),
process_head_offset: 0u64, last_va_offset: pdb_store
mistate_offset: 0u64, .get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
hardware_offset: 0u64, .unwrap_or(0u64),
system_node_offset: 0u64, large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
first_va_offset: 0u64, large_page_size_offset: pdb_store
last_va_offset: 0u64, .get_offset("PoolBigPageTableSize")
large_page_table_offset: 0u64, .unwrap_or(0u64),
large_page_size_offset: 0u64, pool_chunk_size: pdb_store
pool_chunk_size: 0u64, .get_offset("_POOL_HEADER.struct_size")
} .unwrap_or(0u64),
} },
} WindowsVersion::Windows7 => Self {
} eprocess_name_offset: pdb_store
.get_offset("_EPROCESS.ImageFileName")
#[repr(C)] .unwrap_or(0u64),
#[derive(Debug, Copy, Clone)] eprocess_link_offset: pdb_store
pub struct DerefAddr { .get_offset("_EPROCESS.ActiveProcessLinks")
pub addr: u64, .unwrap_or(0u64),
pub size: u64 list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
} process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
#[repr(C)] hardware_offset: pdb_store
#[derive(Debug, Copy, Clone)] .get_offset("_MI_SYSTEM_INFORMATION.Hardware")
pub struct ScanPoolData { .unwrap_or(0u64),
pub start: u64, system_node_offset: pdb_store
pub end: u64, .get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
pub tag: u32 .unwrap_or(0u64),
} first_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
impl ScanPoolData{ .unwrap_or(0u64),
pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self { last_va_offset: pdb_store
Self { .get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
start: arr[0], .unwrap_or(0u64),
end: arr[1], large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
tag: u32::from_le_bytes(*tag) large_page_size_offset: pdb_store
} .get_offset("PoolBigPageTableSize")
} .unwrap_or(0u64),
} pool_chunk_size: pdb_store
.get_offset("_POOL_HEADER.struct_size")
#[repr(C)] .unwrap_or(0u64),
#[derive(Debug, Copy, Clone)] },
pub struct HideProcess { // TODO: Add other version of Windows here
pub name: [u8; 15], // TODO: Warn user of unknown windows version, because BSOD will occur
pub size: u64 _ => Self {
} eprocess_name_offset: 0u64,
eprocess_link_offset: 0u64,
#[repr(C)] list_blink_offset: 0u64,
pub union InputData { process_head_offset: 0u64,
pub offset_value: OffsetData, mistate_offset: 0u64,
pub deref_addr: DerefAddr, hardware_offset: 0u64,
pub scan_range: ScanPoolData, system_node_offset: 0u64,
pub hide_process: HideProcess, first_va_offset: 0u64,
} last_va_offset: 0u64,
large_page_table_offset: 0u64,
#[repr(C)] large_page_size_offset: 0u64,
#[derive(Debug, Copy, Clone)] pool_chunk_size: 0u64,
pub struct Nothing; // for empty data },
}
#[repr(C)] }
pub union OutputData { }
pub nothing: Nothing,
} #[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct DerefAddr {
pub addr: u64,
pub size: u64,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ScanPoolData {
pub start: u64,
pub end: u64,
pub tag: u32,
}
impl ScanPoolData {
pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self {
Self {
start: arr[0],
end: arr[1],
tag: u32::from_le_bytes(*tag),
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct HideProcess {
pub name: [u8; 15],
pub size: u64,
}
#[repr(C)]
pub union InputData {
pub offset_value: OffsetData,
pub deref_addr: DerefAddr,
pub scan_range: ScanPoolData,
pub hide_process: HideProcess,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Nothing; // for empty data
#[repr(C)]
pub union OutputData {
pub nothing: Nothing,
}

1100
src/lib.rs

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
use std::error::Error;
use std::str::{from_utf8};
use serde_json::{json, Value};
use crate::driver_state::DriverState;
use crate::address::Address; use crate::address::Address;
use crate::driver_state::DriverState;
use crate::{get_device_type, to_epoch}; use crate::{get_device_type, to_epoch};
use serde_json::{json, Value};
use std::error::Error;
use std::str::from_utf8;
type BoxResult<T> = Result<T, Box<dyn Error>>; type BoxResult<T> = Result<T, Box<dyn Error>>;
@ -29,26 +29,29 @@ pub fn make_eprocess(d: &DriverState, a: &Address) -> BoxResult<Value> {
let pid: u64 = d.decompose(a, "_EPROCESS.UniqueProcessId")?; let pid: u64 = d.decompose(a, "_EPROCESS.UniqueProcessId")?;
let ppid: u64 = d.decompose(a, "_EPROCESS.InheritedFromUniqueProcessId")?; let ppid: u64 = d.decompose(a, "_EPROCESS.InheritedFromUniqueProcessId")?;
let image_name: Vec<u8> = d.decompose_array(a, "_EPROCESS.ImageFileName", 15)?; let image_name: Vec<u8> = d.decompose_array(a, "_EPROCESS.ImageFileName", 15)?;
let filename_ptr = d.address_of(a, "_EPROCESS.ImageFilePointer.FileName") let filename_ptr = d
.unwrap_or(0); // ImageFilePointer is after Windows 10 Anniversary .address_of(a, "_EPROCESS.ImageFilePointer.FileName")
.unwrap_or(0); // ImageFilePointer is after Windows 10 Anniversary
let eprocess_name = let eprocess_name = if let Ok(name) = from_utf8(&image_name) {
if let Ok(name) = from_utf8(&image_name) { name.to_string().trim_end_matches(char::from(0)).to_string()
name.to_string().trim_end_matches(char::from(0)).to_string() } else {
} else { "".to_string()
"".to_string() };
}; let binary_path = d.get_unicode_string(filename_ptr).unwrap_or("".to_string());
let binary_path = d.get_unicode_string(filename_ptr)
.unwrap_or("".to_string());
let thread_head = d.address_of(a, "_EPROCESS.ThreadListHead")?; let thread_head = d.address_of(a, "_EPROCESS.ThreadListHead")?;
let threads: Vec<Value> = let threads: Vec<Value> = make_list_entry(
make_list_entry(d, Address::from_base(thread_head), "_ETHREAD.ThreadListEntry") d,
.unwrap_or(Vec::new()).iter() Address::from_base(thread_head),
.map(|thread_addr| { "_ETHREAD.ThreadListEntry",
make_ethread(d, thread_addr) )
.unwrap_or(json!({})) // unlikely .unwrap_or(Vec::new())
}).collect(); .iter()
.map(|thread_addr| {
make_ethread(d, thread_addr).unwrap_or(json!({})) // unlikely
})
.collect();
let c_t = to_epoch(createtime); let c_t = to_epoch(createtime);
let e_t = to_epoch(exittime); let e_t = to_epoch(exittime);
@ -77,12 +80,13 @@ pub fn make_ethread(d: &DriverState, a: &Address) -> BoxResult<Value> {
// let exittime: u64 = d.decompose(a, "_ETHREAD.ExitTime")?; // let exittime: u64 = d.decompose(a, "_ETHREAD.ExitTime")?;
let pid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueProcess")?; let pid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueProcess")?;
let tid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueThread")?; let tid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueThread")?;
let name_ptr: u64 = d.address_of(a, "_ETHREAD.ThreadName") let name_ptr: u64 = d.address_of(a, "_ETHREAD.ThreadName").unwrap_or(0); // ThreadName is after Windows 10 Anniversary
.unwrap_or(0); // ThreadName is after Windows 10 Anniversary
let thread_name = let thread_name = if let Ok(name) = d.get_unicode_string(name_ptr) {
if let Ok(name) = d.get_unicode_string(name_ptr) { name } name
else { "".to_string() }; } else {
"".to_string()
};
// let c_t = to_epoch(createtime); // let c_t = to_epoch(createtime);
// let e_t = to_epoch(exittime); // let e_t = to_epoch(exittime);
@ -114,12 +118,13 @@ pub fn make_driver(d: &DriverState, a: &Address) -> BoxResult<Value> {
let unload: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverUnload")?; let unload: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverUnload")?;
let size: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverSize")?; let size: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverSize")?;
let devicename = d.get_unicode_string(devicename_ptr) let devicename = d
.unwrap_or("".to_string()); .get_unicode_string(devicename_ptr)
let hardware = d.get_unicode_string(hardware_ptr) .unwrap_or("".to_string());
.unwrap_or("".to_string()); let hardware = d.get_unicode_string(hardware_ptr).unwrap_or("".to_string());
let servicekey = d.get_unicode_string(servicekey_ptr) let servicekey = d
.unwrap_or("".to_string()); .get_unicode_string(servicekey_ptr)
.unwrap_or("".to_string());
// device tree walk // device tree walk
let devices = { let devices = {
@ -134,7 +139,8 @@ pub fn make_driver(d: &DriverState, a: &Address) -> BoxResult<Value> {
let mut attached_devices: Vec<Value> = Vec::new(); let mut attached_devices: Vec<Value> = Vec::new();
while attached_ptr != 0 { while attached_ptr != 0 {
let attached = Address::from_base(attached_ptr); let attached = Address::from_base(attached_ptr);
let attached_device_type: u32 = d.decompose(&attached, "_DEVICE_OBJECT.DeviceType")?; let attached_device_type: u32 =
d.decompose(&attached, "_DEVICE_OBJECT.DeviceType")?;
attached_devices.push(json!({ attached_devices.push(json!({
"address": format!("0x{:x}", attached_ptr), "address": format!("0x{:x}", attached_ptr),
"type": "_DEVICE_OBJECT", "type": "_DEVICE_OBJECT",
@ -177,20 +183,27 @@ pub fn make_ldr(d: &DriverState, a: &Address) -> BoxResult<Value> {
let fullname_ptr = d.address_of(a, "_LDR_DATA_TABLE_ENTRY.FullDllName")?; let fullname_ptr = d.address_of(a, "_LDR_DATA_TABLE_ENTRY.FullDllName")?;
let basename_ptr = d.address_of(a, "_LDR_DATA_TABLE_ENTRY.BaseDllName")?; let basename_ptr = d.address_of(a, "_LDR_DATA_TABLE_ENTRY.BaseDllName")?;
let fullname = d.get_unicode_string(fullname_ptr) let fullname = d.get_unicode_string(fullname_ptr).unwrap_or("".to_string());
.unwrap_or("".to_string()); let basename = d.get_unicode_string(basename_ptr).unwrap_or("".to_string());
let basename = d.get_unicode_string(basename_ptr)
.unwrap_or("".to_string());
let ldr_load: Vec<String> = let ldr_load: Vec<String> =
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")? make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")?
.iter().map(|x| format!("0x{:x}", x.address())).collect(); .iter()
.map(|x| format!("0x{:x}", x.address()))
.collect();
let ldr_mem: Vec<String> = let ldr_mem: Vec<String> =
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks")? make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks")?
.iter().map(|x| format!("0x{:x}", x.address())).collect(); .iter()
let ldr_init: Vec<String> = .map(|x| format!("0x{:x}", x.address()))
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks")? .collect();
.iter().map(|x| format!("0x{:x}", x.address())).collect(); let ldr_init: Vec<String> = make_list_entry(
d,
a.clone(),
"_LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks",
)?
.iter()
.map(|x| format!("0x{:x}", x.address()))
.collect();
Ok(json!({ Ok(json!({
"address": format!("0x{:x}", a.address()), "address": format!("0x{:x}", a.address()),

File diff suppressed because it is too large Load Diff

View File

@ -1,295 +1,349 @@
use std::ffi::{c_void, CString}; use std::ffi::{c_void, CString};
use std::mem::{transmute, size_of_val}; use std::mem::{size_of_val, transmute};
use std::ptr::null_mut; use std::ptr::null_mut;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use widestring::U16CString; use widestring::U16CString;
use winapi::shared::ntdef::*; use winapi::shared::minwindef::{DWORD, HKEY, HMODULE};
use winapi::shared::minwindef::{DWORD, HKEY, HMODULE}; use winapi::shared::ntdef::*;
use winapi::um::winnt::{ use winapi::um::winnt::{
SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, KEY_WRITE, LUID_AND_ATTRIBUTES,
REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE, OSVERSIONINFOW, PRTL_OSVERSIONINFOW, REG_DWORD, REG_OPTION_NON_VOLATILE, REG_SZ,
PRTL_OSVERSIONINFOW, OSVERSIONINFOW, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES,
FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE };
};
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::ioapiset::{DeviceIoControl}; use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS};
use winapi::um::errhandlingapi::{GetLastError}; use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS}; use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle}; use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA};
use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress}; use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; use winapi::um::securitybaseapi::AdjustTokenPrivileges;
use winapi::um::sysinfoapi::{GetTickCount64}; use winapi::um::sysinfoapi::GetTickCount64;
use winapi::um::securitybaseapi::{AdjustTokenPrivileges}; use winapi::um::winbase::LookupPrivilegeValueA;
use winapi::um::winbase::{LookupPrivilegeValueA}; use winapi::um::winreg::{RegCloseKey, RegCreateKeyExA, RegSetValueExA, HKEY_LOCAL_MACHINE};
use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE};
const STR_DRIVER_REGISTRY_PATH: &str =
const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus"; "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus";
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub enum WindowsVersion { pub enum WindowsVersion {
Windows7, Windows7,
Windows8, Windows8,
Windows10Legacy, Windows10Legacy,
Windows10_2015, Windows10_2015,
Windows10_2016, Windows10_2016,
Windows10_2017, Windows10_2017,
Windows10_2018, Windows10_2018,
Windows10_2019, Windows10_2019,
Windows10_2020, Windows10_2020,
WindowsFastRing, WindowsFastRing,
WindowsUnknown WindowsUnknown,
} }
impl WindowsVersion { impl WindowsVersion {
pub fn not_supported(self) -> bool { pub fn not_supported(self) -> bool {
match self { match self {
WindowsVersion::Windows10Legacy | WindowsVersion::Windows10Legacy
WindowsVersion::Windows10_2015 | | WindowsVersion::Windows10_2015
WindowsVersion::Windows10_2016 | | WindowsVersion::Windows10_2016
WindowsVersion::Windows10_2017 | | WindowsVersion::Windows10_2017
WindowsVersion::Windows8 | | WindowsVersion::Windows8
WindowsVersion::WindowsUnknown => true, | WindowsVersion::WindowsUnknown => true,
_ => false _ => false,
} }
} }
pub fn is_supported(self) -> bool { pub fn is_supported(self) -> bool {
!self.not_supported() !self.not_supported()
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct WindowsFFI { pub struct WindowsFFI {
pub version_info: OSVERSIONINFOW, pub version_info: OSVERSIONINFOW,
pub short_version: WindowsVersion, pub short_version: WindowsVersion,
driver_handle: HANDLE, driver_handle: HANDLE,
ntdll: HMODULE, ntdll: HMODULE,
nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS, nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS,
nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS, nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS,
rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR), rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR),
rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS, rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS,
} }
impl WindowsFFI { impl WindowsFFI {
pub fn new() -> Self { pub fn new() -> Self {
let str_ntdll = CString::new("ntdll").unwrap(); let str_ntdll = CString::new("ntdll").unwrap();
let str_nt_load_driver = CString::new("NtLoadDriver").unwrap(); let str_nt_load_driver = CString::new("NtLoadDriver").unwrap();
let str_nt_unload_driver = CString::new("NtUnloadDriver").unwrap(); let str_nt_unload_driver = CString::new("NtUnloadDriver").unwrap();
let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").unwrap(); let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").unwrap();
let str_rtl_get_version = CString::new("RtlGetVersion").unwrap(); let str_rtl_get_version = CString::new("RtlGetVersion").unwrap();
let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap(); let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap();
let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap(); let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap();
let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\lpus").unwrap(); let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\lpus").unwrap();
let str_type = CString::new("Type").unwrap(); let str_type = CString::new("Type").unwrap();
let str_error_control = CString::new("ErrorControl").unwrap(); let str_error_control = CString::new("ErrorControl").unwrap();
let str_start = CString::new("Start").unwrap(); let str_start = CString::new("Start").unwrap();
let str_image_path = CString::new("ImagePath").unwrap(); let str_image_path = CString::new("ImagePath").unwrap();
let mut version_info = OSVERSIONINFOW { let mut version_info = OSVERSIONINFOW {
dwOSVersionInfoSize: 0u32, dwOSVersionInfoSize: 0u32,
dwMajorVersion: 0u32, dwMajorVersion: 0u32,
dwMinorVersion: 0u32, dwMinorVersion: 0u32,
dwBuildNumber: 0u32, dwBuildNumber: 0u32,
dwPlatformId: 0u32, dwPlatformId: 0u32,
szCSDVersion: [0u16; 128], szCSDVersion: [0u16; 128],
}; };
let ntdll: HMODULE; let ntdll: HMODULE;
let nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS; let nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS;
let nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS; let nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS;
let rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR); let rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR);
let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS; let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS;
// some pointer unsafe C code // some pointer unsafe C code
unsafe { unsafe {
ntdll = LoadLibraryA(str_ntdll.as_ptr()); ntdll = LoadLibraryA(str_ntdll.as_ptr());
let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr()); let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr());
let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr()); let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr());
let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr()); let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr());
let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr()); let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr());
nt_load_driver = transmute(nt_load_driver_); nt_load_driver = transmute(nt_load_driver_);
nt_unload_driver = transmute(nt_unload_driver_); nt_unload_driver = transmute(nt_unload_driver_);
rtl_init_unicode_str = transmute(rtl_init_unicode_str_); rtl_init_unicode_str = transmute(rtl_init_unicode_str_);
rtl_get_version = transmute(rtl_get_version_); rtl_get_version = transmute(rtl_get_version_);
// setup registry // setup registry
let mut registry_key: HKEY = null_mut(); let mut registry_key: HKEY = null_mut();
RegCreateKeyExA( RegCreateKeyExA(
HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(), HKEY_LOCAL_MACHINE,
0, null_mut(), str_registry_path.as_ptr(),
REG_OPTION_NON_VOLATILE, KEY_WRITE, 0,
null_mut(), &mut registry_key, null_mut() null_mut(),
); REG_OPTION_NON_VOLATILE,
let type_value: [u8; 4] = 1u32.to_le_bytes(); KEY_WRITE,
let error_control_value: [u8; 4] = 1u32.to_le_bytes(); null_mut(),
let start_value: [u8; 4] = 3u32.to_le_bytes(); &mut registry_key,
let registry_values = [ null_mut(),
(str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4), );
(str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4), let type_value: [u8; 4] = 1u32.to_le_bytes();
(str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4), let error_control_value: [u8; 4] = 1u32.to_le_bytes();
(str_image_path.as_ptr(), REG_SZ, let start_value: [u8; 4] = 3u32.to_le_bytes();
str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1) let registry_values = [
]; (str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4),
for &(key, keytype, value_ptr, size_in_bytes) in &registry_values { (
RegSetValueExA( str_error_control.as_ptr(),
registry_key, key, 0, REG_DWORD,
keytype, value_ptr, size_in_bytes as u32 error_control_value.as_ptr(),
); 4,
} ),
RegCloseKey(registry_key); (str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4),
(
// Setup privilege SeLoadDriverPrivilege str_image_path.as_ptr(),
let mut token_handle: HANDLE = null_mut(); REG_SZ,
let mut luid = LUID::default(); str_driver_path.as_ptr() as *const u8,
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle); str_driver_path.to_bytes().len() + 1,
LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); ),
let mut new_token_state = TOKEN_PRIVILEGES { ];
PrivilegeCount: 1, for &(key, keytype, value_ptr, size_in_bytes) in &registry_values {
Privileges: [LUID_AND_ATTRIBUTES { RegSetValueExA(
Luid: luid, registry_key,
Attributes: SE_PRIVILEGE_ENABLED key,
}] 0,
}; keytype,
AdjustTokenPrivileges( value_ptr,
token_handle, 0, &mut new_token_state, 16, null_mut(), null_mut()); size_in_bytes as u32,
CloseHandle(token_handle); );
} }
RegCloseKey(registry_key);
rtl_get_version(&mut version_info);
// Setup privilege SeLoadDriverPrivilege
let short_version = match version_info.dwBuildNumber { let mut token_handle: HANDLE = null_mut();
// 2600 => WindowsVersion::WindowsXP, let mut luid = LUID::default();
// 6000 | 6001 | 6002 => WindowsVersion::WindowsVista, OpenProcessToken(
7600 | 7601 => WindowsVersion::Windows7, GetCurrentProcess(),
9200 | 9600 => WindowsVersion::Windows8, TOKEN_ADJUST_PRIVILEGES,
10240 => WindowsVersion::Windows10Legacy, &mut token_handle,
10586 => WindowsVersion::Windows10_2015, );
14393 => WindowsVersion::Windows10_2016, LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid);
15063 | 16299 => WindowsVersion::Windows10_2017, let mut new_token_state = TOKEN_PRIVILEGES {
17134 | 17763 => WindowsVersion::Windows10_2018, PrivilegeCount: 1,
18363 | 18362 => WindowsVersion::Windows10_2019, Privileges: [LUID_AND_ATTRIBUTES {
19041 => WindowsVersion::Windows10_2020, Luid: luid,
x if x >= 19536 => WindowsVersion::WindowsFastRing, Attributes: SE_PRIVILEGE_ENABLED,
_ => WindowsVersion::WindowsUnknown }],
}; };
AdjustTokenPrivileges(
Self { token_handle,
version_info, 0,
short_version, &mut new_token_state,
driver_handle: INVALID_HANDLE_VALUE, 16,
ntdll, null_mut(),
nt_load_driver, null_mut(),
nt_unload_driver, );
rtl_init_unicode_str, CloseHandle(token_handle);
rtl_get_version }
}
} rtl_get_version(&mut version_info);
pub fn driver_loaded(self) -> bool { let short_version = match version_info.dwBuildNumber {
self.driver_handle != INVALID_HANDLE_VALUE // 2600 => WindowsVersion::WindowsXP,
} // 6000 | 6001 | 6002 => WindowsVersion::WindowsVista,
7600 | 7601 => WindowsVersion::Windows7,
pub fn load_driver(&mut self) -> NTSTATUS { 9200 | 9600 => WindowsVersion::Windows8,
// TODO: Move this to new() 10240 => WindowsVersion::Windows10Legacy,
// If we move this function to new(), self.driver_handle will be init, and thus no mut here 10586 => WindowsVersion::Windows10_2015,
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap(); 14393 => WindowsVersion::Windows10_2016,
let mut str_driver_reg_unicode = UNICODE_STRING::default(); 15063 | 16299 => WindowsVersion::Windows10_2017,
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); 17134 | 17763 => WindowsVersion::Windows10_2018,
let status = (self.nt_load_driver)(&mut str_driver_reg_unicode); 18363 | 18362 => WindowsVersion::Windows10_2019,
19041 => WindowsVersion::Windows10_2020,
let filename = CString::new("\\\\.\\poolscanner").unwrap(); x if x >= 19536 => WindowsVersion::WindowsFastRing,
let driver_file_handle: HANDLE = unsafe { _ => WindowsVersion::WindowsUnknown,
CreateFileA(filename.as_ptr(), };
GENERIC_READ | GENERIC_WRITE,
0, null_mut(), CREATE_ALWAYS, Self {
FILE_ATTRIBUTE_NORMAL, null_mut()) version_info,
}; short_version,
driver_handle: INVALID_HANDLE_VALUE,
if driver_file_handle == INVALID_HANDLE_VALUE { ntdll,
println!("Driver CreateFileA failed"); nt_load_driver,
} nt_unload_driver,
else { rtl_init_unicode_str,
self.driver_handle = driver_file_handle; rtl_get_version,
} }
status }
}
pub fn driver_loaded(self) -> bool {
pub fn unload_driver(&self) -> NTSTATUS { self.driver_handle != INVALID_HANDLE_VALUE
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap(); }
let mut str_driver_reg_unicode = UNICODE_STRING::default();
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); pub fn load_driver(&mut self) -> NTSTATUS {
(self.nt_unload_driver)(&mut str_driver_reg_unicode) // TODO: Move this to new()
} // If we move this function to new(), self.driver_handle will be init, and thus no mut here
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
#[allow(dead_code)] let mut str_driver_reg_unicode = UNICODE_STRING::default();
pub fn get_build_number(&self) -> DWORD { (self.rtl_init_unicode_str)(
self.version_info.dwBuildNumber &mut str_driver_reg_unicode,
} str_driver_reg.as_ptr() as *const u16,
);
#[allow(dead_code)] let status = (self.nt_load_driver)(&mut str_driver_reg_unicode);
pub fn print_version(&self) {
println!("Windows version: {}.{}.{} {:?}", let filename = CString::new("\\\\.\\poolscanner").unwrap();
self.version_info.dwMajorVersion, let driver_file_handle: HANDLE = unsafe {
self.version_info.dwMinorVersion, CreateFileA(
self.version_info.dwBuildNumber, filename.as_ptr(),
self.short_version GENERIC_READ | GENERIC_WRITE,
); 0,
} null_mut(),
CREATE_ALWAYS,
pub fn to_epoch(&self, filetime: u64) -> u64 { FILE_ATTRIBUTE_NORMAL,
let windows_epoch_diff = 11644473600000 * 10000; null_mut(),
if filetime < windows_epoch_diff { )
return 0; };
}
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; if driver_file_handle == INVALID_HANDLE_VALUE {
process_time_epoch println!("Driver CreateFileA failed");
} } else {
self.driver_handle = driver_file_handle;
pub fn valid_process_time(&self, filetime: u64) -> bool { }
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ status
let windows_epoch_diff = 11644473600000 * 10000; }
if filetime < windows_epoch_diff {
return false; pub fn unload_driver(&self) -> NTSTATUS {
} let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
let system_up_time_ms = unsafe { GetTickCount64() }; let mut str_driver_reg_unicode = UNICODE_STRING::default();
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr());
let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64; (self.nt_unload_driver)(&mut str_driver_reg_unicode)
let system_start_up_time_ms = }
now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */);
#[allow(dead_code)]
if process_time_epoch < system_start_up_time_ms { pub fn get_build_number(&self) -> DWORD {
false self.version_info.dwBuildNumber
} else if process_time_epoch > now_ms { }
false
} else { #[allow(dead_code)]
true pub fn print_version(&self) {
} println!(
} "Windows version: {}.{}.{} {:?}",
self.version_info.dwMajorVersion,
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD { self.version_info.dwMinorVersion,
self.device_io_raw(code, self.version_info.dwBuildNumber,
inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD, self.short_version
outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD) );
} }
pub fn device_io_raw(&self, code: DWORD, pub fn to_epoch(&self, filetime: u64) -> u64 {
input_ptr: *mut c_void, input_len: DWORD, let windows_epoch_diff = 11644473600000 * 10000;
output_ptr: *mut c_void, output_len: DWORD) -> DWORD { if filetime < windows_epoch_diff {
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code); return 0;
let mut bytes_returned: DWORD = 0; }
unsafe { let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
let status = DeviceIoControl(self.driver_handle, code, process_time_epoch
input_ptr, input_len, }
output_ptr, output_len,
&mut bytes_returned, null_mut()); pub fn valid_process_time(&self, filetime: u64) -> bool {
if status == 0 { // https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
println!("device io failed: last error {}", GetLastError()); let windows_epoch_diff = 11644473600000 * 10000;
} if filetime < windows_epoch_diff {
}; return false;
bytes_returned }
} let system_up_time_ms = unsafe { GetTickCount64() };
} let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond
let now_ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as u64;
let system_start_up_time_ms =
now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */);
if process_time_epoch < system_start_up_time_ms {
false
} else if process_time_epoch > now_ms {
false
} else {
true
}
}
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD {
self.device_io_raw(
code,
inbuf as *mut _ as *mut c_void,
size_of_val(inbuf) as DWORD,
outbuf as *mut _ as *mut c_void,
size_of_val(outbuf) as DWORD,
)
}
pub fn device_io_raw(
&self,
code: DWORD,
input_ptr: *mut c_void,
input_len: DWORD,
output_ptr: *mut c_void,
output_len: DWORD,
) -> DWORD {
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
let mut bytes_returned: DWORD = 0;
unsafe {
let status = DeviceIoControl(
self.driver_handle,
code,
input_ptr,
input_len,
output_ptr,
output_len,
&mut bytes_returned,
null_mut(),
);
if status == 0 {
println!("device io failed: last error {}", GetLastError());
}
};
bytes_returned
}
}