Generalize the API for common scan and return json

This commit is contained in:
nganhkhoa 2020-06-17 01:47:20 +07:00
parent 060f222c0a
commit 1707b301ff
10 changed files with 350 additions and 249 deletions

20
Cargo.lock generated
View File

@ -218,11 +218,6 @@ dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "http"
version = "0.2.0"
@ -354,10 +349,10 @@ version = "0.1.0"
dependencies = [
"app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
"widestring 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -764,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_json"
version = "1.0.48"
version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -988,7 +983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1080,7 +1075,7 @@ dependencies = [
[[package]]
name = "widestring"
version = "0.4.0"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -1166,7 +1161,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
"checksum http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b"
"checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
@ -1226,7 +1220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
"checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
@ -1263,7 +1257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d"
"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b"
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
"checksum widestring 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a763e303c0e0f23b0da40888724762e802a8ffefbc22de4127ef42493c2ea68c"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View File

@ -12,9 +12,9 @@ doctest = false
[dependencies]
app_dirs = "1.2.1"
hex = "0.4.2"
pdb = "0.5.0"
chrono = "0.4"
widestring = "0.4.0"
winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset", "winioctl", "errhandlingapi", "sysinfoapi"] }
reqwest = { version = "0.10.1", features = ["blocking"] }
serde_json = "1.0.55"

21
src/bin/driver_scan.rs Normal file
View File

@ -0,0 +1,21 @@
use std::error::Error;
use lpus::{
driver_state::{DriverState},
scan_driver
};
fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new();
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
let result = scan_driver(&driver).unwrap_or(Vec::new());
for r in result.iter() {
println!("{:#}", r.to_string());
}
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())
}

View File

@ -1,85 +1,19 @@
use std::error::Error;
use std::str::{from_utf8};
use chrono::Utc;
use chrono::{DateTime};
use std::time::{UNIX_EPOCH, Duration};
use lpus::{
driver_state::{DriverState /* , EprocessPoolChunk */},
address::Address
driver_state::{DriverState},
scan_eprocess
};
#[allow(dead_code)]
fn to_str_time(time_ms: u64) -> String {
if time_ms == 0 {
return "".to_string();
}
let d = UNIX_EPOCH + Duration::from_millis(time_ms);
let datetime = DateTime::<Utc>::from(d);
let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
timestamp_str
}
fn main() -> Result<(), Box<dyn Error>> {
// for windows admin require
// https://github.com/nabijaczleweli/rust-embed-resource
let mut driver = DriverState::new();
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
// let eprocess_scan_head = driver.scan_active_head(ntosbase)?;
// let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
driver.scan_pool(b"Proc", "_EPROCESS", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64;
let result = scan_eprocess(&driver).unwrap_or(Vec::new());
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
let eprocess_valid_start = &data_addr;
let eprocess_valid_end = Address::from_base((pool_addr.address() + chunk_size) - eprocess_size);
let mut try_eprocess_ptr = Address::from_base(eprocess_valid_start.address());
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;
for r in result.iter() {
println!("{:#}", r.to_string());
}
try_eprocess_ptr += 0x4; // search exhaustively
}
if try_eprocess_ptr > eprocess_valid_end {
return Ok(false);
}
let eprocess_ptr = &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")?;
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 =
if unicode_str_ptr != 0 {
driver.get_unicode_string(unicode_str_ptr, true)?
} else {
"".to_string()
};
println!("pool: {} | eprocess: {} | pid: {} | ppid: {} | name: {} | path: {}",
pool_addr, eprocess_ptr, pid, ppid, eprocess_name, binary_path);
// eprocess_list.push(EprocessPoolChunk {
// pool_addr,
// eprocess_addr: try_eprocess_ptr,
// eprocess_name: eprocess_name,
// create_time: to_epoch(create_time),
// exit_time: to_epoch(exit_time)
// });
Ok(true)
})?;
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())

View File

@ -1,127 +0,0 @@
use std::error::Error;
use chrono::Utc;
use chrono::{DateTime};
use std::time::{UNIX_EPOCH, Duration};
use lpus::{
driver_state::{DriverState}
};
#[allow(dead_code)]
fn to_str_time(time_ms: u64) -> String {
if time_ms == 0 {
return "".to_string();
}
let d = UNIX_EPOCH + Duration::from_millis(time_ms);
let datetime = DateTime::<Utc>::from(d);
let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
timestamp_str
}
fn main() -> Result<(), Box<dyn Error>> {
// for windows admin require
// https://github.com/nabijaczleweli/rust-embed-resource
let mut driver = DriverState::new();
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
driver.scan_pool(b"Thre", "_ETHREAD", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64;
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();
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);
}
let ethread_ptr = &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")?;
let thread_name =
if unicode_str_ptr == 0 {
"".to_string()
}
else if let Ok(name) = driver.get_unicode_string(unicode_str_ptr, true) {
name
}
else {
"".to_string()
};
println!("pool: {} | ethread: {} | pid: {} | tid: {} | {}",
pool_addr, ethread_ptr, pid, tid, thread_name);
Ok(true)
})?;
println!("Scan _KMUTANT");
// scan for mutants, also reveals Threads
// driver.scan_pool(b"Muta", "_KMUTANT", |pool_addr, header, data_addr| {
// let chunk_size = (header[2] as u64) * 16u64;
//
// println!("Mutant pool size {}", chunk_size);
// return Ok(false);
//
// let kmutant_size = driver.pdb_store.get_offset_r("_KMUTANT.struct_size")?;
// let kmutant_ownerthread_offset = driver.pdb_store.get_offset_r("_KMUTANT.OwnerThread")?;
// let ethread_name_offset = driver.pdb_store.get_offset_r("_ETHREAD.ThreadName")?;
//
// let kmutant_valid_start = data_addr;
// let kmutant_valid_end = (pool_addr + chunk_size) - kmutant_size;
// let mut try_kmutant_ptr = kmutant_valid_start;
//
// while try_kmutant_ptr <= kmutant_valid_end {
// // TODO: Create check
// try_kmutant_ptr += 0x4; // search exhaustively
// }
// if try_kmutant_ptr > kmutant_valid_end {
// return Ok(false);
// }
//
// let kmutant_ptr = try_kmutant_ptr;
// let mut ethread_ptr = 0u64;
// let mut thread_name_ptr = 0u64;
// let mut pid = 0u64;
// let mut tid = 0u64;
//
// driver.deref_addr(kmutant_ptr + kmutant_ownerthread_offset, &mut ethread_ptr);
// let pid_ptr = driver.pdb_store.addr_decompose(ethread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
// let tid_ptr = driver.pdb_store.addr_decompose(ethread_ptr, "_ETHREAD.Cid.UniqueThread")?;
//
// driver.deref_addr(pid_ptr, &mut pid);
// driver.deref_addr(tid_ptr, &mut tid);
// driver.deref_addr(ethread_ptr + ethread_name_offset, &mut thread_name_ptr);
//
// let thread_name =
// if thread_name_ptr != 0 { driver.get_unicode_string(thread_name_ptr, true)? }
// else { "".to_string() };
//
// println!("pool: 0x{:x} | kmutant: 0x{:x} | pid: {} | tid: {} | {}",
// pool_addr, kmutant_ptr, pid, tid, thread_name);
// Ok(true)
// // kmutant_list.push(EprocessPoolChunk {
// // pool_addr,
// // kmutant_addr: try_kmutant_ptr,
// // kmutant_name: kmutant_name,
// // create_time: to_epoch(create_time),
// // exit_time: to_epoch(exit_time)
// // });
// })?;
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())
}

View File

@ -1,48 +1,19 @@
use std::error::Error;
use lpus::{
driver_state::{DriverState}
driver_state::{DriverState},
scan_file
};
fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new();
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
driver.scan_pool(b"File", "_FILE_OBJECT", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64;
let result = scan_file(&driver).unwrap_or(Vec::new());
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;
for r in result.iter() {
println!("{:#}", r.to_string());
}
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 unicode_str_ptr = driver.address_of(fob_addr, "_FILE_OBJECT.FileName")?;
println!("pool: {} | file object: {}", pool_addr, fob_addr);
if read_ok == 0 {
println!(" [NOT READABLE]");
}
else if let Ok(filename) = driver.get_unicode_string(unicode_str_ptr, true) {
println!(" {}", filename);
}
else {
println!(" [NOT A VALID _UNICODE_STRING]");
}
Ok(true)
})?;
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())

View File

@ -2,7 +2,6 @@ use std::error::Error;
use lpus::{
driver_state::{DriverState},
address::Address
};
fn main() -> Result<(), Box<dyn Error>> {

26
src/bin/thread_scan.rs Normal file
View File

@ -0,0 +1,26 @@
use std::error::Error;
use lpus::{
driver_state::{DriverState},
scan_ethread, /* scan_mutant */
};
fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new();
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
let threads = scan_ethread(&driver).unwrap_or(Vec::new());
// let mutants = scan_mutant(&driver).unwrap_or(Vec::new());
for r in threads.iter() {
println!("{:#}", r.to_string());
}
// for r in mutants.iter() {
// println!("{:#}", r.to_string());
// }
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())
}

View File

@ -265,6 +265,10 @@ impl DriverState {
}
pub fn get_unicode_string(&self, unicode_str_addr: u64, deref: bool) -> BoxResult<String> {
if unicode_str_addr == 0 {
return Err("Not a valid address".into());
}
let mut strlen = 0u16;
let mut capacity = 0u16;
let mut bufaddr = 0u64;

View File

@ -7,3 +7,282 @@ pub mod ioctl_protocol;
pub mod driver_state;
pub mod address;
use std::error::Error;
use std::str::{from_utf8};
use serde_json::{json, Value};
use driver_state::DriverState;
use address::Address;
type BoxResult<T> = Result<T, Box<dyn Error>>;
pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new();
driver.scan_pool(b"Proc", "_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);
}
let eprocess_ptr = &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")?;
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, true)
.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(result)
}
pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
let mut result: Vec<Value> = Vec::new();
driver.scan_pool(b"File", "_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, true) {
n
}
else {
"[NOT A VALID _UNICODE_STRING]".to_string()
};
let devicename = driver.get_unicode_string(devicename_ptr, true)
.unwrap_or("".to_string());
let hardware = driver.get_unicode_string(hardware_ptr, true)
.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();
driver.scan_pool(b"Thre", "_ETHREAD", |pool_addr, header, data_addr| {
let chunk_size = (header[2] as u64) * 16u64;
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();
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);
}
let ethread_ptr = &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")?;
let thread_name =
if let Ok(name) = driver.get_unicode_string(unicode_str_ptr, true) {
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(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)?;
driver.scan_pool(b"Muta", "_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(&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")?;
let thread_name =
if let Ok(name) = driver.get_unicode_string(unicode_str_ptr, true) {
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();
driver.scan_pool(b"Driv", "_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 ftype: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Type")?;
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);
}
let dob_addr = &try_ptr;
let devicename_ptr = driver.address_of(dob_addr, "_DRIVER_OBJECT.DriverName")?;
let hardware_ptr: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.HardwareDatabase")?;
let devicename = driver.get_unicode_string(devicename_ptr, true)
.unwrap_or("".to_string());
let hardware = driver.get_unicode_string(hardware_ptr, true)
.unwrap_or("".to_string());
result.push(json!({
"pool": format!("0x{:x}", pool_addr.address()),
"address": format!("0x{:x}", dob_addr.address()),
"type": "_DRIVER_OBJECT",
"device": devicename,
"hardware": hardware
}));
Ok(true)
})?;
Ok(result)
}