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",
driver.windows_ffi.short_version
)
.into());
} }
println!("NtLoadDriver() -> 0x{:x}", driver.startup()); println!("NtLoadDriver() -> 0x{:x}", driver.startup());
let result = scan_eprocess(&driver).unwrap_or(Vec::new()); let scan = scan_eprocess(&driver).unwrap_or(Vec::new());
let activehead = traverse_activehead(&driver).unwrap_or(Vec::new());
let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new());
let handletable = traverse_handletable(&driver).unwrap_or(Vec::new());
for r in result.iter() { for r in scan.iter() {
println!("{:#}", r.to_string()); println!("{:#}", r.to_string());
} }
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(()) 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,14 +1,15 @@
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>> { 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

@ -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

@ -4,9 +4,7 @@ use std::error::Error;
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 { pub fn to_epoch(filetime: u64) -> u64 {
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ // https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
@ -42,18 +40,18 @@ fn main() -> Result<(), Box<dyn Error>> {
if let Err(e) = driver.pdb_store.dt(&line) { if let Err(e) = driver.pdb_store.dt(&line) {
println!("{}", e); println!("{}", e);
} }
}, }
Err(ReadlineError::Interrupted) => { Err(ReadlineError::Interrupted) => {
println!("CTRL-C"); println!("CTRL-C");
break break;
}, }
Err(ReadlineError::Eof) => { Err(ReadlineError::Eof) => {
println!("CTRL-D"); println!("CTRL-D");
break break;
}, }
Err(err) => { Err(err) => {
println!("Error: {:?}", err); println!("Error: {:?}", err);
break break;
} }
} }
} }

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,24 +1,24 @@
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::windows::{WindowsFFI, WindowsVersion};
use crate::ioctl_protocol::{ use crate::ioctl_protocol::{
InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */ DerefAddr, InputData, /* OutputData, */ Nothing, OffsetData,
/* OutputData, */ Nothing ScanPoolData, /* HideProcess, */
}; };
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>>;
@ -42,19 +42,33 @@ pub enum DriverAction {
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)
}
DriverAction::ScanPoolRemote => {
CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_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)
}
} }
} }
} }
@ -65,7 +79,7 @@ pub struct EprocessPoolChunk {
pub eprocess_addr: u64, pub eprocess_addr: u64,
pub eprocess_name: String, pub eprocess_name: String,
pub create_time: u64, pub create_time: u64,
pub exit_time: u64 pub exit_time: u64,
} }
impl PartialEq for EprocessPoolChunk { impl PartialEq for EprocessPoolChunk {
@ -85,17 +99,20 @@ impl DriverState {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
pdb_store: parse_pdb().expect("Cannot get PDB file"), pdb_store: parse_pdb().expect("Cannot get PDB file"),
windows_ffi: WindowsFFI::new() windows_ffi: WindowsFFI::new(),
} }
} }
pub fn startup(&mut self) -> NTSTATUS { pub fn startup(&mut self) -> NTSTATUS {
let s = self.windows_ffi.load_driver(); let s = self.windows_ffi.load_driver();
let mut input = InputData { let mut input = InputData {
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version) offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version),
}; };
self.windows_ffi.device_io(DriverAction::SetupOffset.get_code(), self.windows_ffi.device_io(
&mut input, &mut Nothing); DriverAction::SetupOffset.get_code(),
&mut input,
&mut Nothing,
);
s s
} }
@ -111,23 +128,30 @@ impl DriverState {
// use old tag to scan, for Window < 8 // use old tag to scan, for Window < 8
if self.windows_ffi.short_version < WindowsVersion::Windows8 { if self.windows_ffi.short_version < WindowsVersion::Windows8 {
true true
} } else {
else {
false false
} }
} }
pub fn get_kernel_base(&self) -> Address { pub fn get_kernel_base(&self) -> Address {
let mut ntosbase = 0u64; let mut ntosbase = 0u64;
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(), self.windows_ffi.device_io(
&mut Nothing, &mut ntosbase); DriverAction::GetKernelBase.get_code(),
&mut Nothing,
&mut ntosbase,
);
Address::from_base(ntosbase) Address::from_base(ntosbase)
} }
pub fn scan_pool<F>(&self, tag: &[u8; 4], expected_struct: &str, mut handler: F) -> BoxResult<bool> pub fn scan_pool<F>(
where F: FnMut(Address, &[u8], Address) -> BoxResult<bool> &self,
// F(Pool Address, Pool Header Data, Pool Data Address) tag: &[u8; 4],
// TODO: Pool Header as a real struct expected_struct: &str,
mut handler: F,
) -> BoxResult<bool>
where
F: FnMut(Address, &[u8], Address) -> BoxResult<bool>, // F(Pool Address, Pool Header Data, Pool Data Address)
// TODO: Pool Header as a real struct
{ {
// TODO: scan large pool // TODO: scan large pool
// TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122 // TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122
@ -135,22 +159,27 @@ impl DriverState {
// https://docs.rs/gen-iter/0.2.0/gen_iter/ // https://docs.rs/gen-iter/0.2.0/gen_iter/
// >> More flexibility in code // >> More flexibility in code
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?; let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
let minimum_block_size = self.pdb_store.get_offset_r(&format!("{}.struct_size", expected_struct))? let minimum_block_size = self
+ pool_header_size; .pdb_store
.get_offset_r(&format!("{}.struct_size", expected_struct))?
+ pool_header_size;
let code = DriverAction::ScanPoolRemote.get_code(); let code = DriverAction::ScanPoolRemote.get_code();
let ntosbase = self.get_kernel_base(); let ntosbase = self.get_kernel_base();
let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?; let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?;
println!("kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}", println!(
ntosbase, start_address, end_address, tag, expected_struct); "kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}",
ntosbase, start_address, end_address, tag, expected_struct
);
let mut ptr = start_address; let mut ptr = start_address;
while ptr < end_address { while ptr < end_address {
let mut next_found = 0u64; let mut next_found = 0u64;
let mut input = InputData { let mut input = InputData {
scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag) scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag),
}; };
self.windows_ffi.device_io(code, &mut input, &mut next_found); self.windows_ffi
.device_io(code, &mut input, &mut next_found);
ptr = Address::from_base(next_found); ptr = Address::from_base(next_found);
if ptr >= end_address { if ptr >= end_address {
break; break;
@ -175,8 +204,7 @@ impl DriverState {
let success = handler(pool_addr, &header, data_addr).unwrap_or(false); let success = handler(pool_addr, &header, data_addr).unwrap_or(false);
if success { if success {
ptr += chunk_size; // skip this chunk ptr += chunk_size; // skip this chunk
} } else {
else {
ptr += 0x4; // search next ptr += 0x4; // search next
} }
} }
@ -184,19 +212,24 @@ impl DriverState {
} }
pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> { pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> {
let resolver = |p| { self.deref_addr_new(p) }; let resolver = |p| self.deref_addr_new(p);
let r = self.pdb_store.decompose(&addr, &name)?; let r = self.pdb_store.decompose(&addr, &name)?;
Ok(r.get(&resolver)) Ok(r.get(&resolver))
} }
pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> { pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> {
// interface to pdb_store.decompose // interface to pdb_store.decompose
let resolver = |p| { self.deref_addr_new(p) }; let resolver = |p| self.deref_addr_new(p);
let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver)); let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver));
Ok(r) Ok(r)
} }
pub fn decompose_array<T: Default + Clone>(&self, addr: &Address, name: &str, len: u64) -> BoxResult<Vec<T>> { pub fn decompose_array<T: Default + Clone>(
&self,
addr: &Address,
name: &str,
len: u64,
) -> BoxResult<Vec<T>> {
// interface to pdb_store.decompose for array // interface to pdb_store.decompose for array
let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len); let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len);
Ok(r) Ok(r)
@ -211,7 +244,7 @@ impl DriverState {
} }
pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> { pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> {
let resolver = |p| { self.deref_addr_new(p) }; let resolver = |p| self.deref_addr_new(p);
let mut r: Vec<T> = vec![Default::default(); len as usize]; let mut r: Vec<T> = vec![Default::default(); len as usize];
let size_in_byte = (len as usize) * size_of::<T>(); let size_in_byte = (len as usize) * size_of::<T>();
self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64); self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64);
@ -225,8 +258,8 @@ impl DriverState {
let mut input = InputData { let mut input = InputData {
deref_addr: DerefAddr { deref_addr: DerefAddr {
addr, addr,
size: size as u64 size: size as u64,
} },
}; };
self.windows_ffi.device_io(code, &mut input, outbuf); self.windows_ffi.device_io(code, &mut input, outbuf);
} }
@ -237,12 +270,16 @@ impl DriverState {
let mut input = InputData { let mut input = InputData {
deref_addr: DerefAddr { deref_addr: DerefAddr {
addr, addr,
size: output_len_as_byte size: output_len_as_byte,
} },
}; };
self.windows_ffi.device_io_raw(code, self.windows_ffi.device_io_raw(
&mut input as *mut _ as *mut c_void, size_of_val(&input) as DWORD, code,
outptr as *mut c_void, output_len_as_byte as DWORD); &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 get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> { pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
@ -253,8 +290,12 @@ impl DriverState {
let mut strlen = 0u16; let mut strlen = 0u16;
let mut capacity = 0u16; let mut capacity = 0u16;
let mut bufaddr = 0u64; let mut bufaddr = 0u64;
let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?; let buffer_ptr =
let capacity_addr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.MaximumLength")?; unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
let capacity_addr = unicode_str_addr
+ self
.pdb_store
.get_offset_r("_UNICODE_STRING.MaximumLength")?;
self.deref_addr(unicode_str_addr, &mut strlen); self.deref_addr(unicode_str_addr, &mut strlen);
self.deref_addr(capacity_addr, &mut capacity); self.deref_addr(capacity_addr, &mut capacity);
@ -284,48 +325,50 @@ impl DriverState {
"_MI_SYSTEM_INFORMATION", "_MI_SYSTEM_INFORMATION",
"Hardware", "Hardware",
"SystemNodeNonPagedPool", "SystemNodeNonPagedPool",
"NonPagedPoolFirstVa" "NonPagedPoolFirstVa",
].join("."); ]
.join(".");
let path_last_va: String = vec![ let path_last_va: String = vec![
"_MI_SYSTEM_INFORMATION", "_MI_SYSTEM_INFORMATION",
"Hardware", "Hardware",
"SystemNodeNonPagedPool", "SystemNodeNonPagedPool",
"NonPagedPoolLastVa" "NonPagedPoolLastVa",
].join("."); ]
.join(".");
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?); let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?); let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
Ok([first_va, last_va]) Ok([first_va, last_va])
}, }
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => {
WindowsVersion::Windows10_2018 => {
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?; let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
let path_first_va: String = vec![ let path_first_va: String = vec![
"_MI_SYSTEM_INFORMATION", "_MI_SYSTEM_INFORMATION",
"Hardware", "Hardware",
"SystemNodeInformation", "SystemNodeInformation",
"NonPagedPoolFirstVa" "NonPagedPoolFirstVa",
].join("."); ]
.join(".");
let path_last_va: String = vec![ let path_last_va: String = vec![
"_MI_SYSTEM_INFORMATION", "_MI_SYSTEM_INFORMATION",
"Hardware", "Hardware",
"SystemNodeInformation", "SystemNodeInformation",
"NonPagedPoolLastVa" "NonPagedPoolLastVa",
].join("."); ]
.join(".");
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?); let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?); let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
Ok([first_va, last_va]) Ok([first_va, last_va])
}, }
WindowsVersion::Windows7 => { WindowsVersion::Windows7 => {
let path_first_va = ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?; let path_first_va =
let path_last_va = ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?; 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 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())); let last_va = Address::from_base(self.deref_addr_new(path_last_va.address()));
Ok([first_va, last_va]) Ok([first_va, last_va])
},
_ => {
Err("Windows version for nonpaged pool algorithm is not implemented".into())
} }
_ => Err("Windows version for nonpaged pool algorithm is not implemented".into()),
} }
} }
} }

View File

@ -25,47 +25,94 @@ impl OffsetData {
// 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")
.unwrap_or(0u64),
eprocess_link_offset: pdb_store
.get_offset("_EPROCESS.ActiveProcessLinks")
.unwrap_or(0u64),
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), hardware_offset: pdb_store
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool").unwrap_or(0u64), .get_offset("_MI_SYSTEM_INFORMATION.Hardware")
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64), .unwrap_or(0u64),
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64), system_node_offset: pdb_store
.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool")
.unwrap_or(0u64),
first_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")
.unwrap_or(0u64),
last_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")
.unwrap_or(0u64),
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), large_page_size_offset: pdb_store
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), .get_offset("PoolBigPageTableSize")
.unwrap_or(0u64),
pool_chunk_size: pdb_store
.get_offset("_POOL_HEADER.struct_size")
.unwrap_or(0u64),
}, },
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => Self {
WindowsVersion::Windows10_2018 => Self { eprocess_name_offset: pdb_store
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64), .get_offset("_EPROCESS.ImageFileName")
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64), .unwrap_or(0u64),
eprocess_link_offset: pdb_store
.get_offset("_EPROCESS.ActiveProcessLinks")
.unwrap_or(0u64),
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), hardware_offset: pdb_store
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64), .get_offset("_MI_SYSTEM_INFORMATION.Hardware")
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64), .unwrap_or(0u64),
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64), system_node_offset: pdb_store
.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
.unwrap_or(0u64),
first_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
.unwrap_or(0u64),
last_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
.unwrap_or(0u64),
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), large_page_size_offset: pdb_store
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), .get_offset("PoolBigPageTableSize")
.unwrap_or(0u64),
pool_chunk_size: pdb_store
.get_offset("_POOL_HEADER.struct_size")
.unwrap_or(0u64),
}, },
WindowsVersion::Windows7 => Self { WindowsVersion::Windows7 => 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")
.unwrap_or(0u64),
eprocess_link_offset: pdb_store
.get_offset("_EPROCESS.ActiveProcessLinks")
.unwrap_or(0u64),
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), hardware_offset: pdb_store
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64), .get_offset("_MI_SYSTEM_INFORMATION.Hardware")
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64), .unwrap_or(0u64),
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64), system_node_offset: pdb_store
.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
.unwrap_or(0u64),
first_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
.unwrap_or(0u64),
last_va_offset: pdb_store
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
.unwrap_or(0u64),
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), large_page_size_offset: pdb_store
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), .get_offset("PoolBigPageTableSize")
.unwrap_or(0u64),
pool_chunk_size: pdb_store
.get_offset("_POOL_HEADER.struct_size")
.unwrap_or(0u64),
}, },
// TODO: Add other version of Windows here // TODO: Add other version of Windows here
// TODO: Warn user of unknown windows version, because BSOD will occur // TODO: Warn user of unknown windows version, because BSOD will occur
@ -82,7 +129,7 @@ impl OffsetData {
large_page_table_offset: 0u64, large_page_table_offset: 0u64,
large_page_size_offset: 0u64, large_page_size_offset: 0u64,
pool_chunk_size: 0u64, pool_chunk_size: 0u64,
} },
} }
} }
} }
@ -91,7 +138,7 @@ impl OffsetData {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct DerefAddr { pub struct DerefAddr {
pub addr: u64, pub addr: u64,
pub size: u64 pub size: u64,
} }
#[repr(C)] #[repr(C)]
@ -99,15 +146,15 @@ pub struct DerefAddr {
pub struct ScanPoolData { pub struct ScanPoolData {
pub start: u64, pub start: u64,
pub end: u64, pub end: u64,
pub tag: u32 pub tag: u32,
} }
impl ScanPoolData{ impl ScanPoolData {
pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self { pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self {
Self { Self {
start: arr[0], start: arr[0],
end: arr[1], end: arr[1],
tag: u32::from_le_bytes(*tag) tag: u32::from_le_bytes(*tag),
} }
} }
} }
@ -116,7 +163,7 @@ impl ScanPoolData{
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct HideProcess { pub struct HideProcess {
pub name: [u8; 15], pub name: [u8; 15],
pub size: u64 pub size: u64,
} }
#[repr(C)] #[repr(C)]

View File

@ -1,19 +1,19 @@
extern crate chrono;
extern crate app_dirs; extern crate app_dirs;
extern crate chrono;
pub mod address;
pub mod driver_state;
pub mod ioctl_protocol;
pub mod object;
pub mod pdb_store; pub mod pdb_store;
pub mod windows; pub mod windows;
pub mod ioctl_protocol;
pub mod driver_state;
pub mod address;
pub mod object;
use std::error::Error; use chrono::{DateTime, Local, TimeZone};
use chrono::{DateTime, TimeZone, Local};
use serde_json::{json, Value}; use serde_json::{json, Value};
use std::error::Error;
use driver_state::DriverState;
use address::Address; use address::Address;
use driver_state::DriverState;
use object::*; use object::*;
type BoxResult<T> = Result<T, Box<dyn Error>>; type BoxResult<T> = Result<T, Box<dyn Error>>;
@ -57,13 +57,15 @@ pub fn get_irp_name(idx: usize) -> String {
"IRP_MJ_DEVICE_CHANGE", "IRP_MJ_DEVICE_CHANGE",
"IRP_MJ_QUERY_QUOTA", "IRP_MJ_QUERY_QUOTA",
"IRP_MJ_SET_QUOTA", "IRP_MJ_SET_QUOTA",
"IRP_MJ_PNP" "IRP_MJ_PNP",
].iter().map(|x| x.to_string()).collect::<Vec<String>>(); ]
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>();
if let Some(name) = irp_names.get(idx) { if let Some(name) = irp_names.get(idx) {
name.clone() name.clone()
} } else {
else {
"UNKNOWN".to_string() "UNKNOWN".to_string()
} }
} }
@ -128,15 +130,18 @@ fn get_device_type(typ: u32) -> String {
0x00000024 => "FILE_DEVICE_VIRTUAL_DISK", 0x00000024 => "FILE_DEVICE_VIRTUAL_DISK",
0x00000025 => "FILE_DEVICE_WAVE_IN", 0x00000025 => "FILE_DEVICE_WAVE_IN",
0x00000026 => "FILE_DEVICE_WAVE_OUT", 0x00000026 => "FILE_DEVICE_WAVE_OUT",
_ => "UNKNOWN" _ => "UNKNOWN",
}.to_string() }
.to_string()
} }
pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> { pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new(); let mut result: Vec<Value> = Vec::new();
let tag = let tag = if driver.use_old_tag() {
if driver.use_old_tag() { b"Pro\xe3" } b"Pro\xe3"
else { b"Proc" }; } else {
b"Proc"
};
driver.scan_pool(tag, "_EPROCESS", |pool_addr, header, data_addr| { driver.scan_pool(tag, "_EPROCESS", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64; let chunk_size = (header[2] as u64) * 16u64;
@ -151,7 +156,7 @@ pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
if driver.windows_ffi.valid_process_time(create_time) { if driver.windows_ffi.valid_process_time(create_time) {
break; break;
} }
try_eprocess_ptr += 0x4; // search exhaustively try_eprocess_ptr += 0x4; // search exhaustively
} }
if try_eprocess_ptr > eprocess_valid_end { if try_eprocess_ptr > eprocess_valid_end {
return Ok(false); return Ok(false);
@ -166,9 +171,11 @@ pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> { pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new(); let mut result: Vec<Value> = Vec::new();
let tag = let tag = if driver.use_old_tag() {
if driver.use_old_tag() { b"Fil\xe5" } b"Fil\xe5"
else { b"File" }; } else {
b"File"
};
driver.scan_pool(tag, "_FILE_OBJECT", |pool_addr, header, data_addr| { driver.scan_pool(tag, "_FILE_OBJECT", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64; let chunk_size = (header[2] as u64) * 16u64;
@ -182,7 +189,7 @@ pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
if (size as u64) == fob_size && ftype == 5u16 { if (size as u64) == fob_size && ftype == 5u16 {
break; break;
} }
try_ptr += 0x4; // search exhaustively try_ptr += 0x4; // search exhaustively
} }
if try_ptr > valid_end { if try_ptr > valid_end {
return Ok(false); return Ok(false);
@ -196,23 +203,28 @@ pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
let share_write_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedWrite")?; let share_write_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedWrite")?;
let share_delete_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedDelete")?; let share_delete_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedDelete")?;
let filename_ptr = driver.address_of(fob_addr, "_FILE_OBJECT.FileName")?; let filename_ptr = driver.address_of(fob_addr, "_FILE_OBJECT.FileName")?;
let devicename_ptr: u64 = driver.address_of(fob_addr, "_FILE_OBJECT.DeviceObject.DriverObject.DriverName")?; let devicename_ptr: u64 = driver.address_of(
let hardware_ptr: u64 = driver.decompose(fob_addr, "_FILE_OBJECT.DeviceObject.DriverObject.HardwareDatabase")?; fob_addr,
"_FILE_OBJECT.DeviceObject.DriverObject.DriverName",
)?;
let hardware_ptr: u64 = driver.decompose(
fob_addr,
"_FILE_OBJECT.DeviceObject.DriverObject.HardwareDatabase",
)?;
let filename = let filename = if read_ok == 0 {
if read_ok == 0 { "[NOT READABLE]".to_string()
"[NOT READABLE]".to_string() } else if let Ok(n) = driver.get_unicode_string(filename_ptr) {
} n
else if let Ok(n) = driver.get_unicode_string(filename_ptr) { } else {
n "[NOT A VALID _UNICODE_STRING]".to_string()
} };
else { let devicename = driver
"[NOT A VALID _UNICODE_STRING]".to_string() .get_unicode_string(devicename_ptr)
}; .unwrap_or("".to_string());
let devicename = driver.get_unicode_string(devicename_ptr) let hardware = driver
.unwrap_or("".to_string()); .get_unicode_string(hardware_ptr)
let hardware = driver.get_unicode_string(hardware_ptr) .unwrap_or("".to_string());
.unwrap_or("".to_string());
result.push(json!({ result.push(json!({
"pool": format!("0x{:x}", pool_addr.address()), "pool": format!("0x{:x}", pool_addr.address()),
"address": format!("0x{:x}", fob_addr.address()), "address": format!("0x{:x}", fob_addr.address()),
@ -238,13 +250,17 @@ pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> { pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new(); let mut result: Vec<Value> = Vec::new();
let tag = let tag = if driver.use_old_tag() {
if driver.use_old_tag() { b"Thr\xe5" } b"Thr\xe5"
else { b"Thre" }; } else {
b"Thre"
};
driver.scan_pool(tag, "_ETHREAD", |pool_addr, header, data_addr| { driver.scan_pool(tag, "_ETHREAD", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64; let chunk_size = (header[2] as u64) * 16u64;
let object_header_size = driver.pdb_store.get_offset_r("_OBJECT_HEADER.struct_size")?; let object_header_size = driver
.pdb_store
.get_offset_r("_OBJECT_HEADER.struct_size")?;
let header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?; let header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?; let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?;
let ethread_valid_start = &data_addr; let ethread_valid_start = &data_addr;
@ -253,14 +269,13 @@ pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
if chunk_size == header_size + object_header_size + ethread_size { if chunk_size == header_size + object_header_size + ethread_size {
try_ethread_ptr = ethread_valid_end.clone(); try_ethread_ptr = ethread_valid_end.clone();
} } else {
else {
while try_ethread_ptr <= ethread_valid_end { while try_ethread_ptr <= ethread_valid_end {
let create_time: u64 = driver.decompose(&try_ethread_ptr, "_ETHREAD.CreateTime")?; let create_time: u64 = driver.decompose(&try_ethread_ptr, "_ETHREAD.CreateTime")?;
if driver.windows_ffi.valid_process_time(create_time) { if driver.windows_ffi.valid_process_time(create_time) {
break; break;
} }
try_ethread_ptr += 0x4; // search exhaustively try_ethread_ptr += 0x4; // search exhaustively
} }
if try_ethread_ptr > ethread_valid_end { if try_ethread_ptr > ethread_valid_end {
return Ok(false); return Ok(false);
@ -337,23 +352,29 @@ pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> { pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new(); let mut result: Vec<Value> = Vec::new();
let tag = let tag = if driver.use_old_tag() {
if driver.use_old_tag() { b"Dri\xf6" } b"Dri\xf6"
else { b"Driv" }; } else {
b"Driv"
};
driver.scan_pool(tag, "_DRIVER_OBJECT", |pool_addr, header, data_addr| { driver.scan_pool(tag, "_DRIVER_OBJECT", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64; let chunk_size = (header[2] as u64) * 16u64;
let dob_size = driver.pdb_store.get_offset_r("_DRIVER_OBJECT.struct_size")?; let dob_size = driver
.pdb_store
.get_offset_r("_DRIVER_OBJECT.struct_size")?;
let valid_end = (pool_addr.clone() + chunk_size) - dob_size; let valid_end = (pool_addr.clone() + chunk_size) - dob_size;
let mut try_ptr = data_addr; let mut try_ptr = data_addr;
while try_ptr <= valid_end { while try_ptr <= valid_end {
// No documentation on type constrain // No documentation on type constrain
let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?; let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?;
if (size as u64) == dob_size /* && ftype == 5u16 */ { if (size as u64) == dob_size
/* && ftype == 5u16 */
{
break; break;
} }
try_ptr += 0x4; // search exhaustively try_ptr += 0x4; // search exhaustively
} }
if try_ptr > valid_end { if try_ptr > valid_end {
return Ok(false); return Ok(false);
@ -368,23 +389,31 @@ pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> { pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new(); let mut result: Vec<Value> = Vec::new();
driver.scan_pool(b"MmLd", "_LDR_DATA_TABLE_ENTRY", |_pool_addr, _, data_addr| { driver.scan_pool(
// By reversing, this structure does not have any header b"MmLd",
result.push(make_ldr(driver, &data_addr)?); "_LDR_DATA_TABLE_ENTRY",
Ok(true) |_pool_addr, _, data_addr| {
})?; // By reversing, this structure does not have any header
result.push(make_ldr(driver, &data_addr)?);
Ok(true)
},
)?;
Ok(result) Ok(result)
} }
pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> { pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> {
let ntosbase = driver.get_kernel_base(); let ntosbase = driver.get_kernel_base();
let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?; let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?;
let result = let result = make_list_entry(
make_list_entry(driver, module_list_head.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")? driver,
.iter().map(|x| make_ldr(driver, &x).unwrap_or(json!({}))).collect(); module_list_head.clone(),
"_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks",
)?
.iter()
.map(|x| make_ldr(driver, &x).unwrap_or(json!({})))
.collect();
Ok(result) Ok(result)
} }
@ -395,7 +424,9 @@ pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>> {
let ntosbase = driver.get_kernel_base(); let ntosbase = driver.get_kernel_base();
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?; let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?; let eprocess_listentry_offset = driver
.pdb_store
.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
// TODO: make_list_entry // TODO: make_list_entry
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
@ -456,7 +487,9 @@ pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>> {
let ntosbase = driver.get_kernel_base(); let ntosbase = driver.get_kernel_base();
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?; let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?;
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_KPROCESS.ProcessListEntry")?; let eprocess_listentry_offset = driver
.pdb_store
.get_offset_r("_KPROCESS.ProcessListEntry")?;
// TODO: make_list_entry // TODO: make_list_entry
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
@ -476,7 +509,9 @@ pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>> {
let ntosbase = driver.get_kernel_base(); let ntosbase = driver.get_kernel_base();
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("HandleTableListHead")?; let process_list_head = ntosbase + driver.pdb_store.get_offset_r("HandleTableListHead")?;
let handle_list_offset = driver.pdb_store.get_offset_r("_HANDLE_TABLE.HandleTableList")?; let handle_list_offset = driver
.pdb_store
.get_offset_r("_HANDLE_TABLE.HandleTableList")?;
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
while ptr != process_list_head.address() { while ptr != process_list_head.address() {
@ -498,7 +533,8 @@ pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new(); let mut result: Vec<Value> = Vec::new();
let ntosbase = driver.get_kernel_base(); let ntosbase = driver.get_kernel_base();
let unload_array_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("MmUnloadedDrivers")?; let unload_array_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("MmUnloadedDrivers")?;
let num_unload_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("MmLastUnloadedDriver")?; let num_unload_ptr =
ntosbase.clone() + driver.pdb_store.get_offset_r("MmLastUnloadedDriver")?;
let unload_array = driver.deref_addr_new::<u64>(unload_array_ptr.address()); let unload_array = driver.deref_addr_new::<u64>(unload_array_ptr.address());
if unload_array == 0 { if unload_array == 0 {
@ -507,13 +543,13 @@ pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>> {
// by reversing MmLocateUnloadedDriver // by reversing MmLocateUnloadedDriver
let num_unload = driver.deref_addr_new::<u32>(num_unload_ptr.address()) as u64; let num_unload = driver.deref_addr_new::<u32>(num_unload_ptr.address()) as u64;
let bound = let bound = if num_unload > 0x32 { 0x32 } else { num_unload };
if num_unload > 0x32 { 0x32 }
else { num_unload };
let drivers = (0..bound).map(|i| Address::from_base(unload_array + (i * 0x28))); let drivers = (0..bound).map(|i| Address::from_base(unload_array + (i * 0x28)));
for driver_addr in drivers { for driver_addr in drivers {
let name = driver.get_unicode_string(driver_addr.address()).unwrap_or("".to_string()); let name = driver
.get_unicode_string(driver_addr.address())
.unwrap_or("".to_string());
let start_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.StartAddress")?; let start_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.StartAddress")?;
let end_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.EndAddress")?; let end_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.EndAddress")?;
let current_time: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.CurrentTime")?; let current_time: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.CurrentTime")?;

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()),

View File

@ -1,19 +1,22 @@
use std::error::Error;
use std::io;
use std::io::{Read};
use std::path::{PathBuf};
use std::fs::File;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::PathBuf;
use app_dirs::{app_dir, AppDataType, AppInfo};
use pdb::{ use pdb::{
PDB, SymbolData, TypeData, ClassType, ModifierType, Rva, ClassType, FallibleIterator, ModifierType, Rva, SymbolData, TypeData, TypeFinder, TypeIndex,
FallibleIterator, TypeFinder, TypeIndex PDB,
}; };
use app_dirs::{AppInfo, AppDataType, app_dir};
use crate::address::Address; use crate::address::Address;
const APP_INFO: AppInfo = AppInfo { name: "lpus", author: "nganhkhoa" }; const APP_INFO: AppInfo = AppInfo {
name: "lpus",
author: "nganhkhoa",
};
const KERNEL_PDB_NAME: &str = "ntkrnlmp.pdb"; const KERNEL_PDB_NAME: &str = "ntkrnlmp.pdb";
const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe";
@ -26,7 +29,7 @@ type StructStore = HashMap<String, HashMap<String, (String, u64)>>;
pub struct PdbStore { pub struct PdbStore {
pub symbols: SymbolStore, pub symbols: SymbolStore,
pub structs: StructStore pub structs: StructStore,
} }
impl PdbStore { impl PdbStore {
@ -39,25 +42,22 @@ impl PdbStore {
if name.contains(".") { if name.contains(".") {
let v: Vec<&str> = name.split_terminator('.').collect(); let v: Vec<&str> = name.split_terminator('.').collect();
match self.structs.get(v[0]) { match self.structs.get(v[0]) {
Some(member_info) => { Some(member_info) => match member_info.get(v[1]) {
match member_info.get(v[1]) { Some((_memtype, offset)) => Some(*offset),
Some((_memtype, offset)) => Some(*offset), None => None,
None => None
}
}, },
None => None None => None,
} }
} } else {
else {
match self.symbols.get(name) { match self.symbols.get(name) {
Some(offset) => Some(*offset), Some(offset) => Some(*offset),
None => None None => None,
} }
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn addr_decompose(&self, addr: u64, full_name: &str) -> BoxResult<u64>{ pub fn addr_decompose(&self, addr: u64, full_name: &str) -> BoxResult<u64> {
if !full_name.contains(".") { if !full_name.contains(".") {
return Err("Not decomposable".into()); return Err("Not decomposable".into());
} }
@ -65,24 +65,25 @@ impl PdbStore {
let mut name_part: Vec<&str> = full_name.split_terminator('.').collect(); let mut name_part: Vec<&str> = full_name.split_terminator('.').collect();
let mut next: Vec<_> = name_part.drain(2..).collect(); let mut next: Vec<_> = name_part.drain(2..).collect();
match self.structs.get(name_part[0]) { match self.structs.get(name_part[0]) {
Some(member_info) => { Some(member_info) => match member_info.get(name_part[1]) {
match member_info.get(name_part[1]) { Some((memtype, offset)) => {
Some((memtype, offset)) => { if next.len() != 0 {
if next.len() != 0 { if memtype.contains("*") {
if memtype.contains("*") { return Err(format!(
return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1]).into()); "Cannot dereference pointer at {} {}",
} memtype, name_part[1]
next.insert(0, memtype); )
self.addr_decompose(addr + *offset, &next.join(".")) .into());
} }
else { next.insert(0, memtype);
Ok(addr + *offset) self.addr_decompose(addr + *offset, &next.join("."))
} } else {
}, Ok(addr + *offset)
None => Err(format!("Not found member {}", name_part[1]).into()) }
} }
None => Err(format!("Not found member {}", name_part[1]).into()),
}, },
None => Err(format!("Struct {} not found", name_part[0]).into()) None => Err(format!("Struct {} not found", name_part[0]).into()),
} }
} }
@ -94,10 +95,13 @@ impl PdbStore {
let mut name_part: Vec<&str> = full_name.split_terminator('.').collect(); let mut name_part: Vec<&str> = full_name.split_terminator('.').collect();
let mut next: Vec<_> = name_part.drain(2..).collect(); let mut next: Vec<_> = name_part.drain(2..).collect();
let member_info = self.structs.get(name_part[0]) let member_info = self
.ok_or(format!("No struct {}", name_part[0]))?; .structs
let (memtype, offset) = member_info.get(name_part[1]) .get(name_part[0])
.ok_or(format!("No member {} in {}", name_part[1], name_part[0]))?; .ok_or(format!("No struct {}", name_part[0]))?;
let (memtype, offset) = member_info
.get(name_part[1])
.ok_or(format!("No member {} in {}", name_part[1], name_part[0]))?;
if next.len() == 0 { if next.len() == 0 {
return Ok(source.clone() + *offset); return Ok(source.clone() + *offset);
@ -108,9 +112,7 @@ impl PdbStore {
next.insert(0, &t); next.insert(0, &t);
let p = Address::from_ptr(source.clone() + *offset); let p = Address::from_ptr(source.clone() + *offset);
self.decompose(&p, &next.join(".")) self.decompose(&p, &next.join("."))
} else {
}
else {
next.insert(0, memtype); next.insert(0, memtype);
self.decompose(&(source.clone() + *offset), &next.join(".")) self.decompose(&(source.clone() + *offset), &next.join("."))
} }
@ -119,58 +121,90 @@ impl PdbStore {
#[allow(dead_code)] #[allow(dead_code)]
pub fn print_default_information(&self) { pub fn print_default_information(&self) {
let need_symbols = [ let need_symbols = [
"PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes", "PsLoadedModuleList",
"PoolBigPageTable", "PoolBigPageTableSize", "PsActiveProcessHead",
"KeNumberNodes",
"PoolBigPageTable",
"PoolBigPageTableSize",
// "PoolVector", "ExpNumberOfNonPagedPools", // "PoolVector", "ExpNumberOfNonPagedPools",
"KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP "KdDebuggerDataBlock",
"MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 "MmNonPagedPoolStart",
"MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap", "MmNonPagedPoolEnd", // Windows XP
"MiState" // Windows 10 "MiNonPagedPoolStartAligned",
"MiNonPagedPoolEnd",
"MiNonPagedPoolBitMap", // Windows 7, 8
"MiNonPagedPoolBitMap",
"MiNonPagedPoolVaBitMap",
"MiState", // Windows 10
]; ];
let mut need_structs = HashMap::new(); let mut need_structs = HashMap::new();
need_structs.insert("_POOL_HEADER", vec![ need_structs.insert(
"struct_size", "_POOL_HEADER",
"PoolType", "BlockSize", "PoolTag" vec!["struct_size", "PoolType", "BlockSize", "PoolTag"],
]); );
need_structs.insert("_PEB", vec![]); need_structs.insert("_PEB", vec![]);
need_structs.insert("_LIST_ENTRY", vec![ need_structs.insert("_LIST_ENTRY", vec!["Flink", "Blink"]);
"Flink", "Blink" need_structs.insert("_FILE_OBJECT", vec!["FileName"]);
]); need_structs.insert(
need_structs.insert("_FILE_OBJECT", vec![ "_EPROCESS",
"FileName" vec![
]); "struct_size",
need_structs.insert("_EPROCESS", vec![ "UniqueProcessId",
"struct_size", "ActiveProcessLinks",
"UniqueProcessId", "ActiveProcessLinks", "CreateTime", "CreateTime",
"Peb", "ImageFilePointer", "ImageFileName", "ThreadListHead" "Peb",
]); "ImageFilePointer",
need_structs.insert("_KDDEBUGGER_DATA64", vec![ "ImageFileName",
"MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP "ThreadListHead",
]); ],
);
need_structs.insert(
"_KDDEBUGGER_DATA64",
vec![
"MmNonPagedPoolStart",
"MmNonPagedPoolEnd", // Windows XP
],
);
need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]); need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]);
// these struct supports finding NonPagedPool{First,Last}Va in windows 10 // these struct supports finding NonPagedPool{First,Last}Va in windows 10
need_structs.insert("_MI_SYSTEM_INFORMATION", vec![ need_structs.insert(
"Hardware", // windows 10 2016+ "_MI_SYSTEM_INFORMATION",
"SystemNodeInformation" // windows 10 2015 vec![
]); "Hardware", // windows 10 2016+
need_structs.insert("_MI_HARDWARE_STATE", vec![ "SystemNodeInformation", // windows 10 2015
"SystemNodeInformation", // till windows 10 1900 ],
"SystemNodeNonPagedPool" // windows insider, 2020 );
]); need_structs.insert(
need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900 "_MI_HARDWARE_STATE",
"NonPagedPoolFirstVa", "NonPagedPoolLastVa", vec![
"NonPagedBitMap", // missing on windows 10 1900+ "SystemNodeInformation", // till windows 10 1900
"DynamicBitMapNonPagedPool" // some weird field "SystemNodeNonPagedPool", // windows insider, 2020
]); ],
need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020 );
"NonPagedPoolFirstVa", "NonPagedPoolLastVa", need_structs.insert(
"DynamicBitMapNonPagedPool" // some weird field "_MI_SYSTEM_NODE_INFORMATION",
]); vec![
// till windows 10 1900
"NonPagedPoolFirstVa",
"NonPagedPoolLastVa",
"NonPagedBitMap", // missing on windows 10 1900+
"DynamicBitMapNonPagedPool", // some weird field
],
);
need_structs.insert(
"_MI_SYSTEM_NODE_NONPAGED_POOL",
vec![
// windows insider, 2020
"NonPagedPoolFirstVa",
"NonPagedPoolLastVa",
"DynamicBitMapNonPagedPool", // some weird field
],
);
need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]); need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]);
need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020 need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020
need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020 need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020
for &symbol in &need_symbols { for &symbol in &need_symbols {
match self.symbols.get(symbol) { match self.symbols.get(symbol) {
@ -184,19 +218,23 @@ impl PdbStore {
Some(member_info) => { Some(member_info) => {
for &member in members { for &member in members {
match member_info.get(member) { match member_info.get(member) {
Some((memtype, offset)) => Some((memtype, offset)) => {
println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member), println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member)
}
None => {} None => {}
} }
} }
}, }
None => {} None => {}
} }
} }
} }
pub fn dt(&self, struct_name: &str) -> BoxResult<()> { pub fn dt(&self, struct_name: &str) -> BoxResult<()> {
let member_info = self.structs.get(struct_name).ok_or(format!("no struct named {}", struct_name))?; let member_info = self
.structs
.get(struct_name)
.ok_or(format!("no struct named {}", struct_name))?;
let (_, struct_size) = member_info.get("struct_size").ok_or("")?; let (_, struct_size) = member_info.get("struct_size").ok_or("")?;
println!("// 0x{:x} bytes", struct_size); println!("// 0x{:x} bytes", struct_size);
println!("struct {} {{", struct_name); println!("struct {} {{", struct_name);
@ -208,7 +246,7 @@ impl PdbStore {
members.push((*offset, t.to_string(), name.to_string())); members.push((*offset, t.to_string(), name.to_string()));
} }
} }
members.sort_by(|(o1,_,_), (o2,_,_)| o1.partial_cmp(o2).unwrap()); members.sort_by(|(o1, _, _), (o2, _, _)| o1.partial_cmp(o2).unwrap());
for (offset, memtype, member) in members.iter() { for (offset, memtype, member) in members.iter() {
println!(" +0x{:x} {} {};", offset, memtype, member); println!(" +0x{:x} {} {};", offset, memtype, member);
@ -221,22 +259,19 @@ impl PdbStore {
fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String { fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
match type_finder.find(*typ).unwrap().parse().unwrap() { match type_finder.find(*typ).unwrap().parse().unwrap() {
TypeData::Class(ct) => { TypeData::Class(ct) => format!("{}", ct.name.to_string()),
format!("{}", ct.name.to_string()) TypeData::Primitive(pt) => format!("{:?}", pt.kind),
}, TypeData::Pointer(pt) => format!("{}*", get_type_as_str(type_finder, &pt.underlying_type)),
TypeData::Primitive(pt) => {
format!("{:?}", pt.kind)
},
TypeData::Pointer(pt) => {
format!("{}*", get_type_as_str(type_finder, &pt.underlying_type))
},
TypeData::StaticMember(st) => { TypeData::StaticMember(st) => {
format!("static {}", get_type_as_str(type_finder, &st.field_type)) format!("static {}", get_type_as_str(type_finder, &st.field_type))
}, }
TypeData::Array(at) => { TypeData::Array(at) => {
format!("{}{:?}", format!(
get_type_as_str(type_finder, &at.element_type), /* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions) "{}{:?}",
}, get_type_as_str(type_finder, &at.element_type),
/* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions
)
}
// TypeData::Enumeration(et) => { // TypeData::Enumeration(et) => {
// format!("enumeration") // format!("enumeration")
// }, // },
@ -264,28 +299,82 @@ fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
TypeData::Procedure(pt) => { TypeData::Procedure(pt) => {
let rettype = match pt.return_type { let rettype = match pt.return_type {
Some(rt) => get_type_as_str(type_finder, &rt), Some(rt) => get_type_as_str(type_finder, &rt),
_ => "UNKNOWN".to_string() _ => "UNKNOWN".to_string(),
}; };
format!("{}({})", rettype, get_type_as_str(type_finder, &pt.argument_list)) format!(
}, "{}({})",
TypeData::Modifier(mt) => { rettype,
match mt { get_type_as_str(type_finder, &pt.argument_list)
ModifierType { constant: true, volatile: true, unaligned: true, .. } => )
format!("const volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), }
ModifierType { constant: true, volatile: true, unaligned: false, .. } => TypeData::Modifier(mt) => match mt {
format!("const volatile {}", get_type_as_str(type_finder, &mt.underlying_type)), ModifierType {
ModifierType { constant: true, volatile: false, unaligned: true, .. } => constant: true,
format!("const unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), volatile: true,
ModifierType { constant: false, volatile: true, unaligned: true, .. } => unaligned: true,
format!("volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), ..
ModifierType { constant: true, volatile: false, unaligned: false, .. } => } => format!(
format!("const {}", get_type_as_str(type_finder, &mt.underlying_type)), "const volatile unaligned {}",
ModifierType { constant: false, volatile: true, unaligned: false, .. } => get_type_as_str(type_finder, &mt.underlying_type)
format!("volatile {}", get_type_as_str(type_finder, &mt.underlying_type)), ),
ModifierType { constant: false, volatile: false, unaligned: true, .. } => ModifierType {
format!("unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), constant: true,
_ => format!("modifier {}", get_type_as_str(type_finder, &mt.underlying_type)) volatile: true,
} unaligned: false,
..
} => format!(
"const volatile {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
ModifierType {
constant: true,
volatile: false,
unaligned: true,
..
} => format!(
"const unaligned {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
ModifierType {
constant: false,
volatile: true,
unaligned: true,
..
} => format!(
"volatile unaligned {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
ModifierType {
constant: true,
volatile: false,
unaligned: false,
..
} => format!(
"const {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
ModifierType {
constant: false,
volatile: true,
unaligned: false,
..
} => format!(
"volatile {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
ModifierType {
constant: false,
volatile: false,
unaligned: true,
..
} => format!(
"unaligned {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
_ => format!(
"modifier {}",
get_type_as_str(type_finder, &mt.underlying_type)
),
}, },
// TypeData::Union(ut) => { // TypeData::Union(ut) => {
// format!("union") // format!("union")
@ -293,25 +382,21 @@ fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
// TypeData::Bitfield(bft) => { // TypeData::Bitfield(bft) => {
// format!("bitfield") // format!("bitfield")
// }, // },
TypeData::FieldList(_flt) => { TypeData::FieldList(_flt) => format!("fieldlist"),
format!("fieldlist")
},
// TypeData::ArgumentList(alt) => { // TypeData::ArgumentList(alt) => {
// format!("arglist") // format!("arglist")
// }, // },
// TypeData::MethodList(mlt) => { // TypeData::MethodList(mlt) => {
// format!("methodlist") // format!("methodlist")
// }, // },
unk => { unk => match unk.name() {
match unk.name() { Some(s) => format!("{}", s.to_string()),
Some(s) => format!("{}", s.to_string()), _ => "UNNOWN".to_string(),
_ => "UNNOWN".to_string() },
}
}
} }
} }
fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)>{ fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)> {
// TODO: Check file existance // TODO: Check file existance
let mut file = File::open(exe_file)?; let mut file = File::open(exe_file)?;
@ -329,22 +414,36 @@ fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)>{
buffiter.next().unwrap(), buffiter.next().unwrap(),
buffiter.next().unwrap(), buffiter.next().unwrap(),
buffiter.next().unwrap(), buffiter.next().unwrap(),
].concat(); ]
.concat();
// guid to hex string // guid to hex string
let guid = (vec![ let guid = (vec![
raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0], raw_guid[3],
raw_guid[5], raw_guid[4], raw_guid[2],
raw_guid[7], raw_guid[6], raw_guid[1],
raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11], raw_guid[0],
raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15], raw_guid[5],
].iter().map(|b| format!("{:02X}", b)).collect::<Vec<String>>()).join(""); raw_guid[4],
raw_guid[7],
raw_guid[6],
raw_guid[8],
raw_guid[9],
raw_guid[10],
raw_guid[11],
raw_guid[12],
raw_guid[13],
raw_guid[14],
raw_guid[15],
]
.iter()
.map(|b| format!("{:02X}", b))
.collect::<Vec<String>>())
.join("");
// next 4 bytes is age, in little endian // next 4 bytes is age, in little endian
let raw_age = buffiter.next().unwrap(); let raw_age = buffiter.next().unwrap();
let age = u32::from_le_bytes([ let age = u32::from_le_bytes([raw_age[0], raw_age[1], raw_age[2], raw_age[3]]);
raw_age[0], raw_age[1], raw_age[2], raw_age[3]
]);
Ok((guid, age)) Ok((guid, age))
} }
@ -358,14 +457,20 @@ fn pdb_exists(pdbname: &str, guid: &str, age: u32) -> BoxResult<(bool, PathBuf)>
// |--file.pdb // |--file.pdb
// |--|--GUID // |--|--GUID
// |--|--|--file.pdb // |--|--|--file.pdb
let mut pdb_location = app_dir(AppDataType::UserData, &APP_INFO, let mut pdb_location = app_dir(
&format!("{}/{}/{}", pdbname, guid, age))?; AppDataType::UserData,
&APP_INFO,
&format!("{}/{}/{}", pdbname, guid, age),
)?;
pdb_location.push(pdbname); pdb_location.push(pdbname);
Ok((pdb_location.exists(), pdb_location)) Ok((pdb_location.exists(), pdb_location))
} }
fn download_pdb(pdbname: &str, guid: &str, age: u32, outfile: &PathBuf) -> BoxResult<()> { fn download_pdb(pdbname: &str, guid: &str, age: u32, outfile: &PathBuf) -> BoxResult<()> {
let downloadurl = format!("{}/{}/{}{:X}/{}", PDB_SERVER_PATH, pdbname, guid, age, pdbname); let downloadurl = format!(
"{}/{}/{}{:X}/{}",
PDB_SERVER_PATH, pdbname, guid, age, pdbname
);
println!("{}", downloadurl); println!("{}", downloadurl);
let mut resp = reqwest::blocking::get(&downloadurl)?; let mut resp = reqwest::blocking::get(&downloadurl)?;
@ -390,8 +495,12 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
let info = pdb.pdb_information()?; let info = pdb.pdb_information()?;
let dbi = pdb.debug_information()?; let dbi = pdb.debug_information()?;
println!("PDB for {}, guid: {}, age: {}\n", println!(
dbi.machine_type().unwrap(), info.guid, dbi.age().unwrap_or(0)); "PDB for {}, guid: {}, age: {}\n",
dbi.machine_type().unwrap(),
info.guid,
dbi.age().unwrap_or(0)
);
let type_information = pdb.type_information()?; let type_information = pdb.type_information()?;
let mut type_finder = type_information.type_finder(); let mut type_finder = type_information.type_finder();
@ -410,9 +519,8 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
let name = symbol.name().unwrap().to_string(); let name = symbol.name().unwrap().to_string();
let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default(); let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default();
symbol_extracted.insert(format!("{}", name), rva as u64); symbol_extracted.insert(format!("{}", name), rva as u64);
},
_ => {
} }
_ => {}
} }
} }
@ -420,7 +528,12 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
iter = type_information.iter(); iter = type_information.iter();
while let Some(typ) = iter.next().unwrap() { while let Some(typ) = iter.next().unwrap() {
match typ.parse() { match typ.parse() {
Ok(TypeData::Class(ClassType {name, fields: Some(fields), size, ..})) => { Ok(TypeData::Class(ClassType {
name,
fields: Some(fields),
size,
..
})) => {
let mut struct_fields = HashMap::new(); let mut struct_fields = HashMap::new();
struct_fields.insert("struct_size".to_string(), ("U32".to_string(), size as u64)); struct_fields.insert("struct_size".to_string(), ("U32".to_string(), size as u64));
match type_finder.find(fields).unwrap().parse().unwrap() { match type_finder.find(fields).unwrap().parse().unwrap() {
@ -429,14 +542,16 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
if let TypeData::Member(member) = field { if let TypeData::Member(member) = field {
let mem_typ = get_type_as_str(&type_finder, &member.field_type); let mem_typ = get_type_as_str(&type_finder, &member.field_type);
struct_fields.insert( struct_fields.insert(
format!("{}", member.name), (mem_typ, member.offset as u64)); format!("{}", member.name),
(mem_typ, member.offset as u64),
);
} }
} }
} }
_ => {} _ => {}
} }
struct_extracted.insert(format!("{}", name), struct_fields); struct_extracted.insert(format!("{}", name), struct_fields);
}, }
_ => {} _ => {}
} }
} }
@ -448,12 +563,15 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
unload_driver_member.insert("Name".to_string(), ("_UNICODE_STRING".to_string(), 0)); unload_driver_member.insert("Name".to_string(), ("_UNICODE_STRING".to_string(), 0));
unload_driver_member.insert("StartAddress".to_string(), ("PVOID".to_string(), 0x10)); unload_driver_member.insert("StartAddress".to_string(), ("PVOID".to_string(), 0x10));
unload_driver_member.insert("EndAddress".to_string(), ("PVOID".to_string(), 0x18)); unload_driver_member.insert("EndAddress".to_string(), ("PVOID".to_string(), 0x18));
unload_driver_member.insert("CurrentTime".to_string(), ("_LARGE_INTEGER".to_string(), 0x20)); unload_driver_member.insert(
"CurrentTime".to_string(),
("_LARGE_INTEGER".to_string(), 0x20),
);
struct_extracted.insert("_UNLOADED_DRIVERS".to_string(), unload_driver_member); struct_extracted.insert("_UNLOADED_DRIVERS".to_string(), unload_driver_member);
} }
Ok(PdbStore { Ok(PdbStore {
symbols: symbol_extracted, symbols: symbol_extracted,
structs: struct_extracted structs: struct_extracted,
}) })
} }

View File

@ -1,30 +1,30 @@
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::ioapiset::{DeviceIoControl}; use winapi::um::errhandlingapi::GetLastError;
use winapi::um::errhandlingapi::{GetLastError};
use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS}; use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS};
use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle}; use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress}; use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
use winapi::um::sysinfoapi::{GetTickCount64}; use winapi::um::securitybaseapi::AdjustTokenPrivileges;
use winapi::um::securitybaseapi::{AdjustTokenPrivileges}; use winapi::um::sysinfoapi::GetTickCount64;
use winapi::um::winbase::{LookupPrivilegeValueA}; use winapi::um::winbase::LookupPrivilegeValueA;
use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE}; use winapi::um::winreg::{RegCloseKey, RegCreateKeyExA, RegSetValueExA, HKEY_LOCAL_MACHINE};
const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus"; const STR_DRIVER_REGISTRY_PATH: &str =
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus";
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
@ -39,19 +39,19 @@ pub enum WindowsVersion {
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 {
@ -119,25 +119,43 @@ impl WindowsFFI {
// 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,
KEY_WRITE,
null_mut(),
&mut registry_key,
null_mut(),
); );
let type_value: [u8; 4] = 1u32.to_le_bytes(); let type_value: [u8; 4] = 1u32.to_le_bytes();
let error_control_value: [u8; 4] = 1u32.to_le_bytes(); let error_control_value: [u8; 4] = 1u32.to_le_bytes();
let start_value: [u8; 4] = 3u32.to_le_bytes(); let start_value: [u8; 4] = 3u32.to_le_bytes();
let registry_values = [ let registry_values = [
(str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4), (str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4),
(str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4), (
str_error_control.as_ptr(),
REG_DWORD,
error_control_value.as_ptr(),
4,
),
(str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4), (str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4),
(str_image_path.as_ptr(), REG_SZ, (
str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1) str_image_path.as_ptr(),
REG_SZ,
str_driver_path.as_ptr() as *const u8,
str_driver_path.to_bytes().len() + 1,
),
]; ];
for &(key, keytype, value_ptr, size_in_bytes) in &registry_values { for &(key, keytype, value_ptr, size_in_bytes) in &registry_values {
RegSetValueExA( RegSetValueExA(
registry_key, key, 0, registry_key,
keytype, value_ptr, size_in_bytes as u32 key,
0,
keytype,
value_ptr,
size_in_bytes as u32,
); );
} }
RegCloseKey(registry_key); RegCloseKey(registry_key);
@ -145,17 +163,27 @@ impl WindowsFFI {
// Setup privilege SeLoadDriverPrivilege // Setup privilege SeLoadDriverPrivilege
let mut token_handle: HANDLE = null_mut(); let mut token_handle: HANDLE = null_mut();
let mut luid = LUID::default(); let mut luid = LUID::default();
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle); OpenProcessToken(
GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&mut token_handle,
);
LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid);
let mut new_token_state = TOKEN_PRIVILEGES { let mut new_token_state = TOKEN_PRIVILEGES {
PrivilegeCount: 1, PrivilegeCount: 1,
Privileges: [LUID_AND_ATTRIBUTES { Privileges: [LUID_AND_ATTRIBUTES {
Luid: luid, Luid: luid,
Attributes: SE_PRIVILEGE_ENABLED Attributes: SE_PRIVILEGE_ENABLED,
}] }],
}; };
AdjustTokenPrivileges( AdjustTokenPrivileges(
token_handle, 0, &mut new_token_state, 16, null_mut(), null_mut()); token_handle,
0,
&mut new_token_state,
16,
null_mut(),
null_mut(),
);
CloseHandle(token_handle); CloseHandle(token_handle);
} }
@ -174,7 +202,7 @@ impl WindowsFFI {
18363 | 18362 => WindowsVersion::Windows10_2019, 18363 | 18362 => WindowsVersion::Windows10_2019,
19041 => WindowsVersion::Windows10_2020, 19041 => WindowsVersion::Windows10_2020,
x if x >= 19536 => WindowsVersion::WindowsFastRing, x if x >= 19536 => WindowsVersion::WindowsFastRing,
_ => WindowsVersion::WindowsUnknown _ => WindowsVersion::WindowsUnknown,
}; };
Self { Self {
@ -185,7 +213,7 @@ impl WindowsFFI {
nt_load_driver, nt_load_driver,
nt_unload_driver, nt_unload_driver,
rtl_init_unicode_str, rtl_init_unicode_str,
rtl_get_version rtl_get_version,
} }
} }
@ -198,21 +226,28 @@ impl WindowsFFI {
// If we move this function to new(), self.driver_handle will be init, and thus no mut here // 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(); let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
let mut str_driver_reg_unicode = UNICODE_STRING::default(); let mut str_driver_reg_unicode = UNICODE_STRING::default();
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); (self.rtl_init_unicode_str)(
&mut str_driver_reg_unicode,
str_driver_reg.as_ptr() as *const u16,
);
let status = (self.nt_load_driver)(&mut str_driver_reg_unicode); let status = (self.nt_load_driver)(&mut str_driver_reg_unicode);
let filename = CString::new("\\\\.\\poolscanner").unwrap(); let filename = CString::new("\\\\.\\poolscanner").unwrap();
let driver_file_handle: HANDLE = unsafe { let driver_file_handle: HANDLE = unsafe {
CreateFileA(filename.as_ptr(), CreateFileA(
GENERIC_READ | GENERIC_WRITE, filename.as_ptr(),
0, null_mut(), CREATE_ALWAYS, GENERIC_READ | GENERIC_WRITE,
FILE_ATTRIBUTE_NORMAL, null_mut()) 0,
null_mut(),
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
null_mut(),
)
}; };
if driver_file_handle == INVALID_HANDLE_VALUE { if driver_file_handle == INVALID_HANDLE_VALUE {
println!("Driver CreateFileA failed"); println!("Driver CreateFileA failed");
} } else {
else {
self.driver_handle = driver_file_handle; self.driver_handle = driver_file_handle;
} }
status status
@ -232,7 +267,8 @@ impl WindowsFFI {
#[allow(dead_code)] #[allow(dead_code)]
pub fn print_version(&self) { pub fn print_version(&self) {
println!("Windows version: {}.{}.{} {:?}", println!(
"Windows version: {}.{}.{} {:?}",
self.version_info.dwMajorVersion, self.version_info.dwMajorVersion,
self.version_info.dwMinorVersion, self.version_info.dwMinorVersion,
self.version_info.dwBuildNumber, self.version_info.dwBuildNumber,
@ -257,7 +293,10 @@ impl WindowsFFI {
} }
let system_up_time_ms = unsafe { GetTickCount64() }; let system_up_time_ms = unsafe { GetTickCount64() };
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond 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 now_ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as u64;
let system_start_up_time_ms = let system_start_up_time_ms =
now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */); now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */);
@ -271,21 +310,36 @@ impl WindowsFFI {
} }
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD { pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD {
self.device_io_raw(code, self.device_io_raw(
inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD, code,
outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD) 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, pub fn device_io_raw(
input_ptr: *mut c_void, input_len: DWORD, &self,
output_ptr: *mut c_void, output_len: DWORD) -> DWORD { 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); // println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
let mut bytes_returned: DWORD = 0; let mut bytes_returned: DWORD = 0;
unsafe { unsafe {
let status = DeviceIoControl(self.driver_handle, code, let status = DeviceIoControl(
input_ptr, input_len, self.driver_handle,
output_ptr, output_len, code,
&mut bytes_returned, null_mut()); input_ptr,
input_len,
output_ptr,
output_len,
&mut bytes_returned,
null_mut(),
);
if status == 0 { if status == 0 {
println!("device io failed: last error {}", GetLastError()); println!("device io failed: last error {}", GetLastError());
} }