From 4e67e10aee3897292f8f9ccf5e1016e200d0ba3a Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Wed, 1 Jul 2020 00:01:12 +0700 Subject: [PATCH] Update working status for Windows 7 --- src/bin/driver_scan.rs | 3 ++ src/bin/eprocess_scan.rs | 3 ++ src/bin/eprocess_traverse.rs | 3 ++ src/bin/file_object_scan.rs | 3 ++ src/bin/kernel_module_scan.rs | 3 ++ src/bin/kernel_module_traverse.rs | 3 ++ src/bin/print_pdb.rs | 3 ++ src/bin/thread_scan.rs | 3 ++ src/driver_state.rs | 55 +++++++------------- src/lib.rs | 84 +++++++++++++++++++------------ src/windows.rs | 19 ++++++- 11 files changed, 112 insertions(+), 70 deletions(-) diff --git a/src/bin/driver_scan.rs b/src/bin/driver_scan.rs index 6d52020..2a7a93c 100644 --- a/src/bin/driver_scan.rs +++ b/src/bin/driver_scan.rs @@ -7,6 +7,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let result = scan_driver(&driver).unwrap_or(Vec::new()); diff --git a/src/bin/eprocess_scan.rs b/src/bin/eprocess_scan.rs index 83cdcfc..9d21e52 100644 --- a/src/bin/eprocess_scan.rs +++ b/src/bin/eprocess_scan.rs @@ -7,6 +7,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let result = scan_eprocess(&driver).unwrap_or(Vec::new()); diff --git a/src/bin/eprocess_traverse.rs b/src/bin/eprocess_traverse.rs index a66857d..eb1bcff 100644 --- a/src/bin/eprocess_traverse.rs +++ b/src/bin/eprocess_traverse.rs @@ -9,6 +9,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let activehead = traverse_activehead(&driver).unwrap_or(Vec::new()); diff --git a/src/bin/file_object_scan.rs b/src/bin/file_object_scan.rs index 2e6e48a..6823cc6 100644 --- a/src/bin/file_object_scan.rs +++ b/src/bin/file_object_scan.rs @@ -7,6 +7,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let result = scan_file(&driver).unwrap_or(Vec::new()); diff --git a/src/bin/kernel_module_scan.rs b/src/bin/kernel_module_scan.rs index 980b763..ca47099 100644 --- a/src/bin/kernel_module_scan.rs +++ b/src/bin/kernel_module_scan.rs @@ -7,6 +7,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let result = scan_kernel_module(&driver).unwrap_or(Vec::new()); diff --git a/src/bin/kernel_module_traverse.rs b/src/bin/kernel_module_traverse.rs index 096ec89..995fc90 100644 --- a/src/bin/kernel_module_traverse.rs +++ b/src/bin/kernel_module_traverse.rs @@ -10,6 +10,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new()); diff --git a/src/bin/print_pdb.rs b/src/bin/print_pdb.rs index ec2b91e..a60afa0 100644 --- a/src/bin/print_pdb.rs +++ b/src/bin/print_pdb.rs @@ -25,6 +25,9 @@ fn main() -> Result<(), Box> { driver.windows_ffi.print_version(); driver.pdb_store.print_default_information(); + println!("{}", to_epoch(0xfffffa80018cb688)); + println!("{}", to_epoch(0x01d64ecd8b295318)); + let mut rl = Editor::<()>::new(); if rl.load_history("history.lpus").is_err() { println!("No previous history."); diff --git a/src/bin/thread_scan.rs b/src/bin/thread_scan.rs index 0b83d92..95604d0 100644 --- a/src/bin/thread_scan.rs +++ b/src/bin/thread_scan.rs @@ -7,6 +7,9 @@ use lpus::{ fn main() -> Result<(), Box> { let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!("Windows version {:?} is not supported", driver.windows_ffi.short_version).into()); + } println!("NtLoadDriver() -> 0x{:x}", driver.startup()); let threads = scan_ethread(&driver).unwrap_or(Vec::new()); diff --git a/src/driver_state.rs b/src/driver_state.rs index b0abfdf..d2c4bb2 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -103,6 +103,20 @@ impl DriverState { self.windows_ffi.unload_driver() } + pub fn is_supported(&self) -> bool { + self.windows_ffi.short_version.is_supported() + } + + pub fn use_old_tag(&self) -> bool { + // use old tag to scan, for Window < 8 + if self.windows_ffi.short_version < WindowsVersion::Windows8 { + true + } + else { + false + } + } + pub fn get_kernel_base(&self) -> Address { let mut ntosbase = 0u64; self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(), @@ -110,46 +124,12 @@ impl DriverState { Address::from_base(ntosbase) } - // pub fn scan_active_head(&self) -> BoxResult> { - // let ntosbase = self.get_kernel_base(); - // let ps_active_head = ntosbase + self.pdb_store.get_offset_r("PsActiveProcessHead")?; - // let flink_offset = self.pdb_store.get_offset_r("_LIST_ENTRY.Flink")?; - // let eprocess_link_offset = self.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?; - // let eprocess_name_offset = self.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?; - // - // let mut ptr = ps_active_head; - // self.deref_addr((ptr + flink_offset).get(), &mut ptr); - // - // let mut result: Vec = Vec::new(); - // while ptr != ps_active_head { - // let mut image_name = [0u8; 15]; - // let eprocess = ptr - eprocess_link_offset; - // self.deref_addr(eprocess + eprocess_name_offset, &mut image_name); - // match std::str::from_utf8(&image_name) { - // Ok(n) => { - // result.push(EprocessPoolChunk { - // pool_addr: 0, - // eprocess_addr: eprocess, - // eprocess_name: n.to_string() - // .trim_end_matches(char::from(0)) - // .to_string(), - // create_time: 0, - // exit_time: 0 - // - // }); - // }, - // _ => {} - // }; - // self.deref_addr(ptr + flink_offset, &mut ptr); - // } - // Ok(result) - // } - pub fn scan_pool(&self, tag: &[u8; 4], expected_struct: &str, mut handler: F) -> BoxResult where F: FnMut(Address, &[u8], Address) -> BoxResult // F(Pool Address, Pool Header Data, Pool Data Address) // TODO: Pool Header as a real struct { + // TODO: scan large pool // TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122 // Making this function a generator will turn the call to a for loop // https://docs.rs/gen-iter/0.2.0/gen_iter/ @@ -161,7 +141,8 @@ impl DriverState { let ntosbase = self.get_kernel_base(); let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?; - println!("kernel base: {}; non-paged pool (start, end): ({}, {})", ntosbase, start_address, end_address); + println!("kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}", + ntosbase, start_address, end_address, tag, expected_struct); let mut ptr = start_address; while ptr < end_address { @@ -191,7 +172,7 @@ impl DriverState { } let data_addr = Address::from_base(pool_addr.address() + pool_header_size); - let success = handler(pool_addr, &header, data_addr)?; + let success = handler(pool_addr, &header, data_addr).unwrap_or(false); if success { ptr += chunk_size; // skip this chunk } diff --git a/src/lib.rs b/src/lib.rs index 83f9617..5561865 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,7 +121,10 @@ fn get_device_type(typ: u32) -> String { pub fn scan_eprocess(driver: &DriverState) -> BoxResult> { let mut result: Vec = Vec::new(); - driver.scan_pool(b"Proc", "_EPROCESS", |pool_addr, header, data_addr| { + 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")?; @@ -142,14 +145,11 @@ pub fn scan_eprocess(driver: &DriverState) -> BoxResult> { } let eprocess_ptr = &try_eprocess_ptr; - - println!("EPROCESS: 0x{:x}", eprocess_ptr.address()); - let pid: u64 = driver.decompose(eprocess_ptr, "_EPROCESS.UniqueProcessId")?; let ppid: u64 = driver.decompose(eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?; let image_name: Vec = 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 Windows 10+ + .unwrap_or(0); // ImageFilePointer is after Windows 10 Anniversary let eprocess_name = if let Ok(name) = from_utf8(&image_name) { @@ -177,7 +177,10 @@ pub fn scan_eprocess(driver: &DriverState) -> BoxResult> { pub fn scan_file(driver: &DriverState) -> BoxResult> { let mut result: Vec = Vec::new(); - driver.scan_pool(b"File", "_FILE_OBJECT", |pool_addr, header, data_addr| { + 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")?; @@ -246,30 +249,41 @@ pub fn scan_file(driver: &DriverState) -> BoxResult> { pub fn scan_ethread(driver: &DriverState) -> BoxResult> { let mut result: Vec = Vec::new(); - driver.scan_pool(b"Thre", "_ETHREAD", |pool_addr, header, data_addr| { + 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(); - 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 chunk_size == header_size + object_header_size + ethread_size { + try_ethread_ptr = ethread_valid_end.clone(); } - if try_ethread_ptr > ethread_valid_end { - return Ok(false); + 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); + } } 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 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) { @@ -300,7 +314,10 @@ pub fn scan_mutant(driver: &DriverState) -> BoxResult> { 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 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")?; @@ -353,7 +370,10 @@ pub fn scan_mutant(driver: &DriverState) -> BoxResult> { pub fn scan_driver(driver: &DriverState) -> BoxResult> { let mut result: Vec = Vec::new(); - driver.scan_pool(b"Driv", "_DRIVER_OBJECT", |pool_addr, header, data_addr| { + 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")?; @@ -447,15 +467,15 @@ pub fn scan_driver(driver: &DriverState) -> BoxResult> { pub fn scan_kernel_module(driver: &DriverState) -> BoxResult> { let mut result: Vec = Vec::new(); - driver.scan_pool(b"MmLd", "_KLDR_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 let mod_addr = &data_addr; - let dllbase: u64 = driver.decompose(mod_addr, "_KLDR_DATA_TABLE_ENTRY.DllBase")?; - let entry: u64 = driver.decompose(mod_addr, "_KLDR_DATA_TABLE_ENTRY.EntryPoint")?; - let size: u64 = driver.decompose(mod_addr, "_KLDR_DATA_TABLE_ENTRY.SizeOfImage")?; - let fullname_ptr = driver.address_of(mod_addr, "_KLDR_DATA_TABLE_ENTRY.FullDllName")?; - let basename_ptr = driver.address_of(mod_addr, "_KLDR_DATA_TABLE_ENTRY.BaseDllName")?; + 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()); @@ -464,7 +484,7 @@ pub fn scan_kernel_module(driver: &DriverState) -> BoxResult> { result.push(json!({ "pool": format!("0x{:x}", pool_addr.address()), "address": format!("0x{:x}", mod_addr.address()), - "type": "_KLDR_DATA_TABLE_ENTRY", + "type": "_LDR_DATA_TABLE_ENTRY", "dllbase": format!("0x{:x}", dllbase), "entry": format!("0x{:x}", entry), "size": format!("0x{:x}", size), @@ -487,11 +507,11 @@ pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult> while ptr != module_list_head.address() { let mod_addr = Address::from_base(ptr); - let dllbase: u64 = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.DllBase")?; - let entry: u64 = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.EntryPoint")?; - let size: u64 = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.SizeOfImage")?; - let fullname_ptr = driver.address_of(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.FullDllName")?; - let basename_ptr = driver.address_of(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.BaseDllName")?; + 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()); @@ -499,7 +519,7 @@ pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult> .unwrap_or("".to_string()); result.push(json!({ "address": format!("0x{:x}", mod_addr.address()), - "type": "_KLDR_DATA_TABLE_ENTRY", + "type": "_LDR_DATA_TABLE_ENTRY", "dllbase": format!("0x{:x}", dllbase), "entry": format!("0x{:x}", entry), "size": format!("0x{:x}", size), @@ -507,7 +527,7 @@ pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult> "BaseName": basename })); - ptr = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink")?; + ptr = driver.decompose(&mod_addr, "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink")?; } Ok(result) diff --git a/src/windows.rs b/src/windows.rs index ca703e1..66ba2a4 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -27,7 +27,7 @@ use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCA const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus"; #[allow(dead_code)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub enum WindowsVersion { Windows7, Windows8, @@ -42,6 +42,23 @@ pub enum WindowsVersion { WindowsUnknown } +impl WindowsVersion { + pub fn not_supported(self) -> bool { + match self { + WindowsVersion::Windows10Legacy | + WindowsVersion::Windows10_2015 | + WindowsVersion::Windows10_2016 | + WindowsVersion::Windows10_2017 | + WindowsVersion::Windows8 | + WindowsVersion::WindowsUnknown => true, + _ => false + } + } + pub fn is_supported(self) -> bool { + !self.not_supported() + } +} + #[allow(dead_code)] #[derive(Copy, Clone)] pub struct WindowsFFI {