Run rustfmt
This commit is contained in:
parent
b1c3107c74
commit
a154c71f9b
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,30 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use lpus::{
|
use lpus::{
|
||||||
driver_state::{DriverState},
|
driver_state::DriverState, scan_eprocess, traverse_activehead, traverse_handletable,
|
||||||
scan_eprocess
|
traverse_kiprocesslist,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut driver = DriverState::new();
|
let mut driver = DriverState::new();
|
||||||
if !driver.is_supported() {
|
if !driver.is_supported() {
|
||||||
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into());
|
return Err(format!(
|
||||||
}
|
"Windows version {:?} is not supported",
|
||||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
driver.windows_ffi.short_version
|
||||||
|
)
|
||||||
let result = scan_eprocess(&driver).unwrap_or(Vec::new());
|
.into());
|
||||||
|
}
|
||||||
for r in result.iter() {
|
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||||
println!("{:#}", r.to_string());
|
|
||||||
}
|
let scan = scan_eprocess(&driver).unwrap_or(Vec::new());
|
||||||
|
let activehead = traverse_activehead(&driver).unwrap_or(Vec::new());
|
||||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new());
|
||||||
Ok(())
|
let handletable = traverse_handletable(&driver).unwrap_or(Vec::new());
|
||||||
}
|
|
||||||
|
for r in scan.iter() {
|
||||||
|
println!("{:#}", r.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use lpus::{
|
use lpus::{driver_state::DriverState, scan_file};
|
||||||
driver_state::{DriverState},
|
|
||||||
scan_file
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
};
|
let mut driver = DriverState::new();
|
||||||
|
if !driver.is_supported() {
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
return Err(format!(
|
||||||
let mut driver = DriverState::new();
|
"Windows version {:?} is not supported",
|
||||||
if !driver.is_supported() {
|
driver.windows_ffi.short_version
|
||||||
return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into());
|
)
|
||||||
}
|
.into());
|
||||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
}
|
||||||
|
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||||
let result = scan_file(&driver).unwrap_or(Vec::new());
|
|
||||||
|
let result = scan_file(&driver).unwrap_or(Vec::new());
|
||||||
for r in result.iter() {
|
|
||||||
println!("{:#}", r.to_string());
|
for r in result.iter() {
|
||||||
}
|
println!("{:#}", r.to_string());
|
||||||
|
}
|
||||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
|
||||||
Ok(())
|
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||||
}
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,63 +1,61 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
// use std::time::{SystemTime, UNIX_EPOCH};
|
// use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
|
|
||||||
use lpus::{
|
use lpus::driver_state::DriverState;
|
||||||
driver_state::{DriverState},
|
|
||||||
};
|
pub fn to_epoch(filetime: u64) -> u64 {
|
||||||
|
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
||||||
pub fn to_epoch(filetime: u64) -> u64 {
|
let windows_epoch_diff = 11644473600000 * 10000;
|
||||||
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
if filetime < windows_epoch_diff {
|
||||||
let windows_epoch_diff = 11644473600000 * 10000;
|
return 0;
|
||||||
if filetime < windows_epoch_diff {
|
}
|
||||||
return 0;
|
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
||||||
}
|
// let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
||||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
|
||||||
// let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
process_time_epoch
|
||||||
|
}
|
||||||
process_time_epoch
|
|
||||||
}
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let driver = DriverState::new();
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
driver.windows_ffi.print_version();
|
||||||
let driver = DriverState::new();
|
driver.pdb_store.print_default_information();
|
||||||
driver.windows_ffi.print_version();
|
|
||||||
driver.pdb_store.print_default_information();
|
println!("{}", to_epoch(0xfffffa80018cb688));
|
||||||
|
println!("{}", to_epoch(0x01d64ecd8b295318));
|
||||||
println!("{}", to_epoch(0xfffffa80018cb688));
|
|
||||||
println!("{}", to_epoch(0x01d64ecd8b295318));
|
let mut rl = Editor::<()>::new();
|
||||||
|
if rl.load_history("history.lpus").is_err() {
|
||||||
let mut rl = Editor::<()>::new();
|
println!("No previous history.");
|
||||||
if rl.load_history("history.lpus").is_err() {
|
}
|
||||||
println!("No previous history.");
|
loop {
|
||||||
}
|
let readline = rl.readline(">> ");
|
||||||
loop {
|
match readline {
|
||||||
let readline = rl.readline(">> ");
|
Ok(line) => {
|
||||||
match readline {
|
rl.add_history_entry(line.as_str());
|
||||||
Ok(line) => {
|
println!("Line: {}", line);
|
||||||
rl.add_history_entry(line.as_str());
|
// TODO: add parser here
|
||||||
println!("Line: {}", line);
|
if let Err(e) = driver.pdb_store.dt(&line) {
|
||||||
// TODO: add parser here
|
println!("{}", e);
|
||||||
if let Err(e) = driver.pdb_store.dt(&line) {
|
}
|
||||||
println!("{}", e);
|
}
|
||||||
}
|
Err(ReadlineError::Interrupted) => {
|
||||||
},
|
println!("CTRL-C");
|
||||||
Err(ReadlineError::Interrupted) => {
|
break;
|
||||||
println!("CTRL-C");
|
}
|
||||||
break
|
Err(ReadlineError::Eof) => {
|
||||||
},
|
println!("CTRL-D");
|
||||||
Err(ReadlineError::Eof) => {
|
break;
|
||||||
println!("CTRL-D");
|
}
|
||||||
break
|
Err(err) => {
|
||||||
},
|
println!("Error: {:?}", err);
|
||||||
Err(err) => {
|
break;
|
||||||
println!("Error: {:?}", err);
|
}
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
}
|
rl.save_history("history.lpus").unwrap();
|
||||||
}
|
|
||||||
rl.save_history("history.lpus").unwrap();
|
Ok(())
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,331 +1,374 @@
|
|||||||
use std::default::Default;
|
use std::clone::Clone;
|
||||||
use std::clone::Clone;
|
use std::default::Default;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
// use std::io::{Error, ErrorKind};
|
// use std::io::{Error, ErrorKind};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::mem::{size_of_val, size_of};
|
use std::mem::{size_of, size_of_val};
|
||||||
|
|
||||||
use winapi::shared::ntdef::{NTSTATUS};
|
use winapi::shared::minwindef::DWORD;
|
||||||
use winapi::shared::minwindef::{DWORD};
|
use winapi::shared::ntdef::NTSTATUS;
|
||||||
use winapi::um::winioctl::{
|
use winapi::um::winioctl::{
|
||||||
CTL_CODE, FILE_ANY_ACCESS,
|
CTL_CODE, FILE_ANY_ACCESS, METHOD_IN_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER,
|
||||||
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER
|
METHOD_OUT_DIRECT,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::address::Address;
|
use crate::address::Address;
|
||||||
use crate::pdb_store::{PdbStore, parse_pdb};
|
use crate::ioctl_protocol::{
|
||||||
use crate::windows::{WindowsFFI, WindowsVersion};
|
DerefAddr, InputData, /* OutputData, */ Nothing, OffsetData,
|
||||||
use crate::ioctl_protocol::{
|
ScanPoolData, /* HideProcess, */
|
||||||
InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */
|
};
|
||||||
/* OutputData, */ Nothing
|
use crate::pdb_store::{parse_pdb, PdbStore};
|
||||||
};
|
use crate::windows::{WindowsFFI, WindowsVersion};
|
||||||
|
|
||||||
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||||
|
|
||||||
const SIOCTL_TYPE: DWORD = 40000;
|
const SIOCTL_TYPE: DWORD = 40000;
|
||||||
|
|
||||||
pub fn to_epoch(filetime: u64) -> u64 {
|
pub fn to_epoch(filetime: u64) -> u64 {
|
||||||
let windows_epoch_diff: u64 = 11644473600000 * 10000;
|
let windows_epoch_diff: u64 = 11644473600000 * 10000;
|
||||||
if filetime < windows_epoch_diff {
|
if filetime < windows_epoch_diff {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let process_time_epoch: u64 = (filetime - windows_epoch_diff) / 10000;
|
let process_time_epoch: u64 = (filetime - windows_epoch_diff) / 10000;
|
||||||
process_time_epoch
|
process_time_epoch
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DriverAction {
|
pub enum DriverAction {
|
||||||
SetupOffset,
|
SetupOffset,
|
||||||
GetKernelBase,
|
GetKernelBase,
|
||||||
ScanPsActiveHead,
|
ScanPsActiveHead,
|
||||||
ScanPool,
|
ScanPool,
|
||||||
ScanPoolRemote,
|
ScanPoolRemote,
|
||||||
DereferenceAddress,
|
DereferenceAddress,
|
||||||
HideProcess
|
HideProcess,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DriverAction {
|
impl DriverAction {
|
||||||
pub fn get_code(&self) -> DWORD {
|
pub fn get_code(&self) -> DWORD {
|
||||||
match self {
|
match self {
|
||||||
DriverAction::SetupOffset => CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
DriverAction::SetupOffset => {
|
||||||
DriverAction::GetKernelBase => CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS),
|
CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||||
DriverAction::ScanPsActiveHead => CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS),
|
}
|
||||||
DriverAction::ScanPool => CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
DriverAction::GetKernelBase => {
|
||||||
DriverAction::ScanPoolRemote => CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||||
DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS),
|
}
|
||||||
DriverAction::HideProcess => CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
DriverAction::ScanPsActiveHead => {
|
||||||
}
|
CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
}
|
}
|
||||||
}
|
DriverAction::ScanPool => {
|
||||||
|
CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||||
#[derive(Debug)]
|
}
|
||||||
pub struct EprocessPoolChunk {
|
DriverAction::ScanPoolRemote => {
|
||||||
pub pool_addr: u64,
|
CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||||
pub eprocess_addr: u64,
|
}
|
||||||
pub eprocess_name: String,
|
DriverAction::DereferenceAddress => {
|
||||||
pub create_time: u64,
|
CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||||
pub exit_time: u64
|
}
|
||||||
}
|
DriverAction::HideProcess => {
|
||||||
|
CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||||
impl PartialEq for EprocessPoolChunk {
|
}
|
||||||
fn eq(&self, other: &Self) -> bool {
|
}
|
||||||
self.eprocess_addr == other.eprocess_addr
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
pub struct EprocessPoolChunk {
|
||||||
pub struct DriverState {
|
pub pool_addr: u64,
|
||||||
// TODO: Make private, only call methods of DriverState
|
pub eprocess_addr: u64,
|
||||||
pub pdb_store: PdbStore,
|
pub eprocess_name: String,
|
||||||
pub windows_ffi: WindowsFFI,
|
pub create_time: u64,
|
||||||
}
|
pub exit_time: u64,
|
||||||
|
}
|
||||||
impl DriverState {
|
|
||||||
pub fn new() -> Self {
|
impl PartialEq for EprocessPoolChunk {
|
||||||
Self {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
pdb_store: parse_pdb().expect("Cannot get PDB file"),
|
self.eprocess_addr == other.eprocess_addr
|
||||||
windows_ffi: WindowsFFI::new()
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn startup(&mut self) -> NTSTATUS {
|
pub struct DriverState {
|
||||||
let s = self.windows_ffi.load_driver();
|
// TODO: Make private, only call methods of DriverState
|
||||||
let mut input = InputData {
|
pub pdb_store: PdbStore,
|
||||||
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version)
|
pub windows_ffi: WindowsFFI,
|
||||||
};
|
}
|
||||||
self.windows_ffi.device_io(DriverAction::SetupOffset.get_code(),
|
|
||||||
&mut input, &mut Nothing);
|
impl DriverState {
|
||||||
s
|
pub fn new() -> Self {
|
||||||
}
|
Self {
|
||||||
|
pdb_store: parse_pdb().expect("Cannot get PDB file"),
|
||||||
pub fn shutdown(&self) -> NTSTATUS {
|
windows_ffi: WindowsFFI::new(),
|
||||||
self.windows_ffi.unload_driver()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_supported(&self) -> bool {
|
pub fn startup(&mut self) -> NTSTATUS {
|
||||||
self.windows_ffi.short_version.is_supported()
|
let s = self.windows_ffi.load_driver();
|
||||||
}
|
let mut input = InputData {
|
||||||
|
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version),
|
||||||
pub fn use_old_tag(&self) -> bool {
|
};
|
||||||
// use old tag to scan, for Window < 8
|
self.windows_ffi.device_io(
|
||||||
if self.windows_ffi.short_version < WindowsVersion::Windows8 {
|
DriverAction::SetupOffset.get_code(),
|
||||||
true
|
&mut input,
|
||||||
}
|
&mut Nothing,
|
||||||
else {
|
);
|
||||||
false
|
s
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
pub fn shutdown(&self) -> NTSTATUS {
|
||||||
pub fn get_kernel_base(&self) -> Address {
|
self.windows_ffi.unload_driver()
|
||||||
let mut ntosbase = 0u64;
|
}
|
||||||
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(),
|
|
||||||
&mut Nothing, &mut ntosbase);
|
pub fn is_supported(&self) -> bool {
|
||||||
Address::from_base(ntosbase)
|
self.windows_ffi.short_version.is_supported()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_pool<F>(&self, tag: &[u8; 4], expected_struct: &str, mut handler: F) -> BoxResult<bool>
|
pub fn use_old_tag(&self) -> bool {
|
||||||
where F: FnMut(Address, &[u8], Address) -> BoxResult<bool>
|
// use old tag to scan, for Window < 8
|
||||||
// F(Pool Address, Pool Header Data, Pool Data Address)
|
if self.windows_ffi.short_version < WindowsVersion::Windows8 {
|
||||||
// TODO: Pool Header as a real struct
|
true
|
||||||
{
|
} else {
|
||||||
// TODO: scan large pool
|
false
|
||||||
// TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122
|
}
|
||||||
// Making this function a generator will turn the call to a for loop
|
}
|
||||||
// https://docs.rs/gen-iter/0.2.0/gen_iter/
|
|
||||||
// >> More flexibility in code
|
pub fn get_kernel_base(&self) -> Address {
|
||||||
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
let mut ntosbase = 0u64;
|
||||||
let minimum_block_size = self.pdb_store.get_offset_r(&format!("{}.struct_size", expected_struct))?
|
self.windows_ffi.device_io(
|
||||||
+ pool_header_size;
|
DriverAction::GetKernelBase.get_code(),
|
||||||
let code = DriverAction::ScanPoolRemote.get_code();
|
&mut Nothing,
|
||||||
let ntosbase = self.get_kernel_base();
|
&mut ntosbase,
|
||||||
let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?;
|
);
|
||||||
|
Address::from_base(ntosbase)
|
||||||
println!("kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}",
|
}
|
||||||
ntosbase, start_address, end_address, tag, expected_struct);
|
|
||||||
|
pub fn scan_pool<F>(
|
||||||
let mut ptr = start_address;
|
&self,
|
||||||
while ptr < end_address {
|
tag: &[u8; 4],
|
||||||
let mut next_found = 0u64;
|
expected_struct: &str,
|
||||||
let mut input = InputData {
|
mut handler: F,
|
||||||
scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag)
|
) -> BoxResult<bool>
|
||||||
};
|
where
|
||||||
self.windows_ffi.device_io(code, &mut input, &mut next_found);
|
F: FnMut(Address, &[u8], Address) -> BoxResult<bool>, // F(Pool Address, Pool Header Data, Pool Data Address)
|
||||||
ptr = Address::from_base(next_found);
|
// TODO: Pool Header as a real struct
|
||||||
if ptr >= end_address {
|
{
|
||||||
break;
|
// TODO: scan large pool
|
||||||
}
|
// TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122
|
||||||
|
// Making this function a generator will turn the call to a for loop
|
||||||
let pool_addr = Address::from_base(ptr.address());
|
// https://docs.rs/gen-iter/0.2.0/gen_iter/
|
||||||
let header: Vec<u8> = self.deref_array(&pool_addr, pool_header_size);
|
// >> More flexibility in code
|
||||||
let chunk_size = (header[2] as u64) * 16u64;
|
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
||||||
|
let minimum_block_size = self
|
||||||
if pool_addr.address() + chunk_size > end_address.address() {
|
.pdb_store
|
||||||
// the chunk surpasses the non page pool range
|
.get_offset_r(&format!("{}.struct_size", expected_struct))?
|
||||||
break;
|
+ pool_header_size;
|
||||||
}
|
let code = DriverAction::ScanPoolRemote.get_code();
|
||||||
|
let ntosbase = self.get_kernel_base();
|
||||||
// automatically reject bad chunk
|
let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?;
|
||||||
if chunk_size < minimum_block_size {
|
|
||||||
ptr += 0x4;
|
println!(
|
||||||
continue;
|
"kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}",
|
||||||
}
|
ntosbase, start_address, end_address, tag, expected_struct
|
||||||
|
);
|
||||||
let data_addr = Address::from_base(pool_addr.address() + pool_header_size);
|
|
||||||
let success = handler(pool_addr, &header, data_addr).unwrap_or(false);
|
let mut ptr = start_address;
|
||||||
if success {
|
while ptr < end_address {
|
||||||
ptr += chunk_size; // skip this chunk
|
let mut next_found = 0u64;
|
||||||
}
|
let mut input = InputData {
|
||||||
else {
|
scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag),
|
||||||
ptr += 0x4; // search next
|
};
|
||||||
}
|
self.windows_ffi
|
||||||
}
|
.device_io(code, &mut input, &mut next_found);
|
||||||
Ok(true)
|
ptr = Address::from_base(next_found);
|
||||||
}
|
if ptr >= end_address {
|
||||||
|
break;
|
||||||
pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> {
|
}
|
||||||
let resolver = |p| { self.deref_addr_new(p) };
|
|
||||||
let r = self.pdb_store.decompose(&addr, &name)?;
|
let pool_addr = Address::from_base(ptr.address());
|
||||||
Ok(r.get(&resolver))
|
let header: Vec<u8> = self.deref_array(&pool_addr, pool_header_size);
|
||||||
}
|
let chunk_size = (header[2] as u64) * 16u64;
|
||||||
|
|
||||||
pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> {
|
if pool_addr.address() + chunk_size > end_address.address() {
|
||||||
// interface to pdb_store.decompose
|
// the chunk surpasses the non page pool range
|
||||||
let resolver = |p| { self.deref_addr_new(p) };
|
break;
|
||||||
let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver));
|
}
|
||||||
Ok(r)
|
|
||||||
}
|
// automatically reject bad chunk
|
||||||
|
if chunk_size < minimum_block_size {
|
||||||
pub fn decompose_array<T: Default + Clone>(&self, addr: &Address, name: &str, len: u64) -> BoxResult<Vec<T>> {
|
ptr += 0x4;
|
||||||
// interface to pdb_store.decompose for array
|
continue;
|
||||||
let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len);
|
}
|
||||||
Ok(r)
|
|
||||||
}
|
let data_addr = Address::from_base(pool_addr.address() + pool_header_size);
|
||||||
|
let success = handler(pool_addr, &header, data_addr).unwrap_or(false);
|
||||||
pub fn deref_addr_new<T: Default>(&self, addr: u64) -> T {
|
if success {
|
||||||
let mut r: T = Default::default();
|
ptr += chunk_size; // skip this chunk
|
||||||
if addr != 0 {
|
} else {
|
||||||
self.deref_addr(addr, &mut r);
|
ptr += 0x4; // search next
|
||||||
}
|
}
|
||||||
r
|
}
|
||||||
}
|
Ok(true)
|
||||||
|
}
|
||||||
pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> {
|
|
||||||
let resolver = |p| { self.deref_addr_new(p) };
|
pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> {
|
||||||
let mut r: Vec<T> = vec![Default::default(); len as usize];
|
let resolver = |p| self.deref_addr_new(p);
|
||||||
let size_in_byte = (len as usize) * size_of::<T>();
|
let r = self.pdb_store.decompose(&addr, &name)?;
|
||||||
self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64);
|
Ok(r.get(&resolver))
|
||||||
r
|
}
|
||||||
}
|
|
||||||
|
pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> {
|
||||||
// #[deprecated(note="use deref_addr_new<T>")]
|
// interface to pdb_store.decompose
|
||||||
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
let resolver = |p| self.deref_addr_new(p);
|
||||||
let code = DriverAction::DereferenceAddress.get_code();
|
let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver));
|
||||||
let size: usize = size_of_val(outbuf);
|
Ok(r)
|
||||||
let mut input = InputData {
|
}
|
||||||
deref_addr: DerefAddr {
|
|
||||||
addr,
|
pub fn decompose_array<T: Default + Clone>(
|
||||||
size: size as u64
|
&self,
|
||||||
}
|
addr: &Address,
|
||||||
};
|
name: &str,
|
||||||
self.windows_ffi.device_io(code, &mut input, outbuf);
|
len: u64,
|
||||||
}
|
) -> BoxResult<Vec<T>> {
|
||||||
|
// interface to pdb_store.decompose for array
|
||||||
// #[deprecated(note="use deref_array<T>")]
|
let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len);
|
||||||
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len_as_byte: u64) {
|
Ok(r)
|
||||||
let code = DriverAction::DereferenceAddress.get_code();
|
}
|
||||||
let mut input = InputData {
|
|
||||||
deref_addr: DerefAddr {
|
pub fn deref_addr_new<T: Default>(&self, addr: u64) -> T {
|
||||||
addr,
|
let mut r: T = Default::default();
|
||||||
size: output_len_as_byte
|
if addr != 0 {
|
||||||
}
|
self.deref_addr(addr, &mut r);
|
||||||
};
|
}
|
||||||
self.windows_ffi.device_io_raw(code,
|
r
|
||||||
&mut input as *mut _ as *mut c_void, size_of_val(&input) as DWORD,
|
}
|
||||||
outptr as *mut c_void, output_len_as_byte as DWORD);
|
|
||||||
}
|
pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> {
|
||||||
|
let resolver = |p| self.deref_addr_new(p);
|
||||||
pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
|
let mut r: Vec<T> = vec![Default::default(); len as usize];
|
||||||
if unicode_str_addr == 0 {
|
let size_in_byte = (len as usize) * size_of::<T>();
|
||||||
return Err("Not a valid address".into());
|
self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64);
|
||||||
}
|
r
|
||||||
|
}
|
||||||
let mut strlen = 0u16;
|
|
||||||
let mut capacity = 0u16;
|
// #[deprecated(note="use deref_addr_new<T>")]
|
||||||
let mut bufaddr = 0u64;
|
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
||||||
let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
|
let code = DriverAction::DereferenceAddress.get_code();
|
||||||
let capacity_addr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.MaximumLength")?;
|
let size: usize = size_of_val(outbuf);
|
||||||
|
let mut input = InputData {
|
||||||
self.deref_addr(unicode_str_addr, &mut strlen);
|
deref_addr: DerefAddr {
|
||||||
self.deref_addr(capacity_addr, &mut capacity);
|
addr,
|
||||||
self.deref_addr(buffer_ptr, &mut bufaddr);
|
size: size as u64,
|
||||||
|
},
|
||||||
if bufaddr == 0 || strlen > capacity || strlen == 0 || strlen % 2 != 0 {
|
};
|
||||||
return Err("Unicode string is empty".into());
|
self.windows_ffi.device_io(code, &mut input, outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = vec![0u16; (strlen / 2) as usize];
|
// #[deprecated(note="use deref_array<T>")]
|
||||||
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
|
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len_as_byte: u64) {
|
||||||
// TODO: BUG with deref_array, len is wrong,
|
let code = DriverAction::DereferenceAddress.get_code();
|
||||||
// >> the size of vector is strlen / 2
|
let mut input = InputData {
|
||||||
// >> the size to dereference is strlen
|
deref_addr: DerefAddr {
|
||||||
// XXX: use Vec<u8> and turn to Vec<u16>
|
addr,
|
||||||
// let buf: Vec<u16> = self.deref_array(&Address::from_base(bufaddr), (strlen / 2) as u64);
|
size: output_len_as_byte,
|
||||||
|
},
|
||||||
Ok(String::from_utf16(&buf)?)
|
};
|
||||||
}
|
self.windows_ffi.device_io_raw(
|
||||||
|
code,
|
||||||
pub fn get_nonpaged_range(&self, ntosbase: &Address) -> BoxResult<[Address; 2]> {
|
&mut input as *mut _ as *mut c_void,
|
||||||
// TODO: Add support for other Windows version here
|
size_of_val(&input) as DWORD,
|
||||||
match self.windows_ffi.short_version {
|
outptr as *mut c_void,
|
||||||
WindowsVersion::WindowsFastRing => {
|
output_len_as_byte as DWORD,
|
||||||
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
);
|
||||||
let path_first_va: String = vec![
|
}
|
||||||
"_MI_SYSTEM_INFORMATION",
|
|
||||||
"Hardware",
|
pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
|
||||||
"SystemNodeNonPagedPool",
|
if unicode_str_addr == 0 {
|
||||||
"NonPagedPoolFirstVa"
|
return Err("Not a valid address".into());
|
||||||
].join(".");
|
}
|
||||||
let path_last_va: String = vec![
|
|
||||||
"_MI_SYSTEM_INFORMATION",
|
let mut strlen = 0u16;
|
||||||
"Hardware",
|
let mut capacity = 0u16;
|
||||||
"SystemNodeNonPagedPool",
|
let mut bufaddr = 0u64;
|
||||||
"NonPagedPoolLastVa"
|
let buffer_ptr =
|
||||||
].join(".");
|
unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
|
||||||
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
let capacity_addr = unicode_str_addr
|
||||||
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
+ self
|
||||||
Ok([first_va, last_va])
|
.pdb_store
|
||||||
},
|
.get_offset_r("_UNICODE_STRING.MaximumLength")?;
|
||||||
WindowsVersion::Windows10_2019 |
|
|
||||||
WindowsVersion::Windows10_2018 => {
|
self.deref_addr(unicode_str_addr, &mut strlen);
|
||||||
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
self.deref_addr(capacity_addr, &mut capacity);
|
||||||
let path_first_va: String = vec![
|
self.deref_addr(buffer_ptr, &mut bufaddr);
|
||||||
"_MI_SYSTEM_INFORMATION",
|
|
||||||
"Hardware",
|
if bufaddr == 0 || strlen > capacity || strlen == 0 || strlen % 2 != 0 {
|
||||||
"SystemNodeInformation",
|
return Err("Unicode string is empty".into());
|
||||||
"NonPagedPoolFirstVa"
|
}
|
||||||
].join(".");
|
|
||||||
let path_last_va: String = vec![
|
let mut buf = vec![0u16; (strlen / 2) as usize];
|
||||||
"_MI_SYSTEM_INFORMATION",
|
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
|
||||||
"Hardware",
|
// TODO: BUG with deref_array, len is wrong,
|
||||||
"SystemNodeInformation",
|
// >> the size of vector is strlen / 2
|
||||||
"NonPagedPoolLastVa"
|
// >> the size to dereference is strlen
|
||||||
].join(".");
|
// XXX: use Vec<u8> and turn to Vec<u16>
|
||||||
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
// let buf: Vec<u16> = self.deref_array(&Address::from_base(bufaddr), (strlen / 2) as u64);
|
||||||
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
|
||||||
Ok([first_va, last_va])
|
Ok(String::from_utf16(&buf)?)
|
||||||
},
|
}
|
||||||
WindowsVersion::Windows7 => {
|
|
||||||
let path_first_va = ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?;
|
pub fn get_nonpaged_range(&self, ntosbase: &Address) -> BoxResult<[Address; 2]> {
|
||||||
let path_last_va = ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?;
|
// TODO: Add support for other Windows version here
|
||||||
let first_va = Address::from_base(self.deref_addr_new(path_first_va.address()));
|
match self.windows_ffi.short_version {
|
||||||
let last_va = Address::from_base(self.deref_addr_new(path_last_va.address()));
|
WindowsVersion::WindowsFastRing => {
|
||||||
Ok([first_va, last_va])
|
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||||
},
|
let path_first_va: String = vec![
|
||||||
_ => {
|
"_MI_SYSTEM_INFORMATION",
|
||||||
Err("Windows version for nonpaged pool algorithm is not implemented".into())
|
"Hardware",
|
||||||
}
|
"SystemNodeNonPagedPool",
|
||||||
}
|
"NonPagedPoolFirstVa",
|
||||||
}
|
]
|
||||||
|
.join(".");
|
||||||
}
|
let path_last_va: String = vec![
|
||||||
|
"_MI_SYSTEM_INFORMATION",
|
||||||
|
"Hardware",
|
||||||
|
"SystemNodeNonPagedPool",
|
||||||
|
"NonPagedPoolLastVa",
|
||||||
|
]
|
||||||
|
.join(".");
|
||||||
|
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
||||||
|
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||||
|
Ok([first_va, last_va])
|
||||||
|
}
|
||||||
|
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => {
|
||||||
|
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||||
|
let path_first_va: String = vec![
|
||||||
|
"_MI_SYSTEM_INFORMATION",
|
||||||
|
"Hardware",
|
||||||
|
"SystemNodeInformation",
|
||||||
|
"NonPagedPoolFirstVa",
|
||||||
|
]
|
||||||
|
.join(".");
|
||||||
|
let path_last_va: String = vec![
|
||||||
|
"_MI_SYSTEM_INFORMATION",
|
||||||
|
"Hardware",
|
||||||
|
"SystemNodeInformation",
|
||||||
|
"NonPagedPoolLastVa",
|
||||||
|
]
|
||||||
|
.join(".");
|
||||||
|
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
||||||
|
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||||
|
Ok([first_va, last_va])
|
||||||
|
}
|
||||||
|
WindowsVersion::Windows7 => {
|
||||||
|
let path_first_va =
|
||||||
|
ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?;
|
||||||
|
let path_last_va =
|
||||||
|
ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?;
|
||||||
|
let first_va = Address::from_base(self.deref_addr_new(path_first_va.address()));
|
||||||
|
let last_va = Address::from_base(self.deref_addr_new(path_last_va.address()));
|
||||||
|
Ok([first_va, last_va])
|
||||||
|
}
|
||||||
|
_ => Err("Windows version for nonpaged pool algorithm is not implemented".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,137 +1,184 @@
|
|||||||
use crate::pdb_store::PdbStore;
|
use crate::pdb_store::PdbStore;
|
||||||
use crate::windows::WindowsVersion;
|
use crate::windows::WindowsVersion;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct OffsetData {
|
pub struct OffsetData {
|
||||||
eprocess_name_offset: u64,
|
eprocess_name_offset: u64,
|
||||||
eprocess_link_offset: u64,
|
eprocess_link_offset: u64,
|
||||||
list_blink_offset: u64,
|
list_blink_offset: u64,
|
||||||
process_head_offset: u64,
|
process_head_offset: u64,
|
||||||
mistate_offset: u64,
|
mistate_offset: u64,
|
||||||
hardware_offset: u64,
|
hardware_offset: u64,
|
||||||
system_node_offset: u64,
|
system_node_offset: u64,
|
||||||
first_va_offset: u64,
|
first_va_offset: u64,
|
||||||
last_va_offset: u64,
|
last_va_offset: u64,
|
||||||
large_page_table_offset: u64,
|
large_page_table_offset: u64,
|
||||||
large_page_size_offset: u64,
|
large_page_size_offset: u64,
|
||||||
pool_chunk_size: u64,
|
pool_chunk_size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version
|
// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version
|
||||||
impl OffsetData {
|
impl OffsetData {
|
||||||
pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self {
|
pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self {
|
||||||
// TODO: Fix the backend so that only neccessary fields are used
|
// TODO: Fix the backend so that only neccessary fields are used
|
||||||
// This is too much, most of the functionality has been move to the frontend
|
// This is too much, most of the functionality has been move to the frontend
|
||||||
match windows_version {
|
match windows_version {
|
||||||
WindowsVersion::WindowsFastRing => Self {
|
WindowsVersion::WindowsFastRing => Self {
|
||||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
eprocess_name_offset: pdb_store
|
||||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
.get_offset("_EPROCESS.ImageFileName")
|
||||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
eprocess_link_offset: pdb_store
|
||||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
.get_offset("_EPROCESS.ActiveProcessLinks")
|
||||||
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool").unwrap_or(0u64),
|
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||||
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64),
|
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||||
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64),
|
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
hardware_offset: pdb_store
|
||||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
.get_offset("_MI_SYSTEM_INFORMATION.Hardware")
|
||||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
},
|
system_node_offset: pdb_store
|
||||||
WindowsVersion::Windows10_2019 |
|
.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool")
|
||||||
WindowsVersion::Windows10_2018 => Self {
|
.unwrap_or(0u64),
|
||||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
first_va_offset: pdb_store
|
||||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")
|
||||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
last_va_offset: pdb_store
|
||||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")
|
||||||
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64),
|
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||||
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64),
|
large_page_size_offset: pdb_store
|
||||||
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64),
|
.get_offset("PoolBigPageTableSize")
|
||||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
pool_chunk_size: pdb_store
|
||||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
.get_offset("_POOL_HEADER.struct_size")
|
||||||
},
|
.unwrap_or(0u64),
|
||||||
WindowsVersion::Windows7 => Self {
|
},
|
||||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => Self {
|
||||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
eprocess_name_offset: pdb_store
|
||||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
.get_offset("_EPROCESS.ImageFileName")
|
||||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
eprocess_link_offset: pdb_store
|
||||||
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64),
|
.get_offset("_EPROCESS.ActiveProcessLinks")
|
||||||
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64),
|
.unwrap_or(0u64),
|
||||||
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64),
|
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||||
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64),
|
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
hardware_offset: pdb_store
|
||||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
.get_offset("_MI_SYSTEM_INFORMATION.Hardware")
|
||||||
},
|
.unwrap_or(0u64),
|
||||||
// TODO: Add other version of Windows here
|
system_node_offset: pdb_store
|
||||||
// TODO: Warn user of unknown windows version, because BSOD will occur
|
.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
|
||||||
_ => Self {
|
.unwrap_or(0u64),
|
||||||
eprocess_name_offset: 0u64,
|
first_va_offset: pdb_store
|
||||||
eprocess_link_offset: 0u64,
|
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
|
||||||
list_blink_offset: 0u64,
|
.unwrap_or(0u64),
|
||||||
process_head_offset: 0u64,
|
last_va_offset: pdb_store
|
||||||
mistate_offset: 0u64,
|
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
|
||||||
hardware_offset: 0u64,
|
.unwrap_or(0u64),
|
||||||
system_node_offset: 0u64,
|
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||||
first_va_offset: 0u64,
|
large_page_size_offset: pdb_store
|
||||||
last_va_offset: 0u64,
|
.get_offset("PoolBigPageTableSize")
|
||||||
large_page_table_offset: 0u64,
|
.unwrap_or(0u64),
|
||||||
large_page_size_offset: 0u64,
|
pool_chunk_size: pdb_store
|
||||||
pool_chunk_size: 0u64,
|
.get_offset("_POOL_HEADER.struct_size")
|
||||||
}
|
.unwrap_or(0u64),
|
||||||
}
|
},
|
||||||
}
|
WindowsVersion::Windows7 => Self {
|
||||||
}
|
eprocess_name_offset: pdb_store
|
||||||
|
.get_offset("_EPROCESS.ImageFileName")
|
||||||
#[repr(C)]
|
.unwrap_or(0u64),
|
||||||
#[derive(Debug, Copy, Clone)]
|
eprocess_link_offset: pdb_store
|
||||||
pub struct DerefAddr {
|
.get_offset("_EPROCESS.ActiveProcessLinks")
|
||||||
pub addr: u64,
|
.unwrap_or(0u64),
|
||||||
pub size: u64
|
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||||
}
|
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||||
|
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||||
#[repr(C)]
|
hardware_offset: pdb_store
|
||||||
#[derive(Debug, Copy, Clone)]
|
.get_offset("_MI_SYSTEM_INFORMATION.Hardware")
|
||||||
pub struct ScanPoolData {
|
.unwrap_or(0u64),
|
||||||
pub start: u64,
|
system_node_offset: pdb_store
|
||||||
pub end: u64,
|
.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
|
||||||
pub tag: u32
|
.unwrap_or(0u64),
|
||||||
}
|
first_va_offset: pdb_store
|
||||||
|
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
|
||||||
impl ScanPoolData{
|
.unwrap_or(0u64),
|
||||||
pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self {
|
last_va_offset: pdb_store
|
||||||
Self {
|
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
|
||||||
start: arr[0],
|
.unwrap_or(0u64),
|
||||||
end: arr[1],
|
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||||
tag: u32::from_le_bytes(*tag)
|
large_page_size_offset: pdb_store
|
||||||
}
|
.get_offset("PoolBigPageTableSize")
|
||||||
}
|
.unwrap_or(0u64),
|
||||||
}
|
pool_chunk_size: pdb_store
|
||||||
|
.get_offset("_POOL_HEADER.struct_size")
|
||||||
#[repr(C)]
|
.unwrap_or(0u64),
|
||||||
#[derive(Debug, Copy, Clone)]
|
},
|
||||||
pub struct HideProcess {
|
// TODO: Add other version of Windows here
|
||||||
pub name: [u8; 15],
|
// TODO: Warn user of unknown windows version, because BSOD will occur
|
||||||
pub size: u64
|
_ => Self {
|
||||||
}
|
eprocess_name_offset: 0u64,
|
||||||
|
eprocess_link_offset: 0u64,
|
||||||
#[repr(C)]
|
list_blink_offset: 0u64,
|
||||||
pub union InputData {
|
process_head_offset: 0u64,
|
||||||
pub offset_value: OffsetData,
|
mistate_offset: 0u64,
|
||||||
pub deref_addr: DerefAddr,
|
hardware_offset: 0u64,
|
||||||
pub scan_range: ScanPoolData,
|
system_node_offset: 0u64,
|
||||||
pub hide_process: HideProcess,
|
first_va_offset: 0u64,
|
||||||
}
|
last_va_offset: 0u64,
|
||||||
|
large_page_table_offset: 0u64,
|
||||||
#[repr(C)]
|
large_page_size_offset: 0u64,
|
||||||
#[derive(Debug, Copy, Clone)]
|
pool_chunk_size: 0u64,
|
||||||
pub struct Nothing; // for empty data
|
},
|
||||||
|
}
|
||||||
#[repr(C)]
|
}
|
||||||
pub union OutputData {
|
}
|
||||||
pub nothing: Nothing,
|
|
||||||
}
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct DerefAddr {
|
||||||
|
pub addr: u64,
|
||||||
|
pub size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct ScanPoolData {
|
||||||
|
pub start: u64,
|
||||||
|
pub end: u64,
|
||||||
|
pub tag: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScanPoolData {
|
||||||
|
pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self {
|
||||||
|
Self {
|
||||||
|
start: arr[0],
|
||||||
|
end: arr[1],
|
||||||
|
tag: u32::from_le_bytes(*tag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct HideProcess {
|
||||||
|
pub name: [u8; 15],
|
||||||
|
pub size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union InputData {
|
||||||
|
pub offset_value: OffsetData,
|
||||||
|
pub deref_addr: DerefAddr,
|
||||||
|
pub scan_range: ScanPoolData,
|
||||||
|
pub hide_process: HideProcess,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Nothing; // for empty data
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union OutputData {
|
||||||
|
pub nothing: Nothing,
|
||||||
|
}
|
||||||
|
1100
src/lib.rs
1100
src/lib.rs
File diff suppressed because it is too large
Load Diff
@ -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()),
|
||||||
|
1036
src/pdb_store.rs
1036
src/pdb_store.rs
File diff suppressed because it is too large
Load Diff
644
src/windows.rs
644
src/windows.rs
@ -1,295 +1,349 @@
|
|||||||
use std::ffi::{c_void, CString};
|
use std::ffi::{c_void, CString};
|
||||||
use std::mem::{transmute, size_of_val};
|
use std::mem::{size_of_val, transmute};
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use widestring::U16CString;
|
use widestring::U16CString;
|
||||||
|
|
||||||
use winapi::shared::ntdef::*;
|
use winapi::shared::minwindef::{DWORD, HKEY, HMODULE};
|
||||||
use winapi::shared::minwindef::{DWORD, HKEY, HMODULE};
|
use winapi::shared::ntdef::*;
|
||||||
use winapi::um::winnt::{
|
use winapi::um::winnt::{
|
||||||
SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES,
|
FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, KEY_WRITE, LUID_AND_ATTRIBUTES,
|
||||||
REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE,
|
OSVERSIONINFOW, PRTL_OSVERSIONINFOW, REG_DWORD, REG_OPTION_NON_VOLATILE, REG_SZ,
|
||||||
PRTL_OSVERSIONINFOW, OSVERSIONINFOW,
|
SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES,
|
||||||
FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE
|
};
|
||||||
};
|
|
||||||
|
use winapi::um::errhandlingapi::GetLastError;
|
||||||
use winapi::um::ioapiset::{DeviceIoControl};
|
use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS};
|
||||||
use winapi::um::errhandlingapi::{GetLastError};
|
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
|
||||||
use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS};
|
use winapi::um::ioapiset::DeviceIoControl;
|
||||||
use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle};
|
use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA};
|
||||||
use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress};
|
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
|
||||||
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
|
use winapi::um::securitybaseapi::AdjustTokenPrivileges;
|
||||||
use winapi::um::sysinfoapi::{GetTickCount64};
|
use winapi::um::sysinfoapi::GetTickCount64;
|
||||||
use winapi::um::securitybaseapi::{AdjustTokenPrivileges};
|
use winapi::um::winbase::LookupPrivilegeValueA;
|
||||||
use winapi::um::winbase::{LookupPrivilegeValueA};
|
use winapi::um::winreg::{RegCloseKey, RegCreateKeyExA, RegSetValueExA, HKEY_LOCAL_MACHINE};
|
||||||
use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE};
|
|
||||||
|
const STR_DRIVER_REGISTRY_PATH: &str =
|
||||||
const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus";
|
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus";
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
|
||||||
pub enum WindowsVersion {
|
pub enum WindowsVersion {
|
||||||
Windows7,
|
Windows7,
|
||||||
Windows8,
|
Windows8,
|
||||||
Windows10Legacy,
|
Windows10Legacy,
|
||||||
Windows10_2015,
|
Windows10_2015,
|
||||||
Windows10_2016,
|
Windows10_2016,
|
||||||
Windows10_2017,
|
Windows10_2017,
|
||||||
Windows10_2018,
|
Windows10_2018,
|
||||||
Windows10_2019,
|
Windows10_2019,
|
||||||
Windows10_2020,
|
Windows10_2020,
|
||||||
WindowsFastRing,
|
WindowsFastRing,
|
||||||
WindowsUnknown
|
WindowsUnknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsVersion {
|
impl WindowsVersion {
|
||||||
pub fn not_supported(self) -> bool {
|
pub fn not_supported(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
WindowsVersion::Windows10Legacy |
|
WindowsVersion::Windows10Legacy
|
||||||
WindowsVersion::Windows10_2015 |
|
| WindowsVersion::Windows10_2015
|
||||||
WindowsVersion::Windows10_2016 |
|
| WindowsVersion::Windows10_2016
|
||||||
WindowsVersion::Windows10_2017 |
|
| WindowsVersion::Windows10_2017
|
||||||
WindowsVersion::Windows8 |
|
| WindowsVersion::Windows8
|
||||||
WindowsVersion::WindowsUnknown => true,
|
| WindowsVersion::WindowsUnknown => true,
|
||||||
_ => false
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_supported(self) -> bool {
|
pub fn is_supported(self) -> bool {
|
||||||
!self.not_supported()
|
!self.not_supported()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct WindowsFFI {
|
pub struct WindowsFFI {
|
||||||
pub version_info: OSVERSIONINFOW,
|
pub version_info: OSVERSIONINFOW,
|
||||||
pub short_version: WindowsVersion,
|
pub short_version: WindowsVersion,
|
||||||
driver_handle: HANDLE,
|
driver_handle: HANDLE,
|
||||||
ntdll: HMODULE,
|
ntdll: HMODULE,
|
||||||
nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS,
|
nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS,
|
||||||
nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS,
|
nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS,
|
||||||
rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR),
|
rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR),
|
||||||
rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS,
|
rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsFFI {
|
impl WindowsFFI {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let str_ntdll = CString::new("ntdll").unwrap();
|
let str_ntdll = CString::new("ntdll").unwrap();
|
||||||
let str_nt_load_driver = CString::new("NtLoadDriver").unwrap();
|
let str_nt_load_driver = CString::new("NtLoadDriver").unwrap();
|
||||||
let str_nt_unload_driver = CString::new("NtUnloadDriver").unwrap();
|
let str_nt_unload_driver = CString::new("NtUnloadDriver").unwrap();
|
||||||
let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").unwrap();
|
let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").unwrap();
|
||||||
let str_rtl_get_version = CString::new("RtlGetVersion").unwrap();
|
let str_rtl_get_version = CString::new("RtlGetVersion").unwrap();
|
||||||
let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap();
|
let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap();
|
||||||
|
|
||||||
let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap();
|
let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap();
|
||||||
let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\lpus").unwrap();
|
let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\lpus").unwrap();
|
||||||
let str_type = CString::new("Type").unwrap();
|
let str_type = CString::new("Type").unwrap();
|
||||||
let str_error_control = CString::new("ErrorControl").unwrap();
|
let str_error_control = CString::new("ErrorControl").unwrap();
|
||||||
let str_start = CString::new("Start").unwrap();
|
let str_start = CString::new("Start").unwrap();
|
||||||
let str_image_path = CString::new("ImagePath").unwrap();
|
let str_image_path = CString::new("ImagePath").unwrap();
|
||||||
|
|
||||||
let mut version_info = OSVERSIONINFOW {
|
let mut version_info = OSVERSIONINFOW {
|
||||||
dwOSVersionInfoSize: 0u32,
|
dwOSVersionInfoSize: 0u32,
|
||||||
dwMajorVersion: 0u32,
|
dwMajorVersion: 0u32,
|
||||||
dwMinorVersion: 0u32,
|
dwMinorVersion: 0u32,
|
||||||
dwBuildNumber: 0u32,
|
dwBuildNumber: 0u32,
|
||||||
dwPlatformId: 0u32,
|
dwPlatformId: 0u32,
|
||||||
szCSDVersion: [0u16; 128],
|
szCSDVersion: [0u16; 128],
|
||||||
};
|
};
|
||||||
|
|
||||||
let ntdll: HMODULE;
|
let ntdll: HMODULE;
|
||||||
let nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS;
|
let nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS;
|
||||||
let nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS;
|
let nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS;
|
||||||
let rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR);
|
let rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR);
|
||||||
let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS;
|
let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS;
|
||||||
|
|
||||||
// some pointer unsafe C code
|
// some pointer unsafe C code
|
||||||
unsafe {
|
unsafe {
|
||||||
ntdll = LoadLibraryA(str_ntdll.as_ptr());
|
ntdll = LoadLibraryA(str_ntdll.as_ptr());
|
||||||
let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr());
|
let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr());
|
||||||
let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr());
|
let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr());
|
||||||
let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr());
|
let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr());
|
||||||
let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr());
|
let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr());
|
||||||
|
|
||||||
nt_load_driver = transmute(nt_load_driver_);
|
nt_load_driver = transmute(nt_load_driver_);
|
||||||
nt_unload_driver = transmute(nt_unload_driver_);
|
nt_unload_driver = transmute(nt_unload_driver_);
|
||||||
rtl_init_unicode_str = transmute(rtl_init_unicode_str_);
|
rtl_init_unicode_str = transmute(rtl_init_unicode_str_);
|
||||||
rtl_get_version = transmute(rtl_get_version_);
|
rtl_get_version = transmute(rtl_get_version_);
|
||||||
|
|
||||||
// setup registry
|
// setup registry
|
||||||
let mut registry_key: HKEY = null_mut();
|
let mut registry_key: HKEY = null_mut();
|
||||||
RegCreateKeyExA(
|
RegCreateKeyExA(
|
||||||
HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(),
|
HKEY_LOCAL_MACHINE,
|
||||||
0, null_mut(),
|
str_registry_path.as_ptr(),
|
||||||
REG_OPTION_NON_VOLATILE, KEY_WRITE,
|
0,
|
||||||
null_mut(), &mut registry_key, null_mut()
|
null_mut(),
|
||||||
);
|
REG_OPTION_NON_VOLATILE,
|
||||||
let type_value: [u8; 4] = 1u32.to_le_bytes();
|
KEY_WRITE,
|
||||||
let error_control_value: [u8; 4] = 1u32.to_le_bytes();
|
null_mut(),
|
||||||
let start_value: [u8; 4] = 3u32.to_le_bytes();
|
&mut registry_key,
|
||||||
let registry_values = [
|
null_mut(),
|
||||||
(str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4),
|
);
|
||||||
(str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4),
|
let type_value: [u8; 4] = 1u32.to_le_bytes();
|
||||||
(str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4),
|
let error_control_value: [u8; 4] = 1u32.to_le_bytes();
|
||||||
(str_image_path.as_ptr(), REG_SZ,
|
let start_value: [u8; 4] = 3u32.to_le_bytes();
|
||||||
str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1)
|
let registry_values = [
|
||||||
];
|
(str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4),
|
||||||
for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values {
|
(
|
||||||
RegSetValueExA(
|
str_error_control.as_ptr(),
|
||||||
registry_key, key, 0,
|
REG_DWORD,
|
||||||
keytype, value_ptr, size_in_bytes as u32
|
error_control_value.as_ptr(),
|
||||||
);
|
4,
|
||||||
}
|
),
|
||||||
RegCloseKey(registry_key);
|
(str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4),
|
||||||
|
(
|
||||||
// Setup privilege SeLoadDriverPrivilege
|
str_image_path.as_ptr(),
|
||||||
let mut token_handle: HANDLE = null_mut();
|
REG_SZ,
|
||||||
let mut luid = LUID::default();
|
str_driver_path.as_ptr() as *const u8,
|
||||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle);
|
str_driver_path.to_bytes().len() + 1,
|
||||||
LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid);
|
),
|
||||||
let mut new_token_state = TOKEN_PRIVILEGES {
|
];
|
||||||
PrivilegeCount: 1,
|
for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values {
|
||||||
Privileges: [LUID_AND_ATTRIBUTES {
|
RegSetValueExA(
|
||||||
Luid: luid,
|
registry_key,
|
||||||
Attributes: SE_PRIVILEGE_ENABLED
|
key,
|
||||||
}]
|
0,
|
||||||
};
|
keytype,
|
||||||
AdjustTokenPrivileges(
|
value_ptr,
|
||||||
token_handle, 0, &mut new_token_state, 16, null_mut(), null_mut());
|
size_in_bytes as u32,
|
||||||
CloseHandle(token_handle);
|
);
|
||||||
}
|
}
|
||||||
|
RegCloseKey(registry_key);
|
||||||
rtl_get_version(&mut version_info);
|
|
||||||
|
// Setup privilege SeLoadDriverPrivilege
|
||||||
let short_version = match version_info.dwBuildNumber {
|
let mut token_handle: HANDLE = null_mut();
|
||||||
// 2600 => WindowsVersion::WindowsXP,
|
let mut luid = LUID::default();
|
||||||
// 6000 | 6001 | 6002 => WindowsVersion::WindowsVista,
|
OpenProcessToken(
|
||||||
7600 | 7601 => WindowsVersion::Windows7,
|
GetCurrentProcess(),
|
||||||
9200 | 9600 => WindowsVersion::Windows8,
|
TOKEN_ADJUST_PRIVILEGES,
|
||||||
10240 => WindowsVersion::Windows10Legacy,
|
&mut token_handle,
|
||||||
10586 => WindowsVersion::Windows10_2015,
|
);
|
||||||
14393 => WindowsVersion::Windows10_2016,
|
LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid);
|
||||||
15063 | 16299 => WindowsVersion::Windows10_2017,
|
let mut new_token_state = TOKEN_PRIVILEGES {
|
||||||
17134 | 17763 => WindowsVersion::Windows10_2018,
|
PrivilegeCount: 1,
|
||||||
18363 | 18362 => WindowsVersion::Windows10_2019,
|
Privileges: [LUID_AND_ATTRIBUTES {
|
||||||
19041 => WindowsVersion::Windows10_2020,
|
Luid: luid,
|
||||||
x if x >= 19536 => WindowsVersion::WindowsFastRing,
|
Attributes: SE_PRIVILEGE_ENABLED,
|
||||||
_ => WindowsVersion::WindowsUnknown
|
}],
|
||||||
};
|
};
|
||||||
|
AdjustTokenPrivileges(
|
||||||
Self {
|
token_handle,
|
||||||
version_info,
|
0,
|
||||||
short_version,
|
&mut new_token_state,
|
||||||
driver_handle: INVALID_HANDLE_VALUE,
|
16,
|
||||||
ntdll,
|
null_mut(),
|
||||||
nt_load_driver,
|
null_mut(),
|
||||||
nt_unload_driver,
|
);
|
||||||
rtl_init_unicode_str,
|
CloseHandle(token_handle);
|
||||||
rtl_get_version
|
}
|
||||||
}
|
|
||||||
}
|
rtl_get_version(&mut version_info);
|
||||||
|
|
||||||
pub fn driver_loaded(self) -> bool {
|
let short_version = match version_info.dwBuildNumber {
|
||||||
self.driver_handle != INVALID_HANDLE_VALUE
|
// 2600 => WindowsVersion::WindowsXP,
|
||||||
}
|
// 6000 | 6001 | 6002 => WindowsVersion::WindowsVista,
|
||||||
|
7600 | 7601 => WindowsVersion::Windows7,
|
||||||
pub fn load_driver(&mut self) -> NTSTATUS {
|
9200 | 9600 => WindowsVersion::Windows8,
|
||||||
// TODO: Move this to new()
|
10240 => WindowsVersion::Windows10Legacy,
|
||||||
// If we move this function to new(), self.driver_handle will be init, and thus no mut here
|
10586 => WindowsVersion::Windows10_2015,
|
||||||
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
14393 => WindowsVersion::Windows10_2016,
|
||||||
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
15063 | 16299 => WindowsVersion::Windows10_2017,
|
||||||
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16);
|
17134 | 17763 => WindowsVersion::Windows10_2018,
|
||||||
let status = (self.nt_load_driver)(&mut str_driver_reg_unicode);
|
18363 | 18362 => WindowsVersion::Windows10_2019,
|
||||||
|
19041 => WindowsVersion::Windows10_2020,
|
||||||
let filename = CString::new("\\\\.\\poolscanner").unwrap();
|
x if x >= 19536 => WindowsVersion::WindowsFastRing,
|
||||||
let driver_file_handle: HANDLE = unsafe {
|
_ => WindowsVersion::WindowsUnknown,
|
||||||
CreateFileA(filename.as_ptr(),
|
};
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
0, null_mut(), CREATE_ALWAYS,
|
Self {
|
||||||
FILE_ATTRIBUTE_NORMAL, null_mut())
|
version_info,
|
||||||
};
|
short_version,
|
||||||
|
driver_handle: INVALID_HANDLE_VALUE,
|
||||||
if driver_file_handle == INVALID_HANDLE_VALUE {
|
ntdll,
|
||||||
println!("Driver CreateFileA failed");
|
nt_load_driver,
|
||||||
}
|
nt_unload_driver,
|
||||||
else {
|
rtl_init_unicode_str,
|
||||||
self.driver_handle = driver_file_handle;
|
rtl_get_version,
|
||||||
}
|
}
|
||||||
status
|
}
|
||||||
}
|
|
||||||
|
pub fn driver_loaded(self) -> bool {
|
||||||
pub fn unload_driver(&self) -> NTSTATUS {
|
self.driver_handle != INVALID_HANDLE_VALUE
|
||||||
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
}
|
||||||
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
|
||||||
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr());
|
pub fn load_driver(&mut self) -> NTSTATUS {
|
||||||
(self.nt_unload_driver)(&mut str_driver_reg_unicode)
|
// TODO: Move this to new()
|
||||||
}
|
// If we move this function to new(), self.driver_handle will be init, and thus no mut here
|
||||||
|
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
||||||
#[allow(dead_code)]
|
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
||||||
pub fn get_build_number(&self) -> DWORD {
|
(self.rtl_init_unicode_str)(
|
||||||
self.version_info.dwBuildNumber
|
&mut str_driver_reg_unicode,
|
||||||
}
|
str_driver_reg.as_ptr() as *const u16,
|
||||||
|
);
|
||||||
#[allow(dead_code)]
|
let status = (self.nt_load_driver)(&mut str_driver_reg_unicode);
|
||||||
pub fn print_version(&self) {
|
|
||||||
println!("Windows version: {}.{}.{} {:?}",
|
let filename = CString::new("\\\\.\\poolscanner").unwrap();
|
||||||
self.version_info.dwMajorVersion,
|
let driver_file_handle: HANDLE = unsafe {
|
||||||
self.version_info.dwMinorVersion,
|
CreateFileA(
|
||||||
self.version_info.dwBuildNumber,
|
filename.as_ptr(),
|
||||||
self.short_version
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
);
|
0,
|
||||||
}
|
null_mut(),
|
||||||
|
CREATE_ALWAYS,
|
||||||
pub fn to_epoch(&self, filetime: u64) -> u64 {
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
let windows_epoch_diff = 11644473600000 * 10000;
|
null_mut(),
|
||||||
if filetime < windows_epoch_diff {
|
)
|
||||||
return 0;
|
};
|
||||||
}
|
|
||||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
if driver_file_handle == INVALID_HANDLE_VALUE {
|
||||||
process_time_epoch
|
println!("Driver CreateFileA failed");
|
||||||
}
|
} else {
|
||||||
|
self.driver_handle = driver_file_handle;
|
||||||
pub fn valid_process_time(&self, filetime: u64) -> bool {
|
}
|
||||||
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
status
|
||||||
let windows_epoch_diff = 11644473600000 * 10000;
|
}
|
||||||
if filetime < windows_epoch_diff {
|
|
||||||
return false;
|
pub fn unload_driver(&self) -> NTSTATUS {
|
||||||
}
|
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
||||||
let system_up_time_ms = unsafe { GetTickCount64() };
|
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
||||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond
|
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr());
|
||||||
let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
(self.nt_unload_driver)(&mut str_driver_reg_unicode)
|
||||||
let system_start_up_time_ms =
|
}
|
||||||
now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */);
|
|
||||||
|
#[allow(dead_code)]
|
||||||
if process_time_epoch < system_start_up_time_ms {
|
pub fn get_build_number(&self) -> DWORD {
|
||||||
false
|
self.version_info.dwBuildNumber
|
||||||
} else if process_time_epoch > now_ms {
|
}
|
||||||
false
|
|
||||||
} else {
|
#[allow(dead_code)]
|
||||||
true
|
pub fn print_version(&self) {
|
||||||
}
|
println!(
|
||||||
}
|
"Windows version: {}.{}.{} {:?}",
|
||||||
|
self.version_info.dwMajorVersion,
|
||||||
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD {
|
self.version_info.dwMinorVersion,
|
||||||
self.device_io_raw(code,
|
self.version_info.dwBuildNumber,
|
||||||
inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD,
|
self.short_version
|
||||||
outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn device_io_raw(&self, code: DWORD,
|
pub fn to_epoch(&self, filetime: u64) -> u64 {
|
||||||
input_ptr: *mut c_void, input_len: DWORD,
|
let windows_epoch_diff = 11644473600000 * 10000;
|
||||||
output_ptr: *mut c_void, output_len: DWORD) -> DWORD {
|
if filetime < windows_epoch_diff {
|
||||||
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
|
return 0;
|
||||||
let mut bytes_returned: DWORD = 0;
|
}
|
||||||
unsafe {
|
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
||||||
let status = DeviceIoControl(self.driver_handle, code,
|
process_time_epoch
|
||||||
input_ptr, input_len,
|
}
|
||||||
output_ptr, output_len,
|
|
||||||
&mut bytes_returned, null_mut());
|
pub fn valid_process_time(&self, filetime: u64) -> bool {
|
||||||
if status == 0 {
|
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
||||||
println!("device io failed: last error {}", GetLastError());
|
let windows_epoch_diff = 11644473600000 * 10000;
|
||||||
}
|
if filetime < windows_epoch_diff {
|
||||||
};
|
return false;
|
||||||
bytes_returned
|
}
|
||||||
}
|
let system_up_time_ms = unsafe { GetTickCount64() };
|
||||||
}
|
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond
|
||||||
|
let now_ms = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("Time went backwards")
|
||||||
|
.as_millis() as u64;
|
||||||
|
let system_start_up_time_ms =
|
||||||
|
now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */);
|
||||||
|
|
||||||
|
if process_time_epoch < system_start_up_time_ms {
|
||||||
|
false
|
||||||
|
} else if process_time_epoch > now_ms {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD {
|
||||||
|
self.device_io_raw(
|
||||||
|
code,
|
||||||
|
inbuf as *mut _ as *mut c_void,
|
||||||
|
size_of_val(inbuf) as DWORD,
|
||||||
|
outbuf as *mut _ as *mut c_void,
|
||||||
|
size_of_val(outbuf) as DWORD,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_io_raw(
|
||||||
|
&self,
|
||||||
|
code: DWORD,
|
||||||
|
input_ptr: *mut c_void,
|
||||||
|
input_len: DWORD,
|
||||||
|
output_ptr: *mut c_void,
|
||||||
|
output_len: DWORD,
|
||||||
|
) -> DWORD {
|
||||||
|
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
|
||||||
|
let mut bytes_returned: DWORD = 0;
|
||||||
|
unsafe {
|
||||||
|
let status = DeviceIoControl(
|
||||||
|
self.driver_handle,
|
||||||
|
code,
|
||||||
|
input_ptr,
|
||||||
|
input_len,
|
||||||
|
output_ptr,
|
||||||
|
output_len,
|
||||||
|
&mut bytes_returned,
|
||||||
|
null_mut(),
|
||||||
|
);
|
||||||
|
if status == 0 {
|
||||||
|
println!("device io failed: last error {}", GetLastError());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bytes_returned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user