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:
nganhkhoa 2020-06-22 22:30:35 +07:00
parent 5619048a4a
commit 0350ec46d9
4 changed files with 67 additions and 4 deletions

View File

@ -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());
} }

View File

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

View File

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

View File

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