Scan unloaded module/driver
By reversing MmLocateUnloadedDriver, we can know the algorithm to extract name/start/end of unloaded drivers
This commit is contained in:
parent
5619048a4a
commit
0350ec46d9
@ -2,16 +2,22 @@ use std::error::Error;
|
|||||||
|
|
||||||
use lpus::{
|
use lpus::{
|
||||||
driver_state::{DriverState},
|
driver_state::{DriverState},
|
||||||
traverse_loadedmodulelist
|
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();
|
||||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||||
|
|
||||||
let result = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new());
|
let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new());
|
||||||
|
let unloaded = traverse_unloadeddrivers(&driver).unwrap_or(Vec::new());
|
||||||
|
|
||||||
for r in result.iter() {
|
for r in loaded.iter() {
|
||||||
|
println!("{:#}", r.to_string());
|
||||||
|
}
|
||||||
|
println!("=============================================");
|
||||||
|
for r in unloaded.iter() {
|
||||||
println!("{:#}", r.to_string());
|
println!("{:#}", r.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
src/lib.rs
37
src/lib.rs
@ -528,3 +528,40 @@ pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = Vec::new();
|
||||||
|
let ntosbase = driver.get_kernel_base();
|
||||||
|
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 unload_array = driver.deref_addr_new::<u64>(unload_array_ptr.address());
|
||||||
|
if unload_array == 0 {
|
||||||
|
return Err("The unload driver list is null".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// by reversing MmLocateUnloadedDriver
|
||||||
|
let num_unload = driver.deref_addr_new::<u32>(num_unload_ptr.address()) as u64;
|
||||||
|
let bound =
|
||||||
|
if num_unload > 0x32 { 0x32 }
|
||||||
|
else { num_unload };
|
||||||
|
let drivers = (0..bound).map(|i| Address::from_base(unload_array + (i * 0x28)));
|
||||||
|
|
||||||
|
for driver_addr in drivers {
|
||||||
|
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 end_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.EndAddress")?;
|
||||||
|
let current_time: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.CurrentTime")?;
|
||||||
|
|
||||||
|
result.push(json!({
|
||||||
|
"address": format!("0x{:x}", driver_addr.address()),
|
||||||
|
"type": "_UNLOADED_DRIVERS",
|
||||||
|
"name": name,
|
||||||
|
"start_addr": format!("0x{:x}", start_addr),
|
||||||
|
"end_addr": format!("0x{:x}", end_addr),
|
||||||
|
"current_time": driver.windows_ffi.to_epoch(current_time)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
@ -422,7 +422,7 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
|
|||||||
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() {
|
||||||
TypeData::FieldList(list) => {
|
TypeData::FieldList(list) => {
|
||||||
for field in list.fields {
|
for field in list.fields {
|
||||||
@ -441,6 +441,17 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// https://github.com/Zer0Mem0ry/ntoskrnl/blob/master/Include/mm.h#L1107
|
||||||
|
let mut unload_driver_member = HashMap::new();
|
||||||
|
unload_driver_member.insert("struct_size".to_string(), ("U32".to_string(), 0x30));
|
||||||
|
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("EndAddress".to_string(), ("PVOID".to_string(), 0x18));
|
||||||
|
unload_driver_member.insert("CurrentTime".to_string(), ("_LARGE_INTEGER".to_string(), 0x20));
|
||||||
|
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
|
||||||
|
@ -212,6 +212,15 @@ impl WindowsFFI {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_epoch(&self, filetime: u64) -> u64 {
|
||||||
|
let windows_epoch_diff = 11644473600000 * 10000;
|
||||||
|
if filetime < windows_epoch_diff {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
||||||
|
process_time_epoch
|
||||||
|
}
|
||||||
|
|
||||||
pub fn valid_process_time(&self, filetime: u64) -> bool {
|
pub fn valid_process_time(&self, filetime: u64) -> bool {
|
||||||
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
||||||
let windows_epoch_diff = 11644473600000 * 10000;
|
let windows_epoch_diff = 11644473600000 * 10000;
|
||||||
|
Loading…
Reference in New Issue
Block a user