Create object in object.rs
This commit is contained in:
parent
4e67e10aee
commit
b1c3107c74
7
other/to_epoch.py
Normal file
7
other/to_epoch.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
windows_epoch_diff = 11644473600000 * 10000
|
||||||
|
filetime = 132380977838542980
|
||||||
|
|
||||||
|
process_time_epoch = (filetime - windows_epoch_diff) // 10000
|
||||||
|
print(process_time_epoch)
|
||||||
|
|
381
src/lib.rs
381
src/lib.rs
@ -6,15 +6,28 @@ pub mod windows;
|
|||||||
pub mod ioctl_protocol;
|
pub mod ioctl_protocol;
|
||||||
pub mod driver_state;
|
pub mod driver_state;
|
||||||
pub mod address;
|
pub mod address;
|
||||||
|
pub mod object;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::str::{from_utf8};
|
use chrono::{DateTime, TimeZone, Local};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use driver_state::DriverState;
|
use driver_state::DriverState;
|
||||||
use address::Address;
|
use address::Address;
|
||||||
|
use object::*;
|
||||||
|
|
||||||
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
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 {
|
pub fn get_irp_name(idx: usize) -> String {
|
||||||
let irp_names = vec![
|
let irp_names = vec![
|
||||||
"IRP_MJ_CREATE",
|
"IRP_MJ_CREATE",
|
||||||
@ -144,31 +157,7 @@ pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let eprocess_ptr = &try_eprocess_ptr;
|
result.push(make_eprocess(driver, &try_eprocess_ptr)?);
|
||||||
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")
|
|
||||||
.unwrap_or(0); // ImageFilePointer is after Windows 10 Anniversary
|
|
||||||
|
|
||||||
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!({
|
|
||||||
"pool": format!("0x{:x}", pool_addr.address()),
|
|
||||||
"address": format!("0x{:x}", eprocess_ptr.address()),
|
|
||||||
"type": "_EPROCESS",
|
|
||||||
"pid": pid,
|
|
||||||
"ppid": ppid,
|
|
||||||
"name": eprocess_name,
|
|
||||||
"path": binary_path
|
|
||||||
}));
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
})?;
|
})?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@ -278,29 +267,7 @@ pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ethread_ptr = &try_ethread_ptr;
|
result.push(make_ethread(driver, &try_ethread_ptr)?);
|
||||||
|
|
||||||
let pid: u64 = driver.decompose(ethread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
|
|
||||||
let tid: u64 = driver.decompose(ethread_ptr, "_ETHREAD.Cid.UniqueThread")?;
|
|
||||||
let unicode_str_ptr: u64 = driver.address_of(ethread_ptr, "_ETHREAD.ThreadName")
|
|
||||||
.unwrap_or(0); // ThreadName is after Windows 10 Anniversary
|
|
||||||
|
|
||||||
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": "_ETHREAD",
|
|
||||||
"pid": pid,
|
|
||||||
"tid": tid,
|
|
||||||
"name": thread_name
|
|
||||||
}));
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -308,64 +275,64 @@ pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unstable, do not use
|
// Unstable, do not use
|
||||||
pub fn scan_mutant(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
// pub fn scan_mutant(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
let mut result: Vec<Value> = Vec::new();
|
// let mut result: Vec<Value> = Vec::new();
|
||||||
|
//
|
||||||
let ntosbase = driver.get_kernel_base();
|
// let ntosbase = driver.get_kernel_base();
|
||||||
let [start, end] = driver.get_nonpaged_range(&ntosbase)?;
|
// let [start, end] = driver.get_nonpaged_range(&ntosbase)?;
|
||||||
|
//
|
||||||
let tag =
|
// let tag =
|
||||||
if driver.use_old_tag() { b"Mut\xe1" }
|
// if driver.use_old_tag() { b"Mut\xe1" }
|
||||||
else { b"Muta" };
|
// else { b"Muta" };
|
||||||
driver.scan_pool(tag, "_KMUTANT", |pool_addr, header, data_addr| {
|
// driver.scan_pool(tag, "_KMUTANT", |pool_addr, header, data_addr| {
|
||||||
let chunk_size = (header[2] as u64) * 16u64;
|
// let chunk_size = (header[2] as u64) * 16u64;
|
||||||
|
//
|
||||||
let kmutant_size = driver.pdb_store.get_offset_r("_KMUTANT.struct_size")?;
|
// let kmutant_size = driver.pdb_store.get_offset_r("_KMUTANT.struct_size")?;
|
||||||
|
//
|
||||||
let kmutant_valid_start = data_addr;
|
// let kmutant_valid_start = data_addr;
|
||||||
let kmutant_valid_end = (pool_addr.clone() + chunk_size) - kmutant_size;
|
// let kmutant_valid_end = (pool_addr.clone() + chunk_size) - kmutant_size;
|
||||||
let mut try_kmutant_ptr = kmutant_valid_start.clone();
|
// let mut try_kmutant_ptr = kmutant_valid_start.clone();
|
||||||
|
//
|
||||||
while try_kmutant_ptr <= kmutant_valid_end {
|
// while try_kmutant_ptr <= kmutant_valid_end {
|
||||||
// TODO: Stronger constrain
|
// // TODO: Stronger constrain
|
||||||
let kthread_ptr = driver.address_of(&try_kmutant_ptr, "_KMUTANT.OwnerThread")?;
|
// let kthread_ptr = driver.address_of(&try_kmutant_ptr, "_KMUTANT.OwnerThread")?;
|
||||||
if kthread_ptr > start.address() && kthread_ptr < end.address() {
|
// if kthread_ptr > start.address() && kthread_ptr < end.address() {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
try_kmutant_ptr += 0x4; // search exhaustively
|
// try_kmutant_ptr += 0x4; // search exhaustively
|
||||||
}
|
// }
|
||||||
if try_kmutant_ptr > kmutant_valid_end {
|
// if try_kmutant_ptr > kmutant_valid_end {
|
||||||
return Ok(false);
|
// return Ok(false);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
let kmutant_ptr = try_kmutant_ptr;
|
// let kmutant_ptr = try_kmutant_ptr;
|
||||||
let ethread_ptr = Address::from_base(driver.address_of(&kmutant_ptr, "_KMUTANT.OwnerThread")?);
|
// let ethread_ptr = Address::from_base(driver.address_of(&kmutant_ptr, "_KMUTANT.OwnerThread")?);
|
||||||
|
//
|
||||||
let pid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
|
// let pid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
|
||||||
let tid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueThread")?;
|
// let tid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueThread")?;
|
||||||
let unicode_str_ptr: u64 = driver.address_of(ðread_ptr, "_ETHREAD.ThreadName")?;
|
// let unicode_str_ptr: u64 = driver.address_of(ðread_ptr, "_ETHREAD.ThreadName")?;
|
||||||
|
//
|
||||||
let thread_name =
|
// let thread_name =
|
||||||
if let Ok(name) = driver.get_unicode_string(unicode_str_ptr) {
|
// if let Ok(name) = driver.get_unicode_string(unicode_str_ptr) {
|
||||||
name
|
// name
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
"".to_string()
|
// "".to_string()
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
result.push(json!({
|
// result.push(json!({
|
||||||
"pool": format!("0x{:x}", pool_addr.address()),
|
// "pool": format!("0x{:x}", pool_addr.address()),
|
||||||
"address": format!("0x{:x}", ethread_ptr.address()),
|
// "address": format!("0x{:x}", ethread_ptr.address()),
|
||||||
"type": "_KMUTANT",
|
// "type": "_KMUTANT",
|
||||||
"pid": pid,
|
// "pid": pid,
|
||||||
"tid": tid,
|
// "tid": tid,
|
||||||
"name": thread_name
|
// "name": thread_name
|
||||||
}));
|
// }));
|
||||||
Ok(true)
|
// Ok(true)
|
||||||
})?;
|
// })?;
|
||||||
|
//
|
||||||
Ok(result)
|
// Ok(result)
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
let mut result: Vec<Value> = Vec::new();
|
let mut result: Vec<Value> = Vec::new();
|
||||||
@ -382,7 +349,6 @@ pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
|
|
||||||
while try_ptr <= valid_end {
|
while try_ptr <= valid_end {
|
||||||
// No documentation on type constrain
|
// No documentation on type constrain
|
||||||
// let ftype: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Type")?;
|
|
||||||
let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?;
|
let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?;
|
||||||
if (size as u64) == dob_size /* && ftype == 5u16 */ {
|
if (size as u64) == dob_size /* && ftype == 5u16 */ {
|
||||||
break;
|
break;
|
||||||
@ -392,72 +358,7 @@ pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
if try_ptr > valid_end {
|
if try_ptr > valid_end {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
let dob_addr = &try_ptr;
|
result.push(make_driver(driver, &try_ptr)?);
|
||||||
|
|
||||||
let devicename_ptr = driver.address_of(dob_addr, "_DRIVER_OBJECT.DriverName")?;
|
|
||||||
let servicekey_ptr = driver.address_of(dob_addr, "_DRIVER_OBJECT.DriverExtension.ServiceKeyName")?;
|
|
||||||
let hardware_ptr: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.HardwareDatabase")?;
|
|
||||||
let major_function: Vec<u64> = driver.decompose_array(dob_addr, "_DRIVER_OBJECT.MajorFunction", 28)?;
|
|
||||||
let start: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.DriverStart")?;
|
|
||||||
let init: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.DriverInit")?;
|
|
||||||
let unload: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.DriverUnload")?;
|
|
||||||
let size: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.DriverSize")?;
|
|
||||||
|
|
||||||
let devicename = driver.get_unicode_string(devicename_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
let hardware = driver.get_unicode_string(hardware_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
let servicekey = driver.get_unicode_string(servicekey_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
|
|
||||||
// device tree walk
|
|
||||||
let devices = {
|
|
||||||
let mut driver_devices: Vec<Value> = Vec::new();
|
|
||||||
let mut device_ptr: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.DeviceObject")?;
|
|
||||||
while device_ptr != 0 {
|
|
||||||
let addr = Address::from_base(device_ptr);
|
|
||||||
let device_type: u32 = driver.decompose(&addr, "_DEVICE_OBJECT.DeviceType")?;
|
|
||||||
|
|
||||||
// get attached devices
|
|
||||||
let mut attached_ptr: u64 = driver.decompose(&addr, "_DEVICE_OBJECT.AttachedDevice")?;
|
|
||||||
let mut attached_devices: Vec<Value> = Vec::new();
|
|
||||||
while attached_ptr != 0 {
|
|
||||||
let attached = Address::from_base(attached_ptr);
|
|
||||||
let attached_device_type: u32 = driver.decompose(&attached, "_DEVICE_OBJECT.DeviceType")?;
|
|
||||||
attached_devices.push(json!({
|
|
||||||
"address": format!("0x{:x}", attached_ptr),
|
|
||||||
"type": "_DEVICE_OBJECT",
|
|
||||||
"devicetype": get_device_type(attached_device_type)
|
|
||||||
}));
|
|
||||||
attached_ptr = driver.decompose(&attached, "_DEVICE_OBJECT.AttachedDevice")?;
|
|
||||||
}
|
|
||||||
driver_devices.push(json!({
|
|
||||||
"address": format!("0x{:x}", device_ptr),
|
|
||||||
"type": "_DEVICE_OBJECT",
|
|
||||||
"devicetype": get_device_type(device_type),
|
|
||||||
"attached": attached_devices
|
|
||||||
}));
|
|
||||||
device_ptr = driver.decompose(&addr, "_DEVICE_OBJECT.NextDevice")?;
|
|
||||||
}
|
|
||||||
driver_devices
|
|
||||||
};
|
|
||||||
|
|
||||||
result.push(json!({
|
|
||||||
"pool": format!("0x{:x}", pool_addr.address()),
|
|
||||||
"address": format!("0x{:x}", dob_addr.address()),
|
|
||||||
"type": "_DRIVER_OBJECT",
|
|
||||||
"device": devicename,
|
|
||||||
"hardware": hardware,
|
|
||||||
"major_function": major_function.into_iter()
|
|
||||||
.map(|func| format!("0x{:x}", func))
|
|
||||||
.collect::<Vec<String>>(),
|
|
||||||
"servicekey": servicekey,
|
|
||||||
"start": format!("0x{:x}", start),
|
|
||||||
"init": format!("0x{:x}", init),
|
|
||||||
"unload": format!("0x{:x}", unload),
|
|
||||||
"size": format!("0x{:x}", size),
|
|
||||||
"devicetree": devices
|
|
||||||
}));
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -467,30 +368,9 @@ pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
let mut result: Vec<Value> = Vec::new();
|
let mut result: Vec<Value> = Vec::new();
|
||||||
|
|
||||||
driver.scan_pool(b"MmLd", "_LDR_DATA_TABLE_ENTRY", |pool_addr, _, data_addr| {
|
driver.scan_pool(b"MmLd", "_LDR_DATA_TABLE_ENTRY", |_pool_addr, _, data_addr| {
|
||||||
// By reversing, this structure does not have any header
|
// By reversing, this structure does not have any header
|
||||||
let mod_addr = &data_addr;
|
result.push(make_ldr(driver, &data_addr)?);
|
||||||
|
|
||||||
let dllbase: u64 = driver.decompose(mod_addr, "_LDR_DATA_TABLE_ENTRY.DllBase")?;
|
|
||||||
let entry: u64 = driver.decompose(mod_addr, "_LDR_DATA_TABLE_ENTRY.EntryPoint")?;
|
|
||||||
let size: u64 = driver.decompose(mod_addr, "_LDR_DATA_TABLE_ENTRY.SizeOfImage")?;
|
|
||||||
let fullname_ptr = driver.address_of(mod_addr, "_LDR_DATA_TABLE_ENTRY.FullDllName")?;
|
|
||||||
let basename_ptr = driver.address_of(mod_addr, "_LDR_DATA_TABLE_ENTRY.BaseDllName")?;
|
|
||||||
|
|
||||||
let fullname = driver.get_unicode_string(fullname_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
let basename = driver.get_unicode_string(basename_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
result.push(json!({
|
|
||||||
"pool": format!("0x{:x}", pool_addr.address()),
|
|
||||||
"address": format!("0x{:x}", mod_addr.address()),
|
|
||||||
"type": "_LDR_DATA_TABLE_ENTRY",
|
|
||||||
"dllbase": format!("0x{:x}", dllbase),
|
|
||||||
"entry": format!("0x{:x}", entry),
|
|
||||||
"size": format!("0x{:x}", size),
|
|
||||||
"FullName": fullname,
|
|
||||||
"BaseName": basename
|
|
||||||
}));
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -498,37 +378,13 @@ pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
let mut result: Vec<Value> = Vec::new();
|
|
||||||
|
|
||||||
let ntosbase = driver.get_kernel_base();
|
let ntosbase = driver.get_kernel_base();
|
||||||
let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?;
|
let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?;
|
||||||
|
|
||||||
let mut ptr: u64 = driver.decompose(&module_list_head, "_LIST_ENTRY.Flink")?;
|
let result =
|
||||||
while ptr != module_list_head.address() {
|
make_list_entry(driver, module_list_head.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")?
|
||||||
let mod_addr = Address::from_base(ptr);
|
.iter().map(|x| make_ldr(driver, &x).unwrap_or(json!({}))).collect();
|
||||||
|
|
||||||
let dllbase: u64 = driver.decompose(&mod_addr, "_LDR_DATA_TABLE_ENTRY.DllBase")?;
|
|
||||||
let entry: u64 = driver.decompose(&mod_addr, "_LDR_DATA_TABLE_ENTRY.EntryPoint")?;
|
|
||||||
let size: u64 = driver.decompose(&mod_addr, "_LDR_DATA_TABLE_ENTRY.SizeOfImage")?;
|
|
||||||
let fullname_ptr = driver.address_of(&mod_addr, "_LDR_DATA_TABLE_ENTRY.FullDllName")?;
|
|
||||||
let basename_ptr = driver.address_of(&mod_addr, "_LDR_DATA_TABLE_ENTRY.BaseDllName")?;
|
|
||||||
|
|
||||||
let fullname = driver.get_unicode_string(fullname_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
let basename = driver.get_unicode_string(basename_ptr)
|
|
||||||
.unwrap_or("".to_string());
|
|
||||||
result.push(json!({
|
|
||||||
"address": format!("0x{:x}", mod_addr.address()),
|
|
||||||
"type": "_LDR_DATA_TABLE_ENTRY",
|
|
||||||
"dllbase": format!("0x{:x}", dllbase),
|
|
||||||
"entry": format!("0x{:x}", entry),
|
|
||||||
"size": format!("0x{:x}", size),
|
|
||||||
"FullName": fullname,
|
|
||||||
"BaseName": basename
|
|
||||||
}));
|
|
||||||
|
|
||||||
ptr = driver.decompose(&mod_addr, "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
@ -541,34 +397,11 @@ pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
||||||
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
||||||
|
|
||||||
|
// TODO: make_list_entry
|
||||||
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
||||||
while ptr != process_list_head.address() {
|
while ptr != process_list_head.address() {
|
||||||
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
||||||
|
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
||||||
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")
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
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")?;
|
ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,33 +458,11 @@ pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?;
|
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?;
|
||||||
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_KPROCESS.ProcessListEntry")?;
|
let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_KPROCESS.ProcessListEntry")?;
|
||||||
|
|
||||||
|
// TODO: make_list_entry
|
||||||
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
||||||
while ptr != process_list_head.address() {
|
while ptr != process_list_head.address() {
|
||||||
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
||||||
|
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
||||||
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")
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
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, "_KPROCESS.ProcessListEntry.Flink")?;
|
ptr = driver.decompose(&eprocess_ptr, "_KPROCESS.ProcessListEntry.Flink")?;
|
||||||
}
|
}
|
||||||
@ -674,29 +485,7 @@ pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
|
|
||||||
if quota_process != 0 {
|
if quota_process != 0 {
|
||||||
let eprocess_ptr = Address::from_base(quota_process);
|
let eprocess_ptr = Address::from_base(quota_process);
|
||||||
let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
||||||
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")
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
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(&handle_ptr, "_HANDLE_TABLE.HandleTableList.Flink")?;
|
ptr = driver.decompose(&handle_ptr, "_HANDLE_TABLE.HandleTableList.Flink")?;
|
||||||
|
207
src/object.rs
Normal file
207
src/object.rs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
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::{get_device_type, to_epoch};
|
||||||
|
|
||||||
|
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||||
|
|
||||||
|
pub fn make_list_entry(d: &DriverState, a: Address, next: &str) -> BoxResult<Vec<Address>> {
|
||||||
|
// `a` is the address to the _LIST_ENTRY
|
||||||
|
// `next` is the _LIST_ENTRY field in the object
|
||||||
|
// return a list of address for object
|
||||||
|
let mut result: Vec<Address> = Vec::new();
|
||||||
|
let list_offset = d.pdb_store.get_offset_r(next)?;
|
||||||
|
|
||||||
|
let mut ptr: u64 = d.deref_addr_new(a.address());
|
||||||
|
while ptr != a.address() {
|
||||||
|
let obj_ptr = Address::from_base(ptr - list_offset);
|
||||||
|
ptr = d.decompose(&obj_ptr, &format!("{}.Flink", next))?;
|
||||||
|
result.push(obj_ptr);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_eprocess(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||||
|
let createtime: u64 = d.decompose(a, "_EPROCESS.CreateTime")?;
|
||||||
|
let exittime: u64 = d.decompose(a, "_EPROCESS.ExitTime")?;
|
||||||
|
let pid: u64 = d.decompose(a, "_EPROCESS.UniqueProcessId")?;
|
||||||
|
let ppid: u64 = d.decompose(a, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||||
|
let image_name: Vec<u8> = d.decompose_array(a, "_EPROCESS.ImageFileName", 15)?;
|
||||||
|
let filename_ptr = d.address_of(a, "_EPROCESS.ImageFilePointer.FileName")
|
||||||
|
.unwrap_or(0); // ImageFilePointer is after Windows 10 Anniversary
|
||||||
|
|
||||||
|
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 = d.get_unicode_string(filename_ptr)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
|
||||||
|
let thread_head = d.address_of(a, "_EPROCESS.ThreadListHead")?;
|
||||||
|
let threads: Vec<Value> =
|
||||||
|
make_list_entry(d, Address::from_base(thread_head), "_ETHREAD.ThreadListEntry")
|
||||||
|
.unwrap_or(Vec::new()).iter()
|
||||||
|
.map(|thread_addr| {
|
||||||
|
make_ethread(d, thread_addr)
|
||||||
|
.unwrap_or(json!({})) // unlikely
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let c_t = to_epoch(createtime);
|
||||||
|
let e_t = to_epoch(exittime);
|
||||||
|
|
||||||
|
Ok(json!({
|
||||||
|
"address": format!("0x{:x}", a.address()),
|
||||||
|
"type": "_EPROCESS",
|
||||||
|
"pid": pid,
|
||||||
|
"ppid": ppid,
|
||||||
|
"name": eprocess_name,
|
||||||
|
"path": binary_path,
|
||||||
|
"threads": threads,
|
||||||
|
"createtime": {
|
||||||
|
"unix": c_t.timestamp(),
|
||||||
|
"rfc2822": c_t.to_rfc2822()
|
||||||
|
},
|
||||||
|
"exittime": {
|
||||||
|
"unix": e_t.timestamp(),
|
||||||
|
"rfc2822": e_t.to_rfc2822(),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_ethread(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||||
|
// let createtime: u64 = d.decompose(a, "_ETHREAD.CreateTime")?;
|
||||||
|
// let exittime: u64 = d.decompose(a, "_ETHREAD.ExitTime")?;
|
||||||
|
let pid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueProcess")?;
|
||||||
|
let tid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueThread")?;
|
||||||
|
let name_ptr: u64 = d.address_of(a, "_ETHREAD.ThreadName")
|
||||||
|
.unwrap_or(0); // ThreadName is after Windows 10 Anniversary
|
||||||
|
|
||||||
|
let thread_name =
|
||||||
|
if let Ok(name) = d.get_unicode_string(name_ptr) { name }
|
||||||
|
else { "".to_string() };
|
||||||
|
|
||||||
|
// let c_t = to_epoch(createtime);
|
||||||
|
// let e_t = to_epoch(exittime);
|
||||||
|
|
||||||
|
Ok(json!({
|
||||||
|
"address": format!("0x{:x}", a.address()),
|
||||||
|
"type": "_ETHREAD",
|
||||||
|
"tid": tid,
|
||||||
|
"pid": pid,
|
||||||
|
"name": thread_name,
|
||||||
|
// "createtime": {
|
||||||
|
// "unix": c_t.timestamp(),
|
||||||
|
// "rfc2822": c_t.to_rfc2822()
|
||||||
|
// },
|
||||||
|
// "exittime": {
|
||||||
|
// "unix": e_t.timestamp(),
|
||||||
|
// "rfc2822": e_t.to_rfc2822(),
|
||||||
|
// }
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_driver(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||||
|
let devicename_ptr = d.address_of(a, "_DRIVER_OBJECT.DriverName")?;
|
||||||
|
let servicekey_ptr = d.address_of(a, "_DRIVER_OBJECT.DriverExtension.ServiceKeyName")?;
|
||||||
|
let hardware_ptr: u64 = d.decompose(a, "_DRIVER_OBJECT.HardwareDatabase")?;
|
||||||
|
let major_function: Vec<u64> = d.decompose_array(a, "_DRIVER_OBJECT.MajorFunction", 28)?;
|
||||||
|
let start: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverStart")?;
|
||||||
|
let init: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverInit")?;
|
||||||
|
let unload: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverUnload")?;
|
||||||
|
let size: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverSize")?;
|
||||||
|
|
||||||
|
let devicename = d.get_unicode_string(devicename_ptr)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
let hardware = d.get_unicode_string(hardware_ptr)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
let servicekey = d.get_unicode_string(servicekey_ptr)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
|
||||||
|
// device tree walk
|
||||||
|
let devices = {
|
||||||
|
let mut driver_devices: Vec<Value> = Vec::new();
|
||||||
|
let mut device_ptr: u64 = d.decompose(a, "_DRIVER_OBJECT.DeviceObject")?;
|
||||||
|
while device_ptr != 0 {
|
||||||
|
let addr = Address::from_base(device_ptr);
|
||||||
|
let device_type: u32 = d.decompose(&addr, "_DEVICE_OBJECT.DeviceType")?;
|
||||||
|
|
||||||
|
// get attached devices
|
||||||
|
let mut attached_ptr: u64 = d.decompose(&addr, "_DEVICE_OBJECT.AttachedDevice")?;
|
||||||
|
let mut attached_devices: Vec<Value> = Vec::new();
|
||||||
|
while attached_ptr != 0 {
|
||||||
|
let attached = Address::from_base(attached_ptr);
|
||||||
|
let attached_device_type: u32 = d.decompose(&attached, "_DEVICE_OBJECT.DeviceType")?;
|
||||||
|
attached_devices.push(json!({
|
||||||
|
"address": format!("0x{:x}", attached_ptr),
|
||||||
|
"type": "_DEVICE_OBJECT",
|
||||||
|
"devicetype": get_device_type(attached_device_type)
|
||||||
|
}));
|
||||||
|
attached_ptr = d.decompose(&attached, "_DEVICE_OBJECT.AttachedDevice")?;
|
||||||
|
}
|
||||||
|
driver_devices.push(json!({
|
||||||
|
"address": format!("0x{:x}", device_ptr),
|
||||||
|
"type": "_DEVICE_OBJECT",
|
||||||
|
"devicetype": get_device_type(device_type),
|
||||||
|
"attached": attached_devices
|
||||||
|
}));
|
||||||
|
device_ptr = d.decompose(&addr, "_DEVICE_OBJECT.NextDevice")?;
|
||||||
|
}
|
||||||
|
driver_devices
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(json!({
|
||||||
|
"address": format!("0x{:x}", a.address()),
|
||||||
|
"type": "_DRIVER_OBJECT",
|
||||||
|
"device": devicename,
|
||||||
|
"hardware": hardware,
|
||||||
|
"major_function": major_function.into_iter()
|
||||||
|
.map(|func| format!("0x{:x}", func))
|
||||||
|
.collect::<Vec<String>>(),
|
||||||
|
"servicekey": servicekey,
|
||||||
|
"start": format!("0x{:x}", start),
|
||||||
|
"init": format!("0x{:x}", init),
|
||||||
|
"unload": format!("0x{:x}", unload),
|
||||||
|
"size": format!("0x{:x}", size),
|
||||||
|
"devicetree": devices
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_ldr(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||||
|
let dllbase: u64 = d.decompose(a, "_LDR_DATA_TABLE_ENTRY.DllBase")?;
|
||||||
|
let entry: u64 = d.decompose(a, "_LDR_DATA_TABLE_ENTRY.EntryPoint")?;
|
||||||
|
let size: u64 = d.decompose(a, "_LDR_DATA_TABLE_ENTRY.SizeOfImage")?;
|
||||||
|
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 fullname = d.get_unicode_string(fullname_ptr)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
let basename = d.get_unicode_string(basename_ptr)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
|
||||||
|
let ldr_load: Vec<String> =
|
||||||
|
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")?
|
||||||
|
.iter().map(|x| format!("0x{:x}", x.address())).collect();
|
||||||
|
let ldr_mem: Vec<String> =
|
||||||
|
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks")?
|
||||||
|
.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!({
|
||||||
|
"address": format!("0x{:x}", a.address()),
|
||||||
|
"type": "_LDR_DATA_TABLE_ENTRY",
|
||||||
|
"dllbase": format!("0x{:x}", dllbase),
|
||||||
|
"entry": format!("0x{:x}", entry),
|
||||||
|
"size": format!("0x{:x}", size),
|
||||||
|
"FullName": fullname,
|
||||||
|
"BaseName": basename,
|
||||||
|
"ldr_load": ldr_load,
|
||||||
|
"ldr_mem": ldr_mem,
|
||||||
|
"ldr_init": ldr_init
|
||||||
|
}))
|
||||||
|
}
|
@ -256,9 +256,10 @@ impl WindowsFFI {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let system_up_time_ms = unsafe { GetTickCount64() };
|
let system_up_time_ms = unsafe { GetTickCount64() };
|
||||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond
|
||||||
let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
||||||
let system_start_up_time_ms = now_ms - system_up_time_ms;
|
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 {
|
if process_time_epoch < system_start_up_time_ms {
|
||||||
false
|
false
|
||||||
|
Loading…
Reference in New Issue
Block a user