533 lines
21 KiB
Rust
533 lines
21 KiB
Rust
extern crate chrono;
|
|
extern crate app_dirs;
|
|
|
|
pub mod pdb_store;
|
|
pub mod windows;
|
|
pub mod ioctl_protocol;
|
|
pub mod driver_state;
|
|
pub mod address;
|
|
pub mod object;
|
|
|
|
use std::error::Error;
|
|
use chrono::{DateTime, TimeZone, Local};
|
|
use serde_json::{json, Value};
|
|
|
|
use driver_state::DriverState;
|
|
use address::Address;
|
|
use object::*;
|
|
|
|
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
|
|
|
pub fn to_epoch(filetime: u64) -> DateTime<Local> {
|
|
// return seconds from epoch
|
|
let windows_epoch_diff = 11_644_473_600_000 * 10_000;
|
|
if filetime < windows_epoch_diff {
|
|
return Local.timestamp(0, 0);
|
|
}
|
|
let filetime_epoch = (filetime - windows_epoch_diff) / 10_000_000;
|
|
Local.timestamp(filetime_epoch as i64, 0)
|
|
}
|
|
|
|
pub fn get_irp_name(idx: usize) -> String {
|
|
let irp_names = vec![
|
|
"IRP_MJ_CREATE",
|
|
"IRP_MJ_CREATE_NAMED_PIPE",
|
|
"IRP_MJ_CLOSE",
|
|
"IRP_MJ_READ",
|
|
"IRP_MJ_WRITE",
|
|
"IRP_MJ_QUERY_INFORMATION",
|
|
"IRP_MJ_SET_INFORMATION",
|
|
"IRP_MJ_QUERY_EA",
|
|
"IRP_MJ_SET_EA",
|
|
"IRP_MJ_FLUSH_BUFFERS",
|
|
"IRP_MJ_QUERY_VOLUME_INFORMATION",
|
|
"IRP_MJ_SET_VOLUME_INFORMATION",
|
|
"IRP_MJ_DIRECTORY_CONTROL",
|
|
"IRP_MJ_FILE_SYSTEM_CONTROL",
|
|
"IRP_MJ_DEVICE_CONTROL",
|
|
"IRP_MJ_INTERNAL_DEVICE_CONTROL",
|
|
"IRP_MJ_SHUTDOWN",
|
|
"IRP_MJ_LOCK_CONTROL",
|
|
"IRP_MJ_CLEANUP",
|
|
"IRP_MJ_CREATE_MAILSLOT",
|
|
"IRP_MJ_QUERY_SECURITY",
|
|
"IRP_MJ_SET_SECURITY",
|
|
"IRP_MJ_POWER",
|
|
"IRP_MJ_SYSTEM_CONTROL",
|
|
"IRP_MJ_DEVICE_CHANGE",
|
|
"IRP_MJ_QUERY_QUOTA",
|
|
"IRP_MJ_SET_QUOTA",
|
|
"IRP_MJ_PNP"
|
|
].iter().map(|x| x.to_string()).collect::<Vec<String>>();
|
|
|
|
if let Some(name) = irp_names.get(idx) {
|
|
name.clone()
|
|
}
|
|
else {
|
|
"UNKNOWN".to_string()
|
|
}
|
|
}
|
|
|
|
fn get_device_type(typ: u32) -> String {
|
|
match typ {
|
|
0x00000027 => "FILE_DEVICE_8042_PORT",
|
|
0x00000032 => "FILE_DEVICE_ACPI",
|
|
0x00000029 => "FILE_DEVICE_BATTERY",
|
|
0x00000001 => "FILE_DEVICE_BEEP",
|
|
0x0000002a => "FILE_DEVICE_BUS_EXTENDER",
|
|
0x00000002 => "FILE_DEVICE_CD_ROM",
|
|
0x00000003 => "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
|
|
0x00000030 => "FILE_DEVICE_CHANGER",
|
|
0x00000004 => "FILE_DEVICE_CONTROLLER",
|
|
0x00000005 => "FILE_DEVICE_DATALINK",
|
|
0x00000006 => "FILE_DEVICE_DFS",
|
|
0x00000035 => "FILE_DEVICE_DFS_FILE_SYSTEM",
|
|
0x00000036 => "FILE_DEVICE_DFS_VOLUME",
|
|
0x00000007 => "FILE_DEVICE_DISK",
|
|
0x00000008 => "FILE_DEVICE_DISK_FILE_SYSTEM",
|
|
0x00000033 => "FILE_DEVICE_DVD",
|
|
0x00000009 => "FILE_DEVICE_FILE_SYSTEM",
|
|
0x0000003a => "FILE_DEVICE_FIPS",
|
|
0x00000034 => "FILE_DEVICE_FULLSCREEN_VIDEO",
|
|
0x0000000a => "FILE_DEVICE_INPORT_PORT",
|
|
0x0000000b => "FILE_DEVICE_KEYBOARD",
|
|
0x0000002f => "FILE_DEVICE_KS",
|
|
0x00000039 => "FILE_DEVICE_KSEC",
|
|
0x0000000c => "FILE_DEVICE_MAILSLOT",
|
|
0x0000002d => "FILE_DEVICE_MASS_STORAGE",
|
|
0x0000000d => "FILE_DEVICE_MIDI_IN",
|
|
0x0000000e => "FILE_DEVICE_MIDI_OUT",
|
|
0x0000002b => "FILE_DEVICE_MODEM",
|
|
0x0000000f => "FILE_DEVICE_MOUSE",
|
|
0x00000010 => "FILE_DEVICE_MULTI_UNC_PROVIDER",
|
|
0x00000011 => "FILE_DEVICE_NAMED_PIPE",
|
|
0x00000012 => "FILE_DEVICE_NETWORK",
|
|
0x00000013 => "FILE_DEVICE_NETWORK_BROWSER",
|
|
0x00000014 => "FILE_DEVICE_NETWORK_FILE_SYSTEM",
|
|
0x00000028 => "FILE_DEVICE_NETWORK_REDIRECTOR",
|
|
0x00000015 => "FILE_DEVICE_NULL",
|
|
0x00000016 => "FILE_DEVICE_PARALLEL_PORT",
|
|
0x00000017 => "FILE_DEVICE_PHYSICAL_NETCARD",
|
|
0x00000018 => "FILE_DEVICE_PRINTER",
|
|
0x00000019 => "FILE_DEVICE_SCANNER",
|
|
0x0000001c => "FILE_DEVICE_SCREEN",
|
|
0x00000037 => "FILE_DEVICE_SERENUM",
|
|
0x0000001a => "FILE_DEVICE_SERIAL_MOUSE_PORT",
|
|
0x0000001b => "FILE_DEVICE_SERIAL_PORT",
|
|
0x00000031 => "FILE_DEVICE_SMARTCARD",
|
|
0x0000002e => "FILE_DEVICE_SMB",
|
|
0x0000001d => "FILE_DEVICE_SOUND",
|
|
0x0000001e => "FILE_DEVICE_STREAMS",
|
|
0x0000001f => "FILE_DEVICE_TAPE",
|
|
0x00000020 => "FILE_DEVICE_TAPE_FILE_SYSTEM",
|
|
0x00000038 => "FILE_DEVICE_TERMSRV",
|
|
0x00000021 => "FILE_DEVICE_TRANSPORT",
|
|
0x00000022 => "FILE_DEVICE_UNKNOWN",
|
|
0x0000002c => "FILE_DEVICE_VDM",
|
|
0x00000023 => "FILE_DEVICE_VIDEO",
|
|
0x00000024 => "FILE_DEVICE_VIRTUAL_DISK",
|
|
0x00000025 => "FILE_DEVICE_WAVE_IN",
|
|
0x00000026 => "FILE_DEVICE_WAVE_OUT",
|
|
_ => "UNKNOWN"
|
|
}.to_string()
|
|
}
|
|
|
|
pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
let tag =
|
|
if driver.use_old_tag() { b"Pro\xe3" }
|
|
else { b"Proc" };
|
|
driver.scan_pool(tag, "_EPROCESS", |pool_addr, header, data_addr| {
|
|
let chunk_size = (header[2] as u64) * 16u64;
|
|
|
|
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
|
|
|
let eprocess_valid_start = &data_addr;
|
|
let eprocess_valid_end = (pool_addr.clone() + chunk_size) - eprocess_size;
|
|
let mut try_eprocess_ptr = eprocess_valid_start.clone();
|
|
|
|
while try_eprocess_ptr <= eprocess_valid_end {
|
|
let create_time: u64 = driver.decompose(&try_eprocess_ptr, "_EPROCESS.CreateTime")?;
|
|
if driver.windows_ffi.valid_process_time(create_time) {
|
|
break;
|
|
}
|
|
try_eprocess_ptr += 0x4; // search exhaustively
|
|
}
|
|
if try_eprocess_ptr > eprocess_valid_end {
|
|
return Ok(false);
|
|
}
|
|
|
|
result.push(make_eprocess(driver, &try_eprocess_ptr)?);
|
|
Ok(true)
|
|
})?;
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
let tag =
|
|
if driver.use_old_tag() { b"Fil\xe5" }
|
|
else { b"File" };
|
|
driver.scan_pool(tag, "_FILE_OBJECT", |pool_addr, header, data_addr| {
|
|
let chunk_size = (header[2] as u64) * 16u64;
|
|
|
|
let fob_size = driver.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
|
let valid_end = (pool_addr.clone() + chunk_size) - fob_size;
|
|
let mut try_ptr = data_addr;
|
|
|
|
while try_ptr <= valid_end {
|
|
let ftype: u16 = driver.decompose(&try_ptr, "_FILE_OBJECT.Type")?;
|
|
let size: u16 = driver.decompose(&try_ptr, "_FILE_OBJECT.Size")?;
|
|
if (size as u64) == fob_size && ftype == 5u16 {
|
|
break;
|
|
}
|
|
try_ptr += 0x4; // search exhaustively
|
|
}
|
|
if try_ptr > valid_end {
|
|
return Ok(false);
|
|
}
|
|
|
|
let fob_addr = &try_ptr;
|
|
let read_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.ReadAccess")?;
|
|
let write_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.WriteAccess")?;
|
|
let delete_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.DeleteAccess")?;
|
|
let share_read_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedRead")?;
|
|
let share_write_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedWrite")?;
|
|
let share_delete_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedDelete")?;
|
|
let filename_ptr = driver.address_of(fob_addr, "_FILE_OBJECT.FileName")?;
|
|
let devicename_ptr: u64 = driver.address_of(fob_addr, "_FILE_OBJECT.DeviceObject.DriverObject.DriverName")?;
|
|
let hardware_ptr: u64 = driver.decompose(fob_addr, "_FILE_OBJECT.DeviceObject.DriverObject.HardwareDatabase")?;
|
|
|
|
let filename =
|
|
if read_ok == 0 {
|
|
"[NOT READABLE]".to_string()
|
|
}
|
|
else if let Ok(n) = driver.get_unicode_string(filename_ptr) {
|
|
n
|
|
}
|
|
else {
|
|
"[NOT A VALID _UNICODE_STRING]".to_string()
|
|
};
|
|
let devicename = driver.get_unicode_string(devicename_ptr)
|
|
.unwrap_or("".to_string());
|
|
let hardware = driver.get_unicode_string(hardware_ptr)
|
|
.unwrap_or("".to_string());
|
|
result.push(json!({
|
|
"pool": format!("0x{:x}", pool_addr.address()),
|
|
"address": format!("0x{:x}", fob_addr.address()),
|
|
"type": "_FILE_OBJECT",
|
|
"path": filename,
|
|
"device": devicename,
|
|
"hardware": hardware,
|
|
"access": {
|
|
"r": read_ok == 1,
|
|
"w": write_ok == 1,
|
|
"d": delete_ok == 1,
|
|
"R": share_read_ok == 1,
|
|
"W": share_write_ok == 1,
|
|
"D": share_delete_ok == 1
|
|
}
|
|
}));
|
|
Ok(true)
|
|
})?;
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
let tag =
|
|
if driver.use_old_tag() { b"Thr\xe5" }
|
|
else { b"Thre" };
|
|
driver.scan_pool(tag, "_ETHREAD", |pool_addr, header, data_addr| {
|
|
let chunk_size = (header[2] as u64) * 16u64;
|
|
|
|
let object_header_size = driver.pdb_store.get_offset_r("_OBJECT_HEADER.struct_size")?;
|
|
let header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
|
let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?;
|
|
let ethread_valid_start = &data_addr;
|
|
let ethread_valid_end = (pool_addr.clone() + chunk_size) - ethread_size;
|
|
let mut try_ethread_ptr = ethread_valid_start.clone();
|
|
|
|
if chunk_size == header_size + object_header_size + ethread_size {
|
|
try_ethread_ptr = ethread_valid_end.clone();
|
|
}
|
|
else {
|
|
while try_ethread_ptr <= ethread_valid_end {
|
|
let create_time: u64 = driver.decompose(&try_ethread_ptr, "_ETHREAD.CreateTime")?;
|
|
if driver.windows_ffi.valid_process_time(create_time) {
|
|
break;
|
|
}
|
|
try_ethread_ptr += 0x4; // search exhaustively
|
|
}
|
|
if try_ethread_ptr > ethread_valid_end {
|
|
return Ok(false);
|
|
}
|
|
}
|
|
|
|
result.push(make_ethread(driver, &try_ethread_ptr)?);
|
|
Ok(true)
|
|
})?;
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
// Unstable, do not use
|
|
// pub fn scan_mutant(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
// let mut result: Vec<Value> = Vec::new();
|
|
//
|
|
// let ntosbase = driver.get_kernel_base();
|
|
// let [start, end] = driver.get_nonpaged_range(&ntosbase)?;
|
|
//
|
|
// let tag =
|
|
// if driver.use_old_tag() { b"Mut\xe1" }
|
|
// else { b"Muta" };
|
|
// driver.scan_pool(tag, "_KMUTANT", |pool_addr, header, data_addr| {
|
|
// let chunk_size = (header[2] as u64) * 16u64;
|
|
//
|
|
// let kmutant_size = driver.pdb_store.get_offset_r("_KMUTANT.struct_size")?;
|
|
//
|
|
// let kmutant_valid_start = data_addr;
|
|
// let kmutant_valid_end = (pool_addr.clone() + chunk_size) - kmutant_size;
|
|
// let mut try_kmutant_ptr = kmutant_valid_start.clone();
|
|
//
|
|
// while try_kmutant_ptr <= kmutant_valid_end {
|
|
// // TODO: Stronger constrain
|
|
// let kthread_ptr = driver.address_of(&try_kmutant_ptr, "_KMUTANT.OwnerThread")?;
|
|
// if kthread_ptr > start.address() && kthread_ptr < end.address() {
|
|
// break;
|
|
// }
|
|
// try_kmutant_ptr += 0x4; // search exhaustively
|
|
// }
|
|
// if try_kmutant_ptr > kmutant_valid_end {
|
|
// return Ok(false);
|
|
// }
|
|
//
|
|
// let kmutant_ptr = try_kmutant_ptr;
|
|
// let ethread_ptr = Address::from_base(driver.address_of(&kmutant_ptr, "_KMUTANT.OwnerThread")?);
|
|
//
|
|
// let pid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
|
|
// let tid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueThread")?;
|
|
// let unicode_str_ptr: u64 = driver.address_of(ðread_ptr, "_ETHREAD.ThreadName")?;
|
|
//
|
|
// let thread_name =
|
|
// if let Ok(name) = driver.get_unicode_string(unicode_str_ptr) {
|
|
// name
|
|
// }
|
|
// else {
|
|
// "".to_string()
|
|
// };
|
|
//
|
|
// result.push(json!({
|
|
// "pool": format!("0x{:x}", pool_addr.address()),
|
|
// "address": format!("0x{:x}", ethread_ptr.address()),
|
|
// "type": "_KMUTANT",
|
|
// "pid": pid,
|
|
// "tid": tid,
|
|
// "name": thread_name
|
|
// }));
|
|
// Ok(true)
|
|
// })?;
|
|
//
|
|
// Ok(result)
|
|
// }
|
|
|
|
pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
let tag =
|
|
if driver.use_old_tag() { b"Dri\xf6" }
|
|
else { b"Driv" };
|
|
driver.scan_pool(tag, "_DRIVER_OBJECT", |pool_addr, header, data_addr| {
|
|
let chunk_size = (header[2] as u64) * 16u64;
|
|
|
|
let dob_size = driver.pdb_store.get_offset_r("_DRIVER_OBJECT.struct_size")?;
|
|
let valid_end = (pool_addr.clone() + chunk_size) - dob_size;
|
|
let mut try_ptr = data_addr;
|
|
|
|
while try_ptr <= valid_end {
|
|
// No documentation on type constrain
|
|
let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?;
|
|
if (size as u64) == dob_size /* && ftype == 5u16 */ {
|
|
break;
|
|
}
|
|
try_ptr += 0x4; // search exhaustively
|
|
}
|
|
if try_ptr > valid_end {
|
|
return Ok(false);
|
|
}
|
|
result.push(make_driver(driver, &try_ptr)?);
|
|
Ok(true)
|
|
})?;
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
driver.scan_pool(b"MmLd", "_LDR_DATA_TABLE_ENTRY", |_pool_addr, _, data_addr| {
|
|
// By reversing, this structure does not have any header
|
|
result.push(make_ldr(driver, &data_addr)?);
|
|
Ok(true)
|
|
})?;
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
|
|
let ntosbase = driver.get_kernel_base();
|
|
let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?;
|
|
|
|
let result =
|
|
make_list_entry(driver, module_list_head.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")?
|
|
.iter().map(|x| make_ldr(driver, &x).unwrap_or(json!({}))).collect();
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(nt!PsActiveProcessHead), "nt!_EPROCESS", "ActiveProcessLinks")
|
|
pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
let ntosbase = driver.get_kernel_base();
|
|
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
|
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
|
|
|
// TODO: make_list_entry
|
|
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
|
while ptr != process_list_head.address() {
|
|
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
|
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
|
ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?;
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
// TODO: where is afd!
|
|
// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(afd!AfdEndpointListHead), "nt!_EPROCESS", "ActiveProcessLinks")
|
|
// pub fn traverse_afdendpoint(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
// let mut result: Vec<Value> = Vec::new();
|
|
//
|
|
// let ntosbase = driver.get_kernel_base();
|
|
// let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
|
// let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
|
//
|
|
// let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
|
// while ptr != process_list_head.address() {
|
|
// let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
|
//
|
|
// let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
|
// let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
|
// let image_name: Vec<u8> = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?;
|
|
// let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?;
|
|
//
|
|
// let eprocess_name =
|
|
// if let Ok(name) = from_utf8(&image_name) {
|
|
// name.to_string().trim_end_matches(char::from(0)).to_string()
|
|
// } else {
|
|
// "".to_string()
|
|
// };
|
|
// let binary_path = driver.get_unicode_string(unicode_str_ptr)
|
|
// .unwrap_or("".to_string());
|
|
//
|
|
// result.push(json!({
|
|
// "address": format!("0x{:x}", &eprocess_ptr.address()),
|
|
// "type": "_EPROCESS",
|
|
// "pid": pid,
|
|
// "ppid": ppid,
|
|
// "name": eprocess_name,
|
|
// "path": binary_path
|
|
// }));
|
|
//
|
|
// ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?;
|
|
// }
|
|
//
|
|
// Ok(result)
|
|
// }
|
|
|
|
// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(nt!KiProcessListHead), "nt!_KPROCESS", "ProcessListEntry").Select( p => new {Process = (nt!_EPROCESS*)&p )
|
|
pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
let ntosbase = driver.get_kernel_base();
|
|
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?;
|
|
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_KPROCESS.ProcessListEntry")?;
|
|
|
|
// TODO: make_list_entry
|
|
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
|
while ptr != process_list_head.address() {
|
|
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
|
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
|
|
|
ptr = driver.decompose(&eprocess_ptr, "_KPROCESS.ProcessListEntry.Flink")?;
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
// dx Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead, "nt!_HANDLE_TABLE", "HandleTableList").Where(h => h.QuotaProcess != 0).Select( qp => new {Process= qp.QuotaProcess} )
|
|
pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|
let mut result: Vec<Value> = Vec::new();
|
|
|
|
let ntosbase = driver.get_kernel_base();
|
|
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("HandleTableListHead")?;
|
|
let handle_list_offset = driver.pdb_store.get_offset_r("_HANDLE_TABLE.HandleTableList")?;
|
|
|
|
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
|
while ptr != process_list_head.address() {
|
|
let handle_ptr = Address::from_base(ptr - handle_list_offset);
|
|
let quota_process: u64 = driver.decompose(&handle_ptr, "_HANDLE_TABLE.QuotaProcess")?;
|
|
|
|
if quota_process != 0 {
|
|
let eprocess_ptr = Address::from_base(quota_process);
|
|
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
|
}
|
|
|
|
ptr = driver.decompose(&handle_ptr, "_HANDLE_TABLE.HandleTableList.Flink")?;
|
|
}
|
|
|
|
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)
|
|
}
|