From 8928e4e4cbab46b49bd7385e400cb46680f4e21b Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 24 Feb 2020 22:53:30 +0700 Subject: [PATCH 1/9] add device io call --- Cargo.toml | 2 +- src/main.rs | 5 ++ src/windows.rs | 146 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 117 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 01a0399..75453c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,5 @@ edition = "2018" hex = "0.4.2" pdb = "0.5.0" widestring = "0.4.0" -winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg"] } +winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset"] } reqwest = { version = "0.10.1", features = ["blocking"] } diff --git a/src/main.rs b/src/main.rs index 953a8f2..01f5a15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,9 +5,14 @@ fn main() { let store = pdb_store::parse_pdb(); store.print_default_information(); + // for windows admin require + // https://github.com/nabijaczleweli/rust-embed-resource let mut windows_ffi = windows::WindowsFFI::new(); windows_ffi.print_version(); println!("NtLoadDriver() -> 0x{:x}", windows_ffi.load_driver()); + + windows_ffi.device_io(0x900); + println!("NtUnloadDriver() -> 0x{:x}", windows_ffi.unload_driver()); } diff --git a/src/windows.rs b/src/windows.rs index d0daff4..fc876e8 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,20 +1,24 @@ use std::ffi::CString; -use widestring::{U16CString}; +use std::ptr::null_mut; +use widestring::U16CString; use winapi::shared::ntdef::*; use winapi::shared::minwindef::{DWORD, HKEY, HMODULE}; use winapi::um::winnt::{ SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES, REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE, - PRTL_OSVERSIONINFOW, OSVERSIONINFOW + PRTL_OSVERSIONINFOW, OSVERSIONINFOW, + FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE }; -use winapi::um::handleapi::*; -use winapi::um::libloaderapi::*; -use winapi::um::processthreadsapi::*; -use winapi::um::securitybaseapi::*; -use winapi::um::winbase::*; -use winapi::um::winreg::*; +use winapi::um::ioapiset::DeviceIoControl; +use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS}; +use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle}; +use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress}; +use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; +use winapi::um::securitybaseapi::{AdjustTokenPrivileges}; +use winapi::um::winbase::{LookupPrivilegeValueA}; +use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE}; #[allow(dead_code)] #[derive(Debug)] @@ -33,7 +37,8 @@ pub enum WindowsVersion { pub struct WindowsFFI { pub version_info: OSVERSIONINFOW, pub short_version: WindowsVersion, - driver_registry_string: UNICODE_STRING, + // driver_registry_string: UNICODE_STRING, + driver_handle: HANDLE, ntdll: HMODULE, nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS, nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS, @@ -43,23 +48,22 @@ pub struct WindowsFFI { impl WindowsFFI { pub fn new() -> Self { - let str_ntdll = CString::new("ntdll").expect(""); - let str_nt_load_driver = CString::new("NtLoadDriver").expect(""); - let str_nt_unload_driver = CString::new("NtUnloadDriver").expect(""); - let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").expect(""); - let str_rtl_get_version = CString::new("RtlGetVersion").expect(""); - let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").expect(""); + let str_ntdll = CString::new("ntdll").unwrap(); + let str_nt_load_driver = CString::new("NtLoadDriver").unwrap(); + let str_nt_unload_driver = CString::new("NtUnloadDriver").unwrap(); + let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").unwrap(); + let str_rtl_get_version = CString::new("RtlGetVersion").unwrap(); + let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap(); - let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").expect(""); - let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); - let str_driver_reg = - U16CString::from_str("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); - let str_type = CString::new("Type").expect(""); - let str_error_control = CString::new("ErrorControl").expect(""); - let str_start = CString::new("Start").expect(""); - let str_image_path = CString::new("ImagePath").expect(""); + let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").unwrap(); + let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").unwrap(); + let str_type = CString::new("Type").unwrap(); + let str_error_control = CString::new("ErrorControl").unwrap(); + let str_start = CString::new("Start").unwrap(); + let str_image_path = CString::new("ImagePath").unwrap(); - let mut str_driver_reg_unicode = UNICODE_STRING::default(); + // let mut str_driver_reg_unicode = UNICODE_STRING::default(); + let str_driver_reg_unicode: UNICODE_STRING; let mut version_info = OSVERSIONINFOW { dwOSVersionInfoSize: 0u32, dwMajorVersion: 0u32, @@ -89,12 +93,12 @@ impl WindowsFFI { rtl_get_version = std::mem::transmute(rtl_get_version_); // setup registry - let mut registry_key: HKEY = std::ptr::null_mut(); + let mut registry_key: HKEY = null_mut(); RegCreateKeyExA( HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(), - 0, std::ptr::null_mut(), + 0, null_mut(), REG_OPTION_NON_VOLATILE, KEY_WRITE, - std::ptr::null_mut(), &mut registry_key, std::ptr::null_mut() + null_mut(), &mut registry_key, null_mut() ); let type_value: [u8; 4] = 1u32.to_le_bytes(); let error_control_value: [u8; 4] = 1u32.to_le_bytes(); @@ -115,10 +119,10 @@ impl WindowsFFI { RegCloseKey(registry_key); // Setup privilege SeLoadDriverPrivilege - let mut token_handle: HANDLE = std::ptr::null_mut(); + let mut token_handle: HANDLE = null_mut(); let mut luid = LUID::default(); OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle); - LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); + LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); let mut new_token_state = TOKEN_PRIVILEGES { PrivilegeCount: 1, Privileges: [LUID_AND_ATTRIBUTES { @@ -127,11 +131,17 @@ impl WindowsFFI { }] }; AdjustTokenPrivileges( - token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut()); + token_handle, 0, &mut new_token_state, 16, null_mut(), null_mut()); CloseHandle(token_handle); - // init string for load and unload driver routine - rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); + // init string for loading and unloading driver routine + // rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); + // + // let unicode_str = + // U16CString::from_ptr_unchecked( + // str_driver_reg_unicode.Buffer, (str_driver_reg_unicode.Length / 2) as usize); + // + // println!("unicode string created: {:p} {}", str_driver_reg_unicode.Buffer, unicode_str.to_string_lossy()); } rtl_get_version(&mut version_info); @@ -147,7 +157,8 @@ impl WindowsFFI { Self { version_info, short_version, - driver_registry_string: str_driver_reg_unicode, + // driver_registry_string: str_driver_reg_unicode, + driver_handle: null_mut(), ntdll, nt_load_driver, nt_unload_driver, @@ -157,11 +168,69 @@ impl WindowsFFI { } pub fn load_driver(&mut self) -> NTSTATUS { - (self.nt_load_driver)(&mut self.driver_registry_string) + let mut str_driver_reg_unicode: UNICODE_STRING = UNICODE_STRING::default(); + unsafe { + let str_driver_reg = + U16CString::from_str( + "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa") + .expect(""); + (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); + // str_driver_reg_unicode = UNICODE_STRING { + // Length: (str_driver_reg.len() * 2) as u16, + // MaximumLength: (str_driver_reg.len() * 2) as u16, + // Buffer: str_driver_reg.as_ptr() as *mut u16 + // }; + let unicode_str = + U16CString::from_ptr_unchecked( + str_driver_reg_unicode.Buffer, (str_driver_reg_unicode.Length / 2) as usize); + + println!("unicode string called: {:p} {}", str_driver_reg_unicode.Buffer, unicode_str.to_string_lossy()); + println!("unicode string called: {:?}", unicode_str.into_vec_with_nul()); + } + let status = (self.nt_load_driver)(&mut str_driver_reg_unicode); + // Create a device handle to loaded driver + let driver_system_path = CString::new("\\Device\\poolscanner").unwrap(); + let driver_handle; + unsafe { + driver_handle = CreateFileA(driver_system_path.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + 0, + null_mut(), + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + null_mut()); + } + // TODO: check driver_handle return status + self.driver_handle = driver_handle; + if driver_handle == INVALID_HANDLE_VALUE { + println!("Driver create failed"); + status + } + else { + status + } } pub fn unload_driver(&mut self) -> NTSTATUS { - (self.nt_unload_driver)(&mut self.driver_registry_string) + let mut str_driver_reg_unicode: UNICODE_STRING; + unsafe { + let str_driver_reg = + U16CString::from_str( + "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa") + .expect(""); + str_driver_reg_unicode = UNICODE_STRING { + Length: (str_driver_reg.len() * 2) as u16, + MaximumLength: (str_driver_reg.len() * 2) as u16, + Buffer: str_driver_reg.as_ptr() as *mut u16 + }; + let unicode_str = + U16CString::from_ptr_unchecked( + str_driver_reg_unicode.Buffer, (str_driver_reg_unicode.Length / 2) as usize); + + println!("unicode string called: {:p} {}", str_driver_reg_unicode.Buffer, unicode_str.to_string_lossy()); + println!("unicode string called: {:?}", unicode_str.into_vec_with_nul()); + } + (self.nt_unload_driver)(&mut str_driver_reg_unicode) } #[allow(dead_code)] @@ -178,4 +247,11 @@ impl WindowsFFI { self.short_version ); } + + #[allow(dead_code)] + pub fn device_io(&self, _code: DWORD) { + unsafe { + DeviceIoControl(self.driver_handle, 0x900, null_mut(), 0, null_mut(), 0, null_mut(), null_mut()); + } + } } From 2ee77d16c7a26ea2f3d3f0e0b88158595427df99 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Tue, 25 Feb 2020 01:20:54 +0700 Subject: [PATCH 2/9] Fix load driver issue The Buffer pointer of UNICODE_STRING seems to be cleaned up after routine, so we cannot store the string, but have to init the string when needed. --- src/windows.rs | 110 ++++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 78 deletions(-) diff --git a/src/windows.rs b/src/windows.rs index fc876e8..a009ecd 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,4 +1,5 @@ use std::ffi::CString; +use std::mem::transmute; use std::ptr::null_mut; use widestring::U16CString; @@ -20,6 +21,8 @@ use winapi::um::securitybaseapi::{AdjustTokenPrivileges}; use winapi::um::winbase::{LookupPrivilegeValueA}; use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE}; +const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa"; + #[allow(dead_code)] #[derive(Debug)] pub enum WindowsVersion { @@ -37,12 +40,11 @@ pub enum WindowsVersion { pub struct WindowsFFI { pub version_info: OSVERSIONINFOW, pub short_version: WindowsVersion, - // driver_registry_string: UNICODE_STRING, driver_handle: HANDLE, ntdll: HMODULE, - nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS, - nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS, - rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR), + nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS, + nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS, + rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR), rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS, } @@ -62,8 +64,6 @@ impl WindowsFFI { let str_start = CString::new("Start").unwrap(); let str_image_path = CString::new("ImagePath").unwrap(); - // let mut str_driver_reg_unicode = UNICODE_STRING::default(); - let str_driver_reg_unicode: UNICODE_STRING; let mut version_info = OSVERSIONINFOW { dwOSVersionInfoSize: 0u32, dwMajorVersion: 0u32, @@ -74,9 +74,9 @@ impl WindowsFFI { }; let ntdll: HMODULE; - let nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; - let nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; - let rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR); + let nt_load_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS; + let nt_unload_driver: extern "system" fn(PUNICODE_STRING) -> NTSTATUS; + let rtl_init_unicode_str: extern "system" fn(PUNICODE_STRING, PCWSTR); let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS; // some pointer unsafe C code @@ -87,10 +87,10 @@ impl WindowsFFI { let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr()); let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr()); - nt_load_driver = std::mem::transmute(nt_load_driver_); - nt_unload_driver = std::mem::transmute(nt_unload_driver_); - rtl_init_unicode_str = std::mem::transmute(rtl_init_unicode_str_); - rtl_get_version = std::mem::transmute(rtl_get_version_); + nt_load_driver = transmute(nt_load_driver_); + nt_unload_driver = transmute(nt_unload_driver_); + rtl_init_unicode_str = transmute(rtl_init_unicode_str_); + rtl_get_version = transmute(rtl_get_version_); // setup registry let mut registry_key: HKEY = null_mut(); @@ -133,15 +133,6 @@ impl WindowsFFI { AdjustTokenPrivileges( token_handle, 0, &mut new_token_state, 16, null_mut(), null_mut()); CloseHandle(token_handle); - - // init string for loading and unloading driver routine - // rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); - // - // let unicode_str = - // U16CString::from_ptr_unchecked( - // str_driver_reg_unicode.Buffer, (str_driver_reg_unicode.Length / 2) as usize); - // - // println!("unicode string created: {:p} {}", str_driver_reg_unicode.Buffer, unicode_str.to_string_lossy()); } rtl_get_version(&mut version_info); @@ -157,7 +148,6 @@ impl WindowsFFI { Self { version_info, short_version, - // driver_registry_string: str_driver_reg_unicode, driver_handle: null_mut(), ntdll, nt_load_driver, @@ -168,68 +158,32 @@ impl WindowsFFI { } pub fn load_driver(&mut self) -> NTSTATUS { - let mut str_driver_reg_unicode: UNICODE_STRING = UNICODE_STRING::default(); - unsafe { - let str_driver_reg = - U16CString::from_str( - "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa") - .expect(""); - (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); - // str_driver_reg_unicode = UNICODE_STRING { - // Length: (str_driver_reg.len() * 2) as u16, - // MaximumLength: (str_driver_reg.len() * 2) as u16, - // Buffer: str_driver_reg.as_ptr() as *mut u16 - // }; - let unicode_str = - U16CString::from_ptr_unchecked( - str_driver_reg_unicode.Buffer, (str_driver_reg_unicode.Length / 2) as usize); - - println!("unicode string called: {:p} {}", str_driver_reg_unicode.Buffer, unicode_str.to_string_lossy()); - println!("unicode string called: {:?}", unicode_str.into_vec_with_nul()); - } + let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap(); + let mut str_driver_reg_unicode = UNICODE_STRING::default(); + (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); let status = (self.nt_load_driver)(&mut str_driver_reg_unicode); - // Create a device handle to loaded driver - let driver_system_path = CString::new("\\Device\\poolscanner").unwrap(); - let driver_handle; - unsafe { - driver_handle = CreateFileA(driver_system_path.as_ptr(), - GENERIC_READ | GENERIC_WRITE, - 0, - null_mut(), - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - null_mut()); - } - // TODO: check driver_handle return status - self.driver_handle = driver_handle; - if driver_handle == INVALID_HANDLE_VALUE { - println!("Driver create failed"); - status + + let filename = CString::new("\\Device\\poolscanner").unwrap(); + let driver_file_handle: HANDLE = unsafe { + CreateFileA(filename.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + 0, null_mut(), CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, null_mut()) + }; + + if driver_file_handle == INVALID_HANDLE_VALUE { + println!("Driver CreateFileA failed"); } else { - status + self.driver_handle = driver_file_handle; } + status } pub fn unload_driver(&mut self) -> NTSTATUS { - let mut str_driver_reg_unicode: UNICODE_STRING; - unsafe { - let str_driver_reg = - U16CString::from_str( - "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa") - .expect(""); - str_driver_reg_unicode = UNICODE_STRING { - Length: (str_driver_reg.len() * 2) as u16, - MaximumLength: (str_driver_reg.len() * 2) as u16, - Buffer: str_driver_reg.as_ptr() as *mut u16 - }; - let unicode_str = - U16CString::from_ptr_unchecked( - str_driver_reg_unicode.Buffer, (str_driver_reg_unicode.Length / 2) as usize); - - println!("unicode string called: {:p} {}", str_driver_reg_unicode.Buffer, unicode_str.to_string_lossy()); - println!("unicode string called: {:?}", unicode_str.into_vec_with_nul()); - } + let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap(); + let mut str_driver_reg_unicode = UNICODE_STRING::default(); + (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); (self.nt_unload_driver)(&mut str_driver_reg_unicode) } From 0ca87a871c9a2dee7fd47510b7e02ab93fd8b095 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Tue, 25 Feb 2020 01:33:16 +0700 Subject: [PATCH 3/9] fix driver file name path --- src/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows.rs b/src/windows.rs index a009ecd..30496f6 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -163,7 +163,7 @@ impl WindowsFFI { (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); let status = (self.nt_load_driver)(&mut str_driver_reg_unicode); - let filename = CString::new("\\Device\\poolscanner").unwrap(); + let filename = CString::new("\\\\.\\poolscanner").unwrap(); let driver_file_handle: HANDLE = unsafe { CreateFileA(filename.as_ptr(), GENERIC_READ | GENERIC_WRITE, From d08852af559aac72a7b6b5539a5b539db1c95eaa Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Thu, 27 Feb 2020 03:27:54 +0700 Subject: [PATCH 4/9] finish device io call to scan --- Cargo.toml | 2 +- src/driver_state.rs | 246 ++++++++++++++++++++++++++++++++++++++++++ src/ioctl_protocol.rs | 95 ++++++++++++++++ src/main.rs | 23 ++-- src/windows.rs | 55 ++++++++-- 5 files changed, 402 insertions(+), 19 deletions(-) create mode 100644 src/driver_state.rs create mode 100644 src/ioctl_protocol.rs diff --git a/Cargo.toml b/Cargo.toml index 75453c8..6edb2a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,5 @@ edition = "2018" hex = "0.4.2" pdb = "0.5.0" widestring = "0.4.0" -winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset"] } +winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset", "winioctl", "errhandlingapi"] } reqwest = { version = "0.10.1", features = ["blocking"] } diff --git a/src/driver_state.rs b/src/driver_state.rs new file mode 100644 index 0000000..68caec0 --- /dev/null +++ b/src/driver_state.rs @@ -0,0 +1,246 @@ +use std::ffi::c_void; +use std::mem::{size_of_val}; + +use winapi::shared::ntdef::{NTSTATUS}; +use winapi::shared::minwindef::{DWORD}; +use winapi::um::winioctl::{ + CTL_CODE, FILE_ANY_ACCESS, + METHOD_IN_DIRECT, METHOD_OUT_DIRECT, METHOD_BUFFERED, METHOD_NEITHER +}; + +use crate::pdb_store::{PdbStore}; +use crate::windows::{WindowsFFI, WindowsVersion}; +use crate::ioctl_protocol::{ + InputData, OffsetData, DerefAddr, ScanRange, + OutputData, Nothing +}; + +const SIOCTL_TYPE: DWORD = 40000; + +#[allow(dead_code)] +#[derive(Debug)] +pub enum DriverAction { + SetupOffset, + GetKernelBase, + ScanPsActiveHead, + ScanPool, + ScanPoolRemote, + DereferenceAddress +} + +impl DriverAction { + pub fn get_code(&self) -> DWORD { + match self { + DriverAction::SetupOffset => CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS), + DriverAction::GetKernelBase => CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS), + DriverAction::ScanPsActiveHead => CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS), + DriverAction::ScanPool => CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS), + DriverAction::ScanPoolRemote => CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS), + DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + } + } +} + +#[allow(dead_code)] +pub struct DriverState { + pdb_store: PdbStore, + windows_ffi: WindowsFFI, + ntosbase: u64, + nonpaged_range: [u64; 2], +} + +impl DriverState { + pub fn new(pdb_store: PdbStore, windows_ffi: WindowsFFI) -> Self { + pdb_store.print_default_information(); + windows_ffi.print_version(); + Self { + pdb_store, + windows_ffi, + ntosbase: 0u64, + nonpaged_range: [0, 0] + } + } + + pub fn startup(&mut self) -> NTSTATUS { + self.windows_ffi.load_driver() + } + + pub fn shutdown(&self) -> NTSTATUS { + self.windows_ffi.unload_driver() + } + + // TODO: Function output and input data???? + pub fn interact(&mut self, action: DriverAction) { + let code = action.get_code(); + println!("Driver action: {:?}", action); + match action { + DriverAction::SetupOffset => { + let mut input = InputData { + offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version) + }; + self.windows_ffi.device_io(code, &mut input, &mut Nothing); + }, + DriverAction::GetKernelBase => { + self.windows_ffi.device_io(code, &mut Nothing, &mut self.ntosbase); + println!("ntosbase: 0x{:x}", self.ntosbase); + }, + DriverAction::ScanPsActiveHead => { + self.interact(DriverAction::GetKernelBase); + let ps_active_head = self.ntosbase + self.pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64); + let flink_offset = self.pdb_store.get_offset("_LIST_ENTRY.Flink").unwrap_or(0u64); + let eprocess_link_offset = self.pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64); + let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64); + + let mut ptr = ps_active_head; + self.deref_addr(ptr + flink_offset, &mut ptr); + + println!("========================"); + println!("Scan PsActiveProcessHead"); + 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) => { + // TODO: save to somewhere + println!("_EPROCESS at 0x{:x} of {}", eprocess, n); + }, + _ => {} + }; + self.deref_addr(ptr + flink_offset, &mut ptr); + } + println!("========================"); + + // test call to check result + self.windows_ffi.device_io(code, &mut Nothing, &mut Nothing); + }, + DriverAction::ScanPool => { + self.get_nonpaged_range(); + let mut input = InputData { + scan_range: ScanRange::new(&self.nonpaged_range) + }; + self.windows_ffi.device_io(code, &mut input, &mut Nothing); + }, + DriverAction::ScanPoolRemote => { + self.get_nonpaged_range(); + let start_address = self.nonpaged_range[0]; + let end_address = self.nonpaged_range[1]; + + let pool_header_size = self.pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64); + let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64); + + let mut ptr = start_address; + while ptr < end_address { + let mut input = InputData { + scan_range: ScanRange::new(&[ptr, end_address]) + }; + self.windows_ffi.device_io(code, &mut input, &mut ptr); + if ptr >= end_address { + break; + } + let pool_addr = ptr; + ptr += pool_header_size; + + let mut pool = vec![0u8; pool_header_size as usize]; + self.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); + // TODO: Use pdb to parse, bit mangling and stuff + println!("========================="); + println!("Pool at 0x{:x}", pool_addr); + println!("Previos Size: 0x{:x}", pool[0]); + println!("Pool index : {:x}", pool[1]); + println!("Block size : 0x{:x}", (pool[2] as u64) * 16u64); // CHUNK_SIZE = 16 + println!("Pool type : {}", pool[3]); + println!("Pool tag : {}", std::str::from_utf8(&pool[4..8]).unwrap()); + + let pool_size = (pool[2] as u64) * 16u64; + // dump pool here + let eprocess_offset: Vec = match pool_size { + 0xf00 => vec![0x40], + 0xd80 => vec![0x40, 0x70, 0x80], + 0xe00 => vec![0x60, 0x70, 0x80, 0x90], + _ => vec![] + }; + // let eprocess_offset: Vec = vec![0x40, 0x70, 0x80]; + let mut found_valid = false; + for &offset in &eprocess_offset { + let eprocess = pool_addr + offset; + let mut image_name = [0u8; 15]; + self.deref_addr(eprocess + eprocess_name_offset, &mut image_name); + match std::str::from_utf8(&image_name) { + Ok(n) => { + // TODO: save to somewhere + // TODO: check if a name is not valid, values outside ascii, + // remember that if a string is vaid, the rest of the name is 0 + found_valid = true; + println!("_EPROCESS at 0x{:x} of {}", eprocess, n); + }, + _ => {} + }; + } + if !found_valid { + println!("Not an eprocess maybe"); + } + } + }, + _ => {} + }; + } + + fn deref_addr(&self, addr: u64, outbuf: &mut T) { + let code = DriverAction::DereferenceAddress.get_code(); + let size: usize = size_of_val(outbuf); + let mut input = InputData { + deref_addr: DerefAddr { + addr, + size: size as u64 + } + }; + // unsafe { println!("Dereference {} bytes at 0x{:x}", input.deref_addr.size, input.deref_addr.addr) }; + self.windows_ffi.device_io(code, &mut input, outbuf); + } + + fn deref_addr_ptr(&self, addr: u64, outptr: *mut T, output_len: u64) { + let code = DriverAction::DereferenceAddress.get_code(); + let mut input = InputData { + deref_addr: DerefAddr { + addr, + size: output_len + } + }; + self.windows_ffi.device_io_raw(code, + &mut input as *mut _ as *mut c_void, size_of_val(&input) as DWORD, + outptr as *mut c_void, output_len as DWORD); + } + + #[allow(dead_code)] + fn get_nonpaged_range(&mut self) { + // TODO: Add support for other Windows version here + match self.windows_ffi.short_version { + WindowsVersion::Windows10FastRing => { + let mistate = self.ntosbase + self.pdb_store.get_offset("MiState").unwrap_or(0u64); + let system_node_ptr = self.pdb_store.addr_decompose( + mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") + .unwrap_or(0u64); + let mut system_node_addr = 0u64; + self.deref_addr(system_node_ptr, &mut system_node_addr); + + let mut first_va = 0u64; + let mut last_va = 0u64; + self.deref_addr( + system_node_addr + self.pdb_store.get_offset( + "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64), + &mut first_va); + + self.deref_addr( + system_node_addr + self.pdb_store.get_offset( + "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64), + &mut last_va); + + self.nonpaged_range[0] = first_va; + self.nonpaged_range[1] = last_va; + } + _ => {} + }; + println!("Nonpaged pool range: 0x{:x} - 0x{:x}", self.nonpaged_range[0], self.nonpaged_range[1]); + } +} diff --git a/src/ioctl_protocol.rs b/src/ioctl_protocol.rs new file mode 100644 index 0000000..82f5ac7 --- /dev/null +++ b/src/ioctl_protocol.rs @@ -0,0 +1,95 @@ +use crate::pdb_store::PdbStore; +use crate::windows::WindowsVersion; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct OffsetData { + eprocess_name_offset: u64, + eprocess_link_offset: u64, + list_blink_offset: u64, + process_head_offset: u64, + mistate_offset: u64, + hardware_offset: u64, + system_node_offset: u64, + first_va_offset: u64, + last_va_offset: u64, + large_page_table_offset: u64, + large_page_size_offset: u64, + pool_chunk_size: u64, +} + +// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version +impl OffsetData { + pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self { + match windows_version { + WindowsVersion::Windows10FastRing => Self { + eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64), + eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64), + list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64), + process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64), + mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64), + hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64), + system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool").unwrap_or(0u64), + first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64), + last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64), + large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64), + large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64), + pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64), + }, + // TODO: Add other version of Windows here + _ => Self { + eprocess_name_offset: 0u64, + eprocess_link_offset: 0u64, + list_blink_offset: 0u64, + process_head_offset: 0u64, + mistate_offset: 0u64, + hardware_offset: 0u64, + system_node_offset: 0u64, + first_va_offset: 0u64, + last_va_offset: 0u64, + large_page_table_offset: 0u64, + large_page_size_offset: 0u64, + pool_chunk_size: 0u64, + } + } + } +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DerefAddr { + pub addr: u64, + pub size: u64 +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ScanRange { + pub start: u64, + pub end: u64 +} + +impl ScanRange { + pub fn new(arr: &[u64; 2]) -> Self { + Self { + start: arr[0], + end: arr[1] + } + } +} + +#[repr(C)] +pub union InputData { + pub offset_value: OffsetData, + pub deref_addr: DerefAddr, + pub scan_range: ScanRange, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Nothing; // for empty data + +#[repr(C)] +pub union OutputData { + pub nothing: Nothing, +} diff --git a/src/main.rs b/src/main.rs index 01f5a15..3b7b573 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,25 @@ mod pdb_store; mod windows; +mod ioctl_protocol; +mod driver_state; + +use pdb_store::parse_pdb; +use windows::WindowsFFI; +use driver_state::{DriverState, DriverAction}; fn main() { - let store = pdb_store::parse_pdb(); - store.print_default_information(); - // for windows admin require // https://github.com/nabijaczleweli/rust-embed-resource - let mut windows_ffi = windows::WindowsFFI::new(); - windows_ffi.print_version(); - println!("NtLoadDriver() -> 0x{:x}", windows_ffi.load_driver()); + let mut driver = DriverState::new(parse_pdb(), WindowsFFI::new()); - windows_ffi.device_io(0x900); + println!("NtLoadDriver() -> 0x{:x}", driver.startup()); - println!("NtUnloadDriver() -> 0x{:x}", windows_ffi.unload_driver()); + driver.interact(DriverAction::SetupOffset); + driver.interact(DriverAction::GetKernelBase); + // driver.interact(DriverAction::ScanPsActiveHead); + // driver.interact(DriverAction::ScanPool); + driver.interact(DriverAction::ScanPoolRemote); + + println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); } diff --git a/src/windows.rs b/src/windows.rs index 30496f6..0300b27 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,5 +1,5 @@ -use std::ffi::CString; -use std::mem::transmute; +use std::ffi::{c_void, CString}; +use std::mem::{transmute, size_of_val}; use std::ptr::null_mut; use widestring::U16CString; @@ -12,7 +12,8 @@ use winapi::um::winnt::{ FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE }; -use winapi::um::ioapiset::DeviceIoControl; +use winapi::um::ioapiset::{DeviceIoControl}; +use winapi::um::errhandlingapi::{GetLastError}; use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS}; use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle}; use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress}; @@ -24,7 +25,7 @@ use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCA const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa"; #[allow(dead_code)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum WindowsVersion { Windows10_2015, Windows10_2016, @@ -37,6 +38,7 @@ pub enum WindowsVersion { } #[allow(dead_code)] +#[derive(Copy, Clone)] pub struct WindowsFFI { pub version_info: OSVERSIONINFOW, pub short_version: WindowsVersion, @@ -148,7 +150,7 @@ impl WindowsFFI { Self { version_info, short_version, - driver_handle: null_mut(), + driver_handle: INVALID_HANDLE_VALUE, ntdll, nt_load_driver, nt_unload_driver, @@ -157,7 +159,13 @@ impl WindowsFFI { } } + pub fn driver_loaded(self) -> bool { + self.driver_handle != INVALID_HANDLE_VALUE + } + pub fn load_driver(&mut self) -> NTSTATUS { + // TODO: Move this to new() + // If we move this function to new(), self.driver_handle will be init, and thus no mut here let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap(); let mut str_driver_reg_unicode = UNICODE_STRING::default(); (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); @@ -180,7 +188,7 @@ impl WindowsFFI { status } - pub fn unload_driver(&mut self) -> NTSTATUS { + pub fn unload_driver(&self) -> NTSTATUS { let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap(); let mut str_driver_reg_unicode = UNICODE_STRING::default(); (self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr()); @@ -202,10 +210,37 @@ impl WindowsFFI { ); } - #[allow(dead_code)] - pub fn device_io(&self, _code: DWORD) { + pub fn device_io(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD { + // input_ptr: *mut c_void, input_len: DWORD, output_ptr: *mut c_void, output_len: DWORD) { + // println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code); + // TODO: call device_io_raw + let mut bytes_returned: DWORD = 0; unsafe { - DeviceIoControl(self.driver_handle, 0x900, null_mut(), 0, null_mut(), 0, null_mut(), null_mut()); - } + let status = DeviceIoControl(self.driver_handle, code, + inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD, + outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD, + &mut bytes_returned, null_mut()); + if status == 0 { + println!("device io failed: last error {}", GetLastError()); + } + }; + bytes_returned + } + + pub fn device_io_raw(&self, code: DWORD, + input_ptr: *mut c_void, input_len: DWORD, + output_ptr: *mut c_void, output_len: DWORD) -> DWORD { + // println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code); + let mut bytes_returned: DWORD = 0; + unsafe { + let status = DeviceIoControl(self.driver_handle, code, + input_ptr, input_len, + output_ptr, output_len, + &mut bytes_returned, null_mut()); + if status == 0 { + println!("device io failed: last error {}", GetLastError()); + } + }; + bytes_returned } } From d0c0161b06ce4c9b262c30554c634e10989a42ff Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Thu, 27 Feb 2020 08:25:39 +0700 Subject: [PATCH 5/9] find eprocess offset base on CreateTime --- Cargo.toml | 2 +- src/driver_state.rs | 92 ++++++++++++++++++++++++++++----------------- src/main.rs | 19 +++++++++- src/windows.rs | 39 ++++++++++++------- 4 files changed, 101 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6edb2a4..16ac852 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,5 @@ edition = "2018" hex = "0.4.2" pdb = "0.5.0" widestring = "0.4.0" -winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset", "winioctl", "errhandlingapi"] } +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"] } diff --git a/src/driver_state.rs b/src/driver_state.rs index 68caec0..bf19ad3 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -41,12 +41,27 @@ impl DriverAction { } } +#[derive(Debug)] +pub struct EprocessPoolChunk { + pub pool_addr: u64, + pub eprocess_addr: u64, + pub eprocess_name: String +} + +impl PartialEq for EprocessPoolChunk { + fn eq(&self, other: &Self) -> bool { + self.eprocess_addr == other.eprocess_addr + } +} + #[allow(dead_code)] pub struct DriverState { pdb_store: PdbStore, windows_ffi: WindowsFFI, ntosbase: u64, nonpaged_range: [u64; 2], + pub eprocess_traverse_result: Vec, + pub pool_scan_result: Vec } impl DriverState { @@ -57,7 +72,9 @@ impl DriverState { pdb_store, windows_ffi, ntosbase: 0u64, - nonpaged_range: [0, 0] + nonpaged_range: [0, 0], + eprocess_traverse_result: Vec::new(), + pool_scan_result: Vec::new() } } @@ -94,8 +111,8 @@ impl DriverState { let mut ptr = ps_active_head; self.deref_addr(ptr + flink_offset, &mut ptr); - println!("========================"); - println!("Scan PsActiveProcessHead"); + // println!("========================"); + // println!("Scan PsActiveProcessHead"); while ptr != ps_active_head { let mut image_name = [0u8; 15]; let eprocess = ptr - eprocess_link_offset; @@ -103,13 +120,18 @@ impl DriverState { match std::str::from_utf8(&image_name) { Ok(n) => { // TODO: save to somewhere - println!("_EPROCESS at 0x{:x} of {}", eprocess, n); + // println!("_EPROCESS at 0x{:x} of {}", eprocess, n); + self.eprocess_traverse_result.push(EprocessPoolChunk { + pool_addr: 0, + eprocess_addr: eprocess, + eprocess_name: n.to_string() + }); }, _ => {} }; self.deref_addr(ptr + flink_offset, &mut ptr); } - println!("========================"); + // println!("========================"); // test call to check result self.windows_ffi.device_io(code, &mut Nothing, &mut Nothing); @@ -128,6 +150,8 @@ impl DriverState { let pool_header_size = self.pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64); let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64); + let eprocess_create_time_offset = self.pdb_store.get_offset("_EPROCESS.CreateTime").unwrap_or(0u64); + let eprocess_size = self.pdb_store.get_offset("_EPROCESS.struct_size").unwrap_or(0u64); let mut ptr = start_address; while ptr < end_address { @@ -144,38 +168,38 @@ impl DriverState { let mut pool = vec![0u8; pool_header_size as usize]; self.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); // TODO: Use pdb to parse, bit mangling and stuff - println!("========================="); - println!("Pool at 0x{:x}", pool_addr); - println!("Previos Size: 0x{:x}", pool[0]); - println!("Pool index : {:x}", pool[1]); - println!("Block size : 0x{:x}", (pool[2] as u64) * 16u64); // CHUNK_SIZE = 16 - println!("Pool type : {}", pool[3]); - println!("Pool tag : {}", std::str::from_utf8(&pool[4..8]).unwrap()); + // println!("========================="); + // println!("Pool at 0x{:x}", pool_addr); + // println!("Previos Size: 0x{:x}", pool[0]); + // println!("Pool index : {:x}", pool[1]); + // println!("Block size : 0x{:x}", (pool[2] as u64) * 16u64); // CHUNK_SIZE = 16 + // println!("Pool type : {}", pool[3]); + // println!("Pool tag : {}", std::str::from_utf8(&pool[4..8]).unwrap()); let pool_size = (pool[2] as u64) * 16u64; - // dump pool here - let eprocess_offset: Vec = match pool_size { - 0xf00 => vec![0x40], - 0xd80 => vec![0x40, 0x70, 0x80], - 0xe00 => vec![0x60, 0x70, 0x80, 0x90], - _ => vec![] - }; - // let eprocess_offset: Vec = vec![0x40, 0x70, 0x80]; + let eprocess_valid_start = pool_addr + pool_header_size; + let eprocess_valid_end = pool_addr + pool_size - eprocess_size; let mut found_valid = false; - for &offset in &eprocess_offset { - let eprocess = pool_addr + offset; - let mut image_name = [0u8; 15]; - self.deref_addr(eprocess + eprocess_name_offset, &mut image_name); - match std::str::from_utf8(&image_name) { - Ok(n) => { - // TODO: save to somewhere - // TODO: check if a name is not valid, values outside ascii, - // remember that if a string is vaid, the rest of the name is 0 - found_valid = true; - println!("_EPROCESS at 0x{:x} of {}", eprocess, n); - }, - _ => {} - }; + let mut try_eprocess_ptr = eprocess_valid_start; + + while !found_valid || try_eprocess_ptr < eprocess_valid_end { + let mut create_time = 0u64; + self.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time); + if self.windows_ffi.valid_process_time(create_time) { + found_valid = true; + let mut image_name = [0u8; 15]; + self.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); + // println!("_EPROCESS at 0x{:x} of {}", + // try_eprocess_ptr, std::str::from_utf8(&image_name).unwrap()); + // TODO: save result + self.pool_scan_result.push(EprocessPoolChunk { + pool_addr, + eprocess_addr: try_eprocess_ptr, + eprocess_name: std::str::from_utf8(&image_name).unwrap().to_string() + }); + break; + } + try_eprocess_ptr += 0x4; // search exhaustively } if !found_valid { println!("Not an eprocess maybe"); diff --git a/src/main.rs b/src/main.rs index 3b7b573..58977a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,9 +17,24 @@ fn main() { driver.interact(DriverAction::SetupOffset); driver.interact(DriverAction::GetKernelBase); - // driver.interact(DriverAction::ScanPsActiveHead); - // driver.interact(DriverAction::ScanPool); + driver.interact(DriverAction::ScanPsActiveHead); driver.interact(DriverAction::ScanPoolRemote); + println!("PsActiveProcessHead traversal"); + println!("- [is in scan list?] eprocess_addr eprocess_name"); + for result in &driver.eprocess_traverse_result { + println!("- [{}] 0x{:x} {}", + driver.pool_scan_result.contains(&result), + result.eprocess_addr, result.eprocess_name.trim_end_matches(char::from(0))); + } + + println!("Pool tag (quick) scanning"); + println!("- [is in pslist?] pool_addr eprocess_addr eprocess_name"); + for result in &driver.pool_scan_result { + println!("- [{}] 0x{:x} 0x{:x} {}", + driver.eprocess_traverse_result.contains(&result), + result.pool_addr, result.eprocess_addr, result.eprocess_name.trim_end_matches(char::from(0))); + } + println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); } diff --git a/src/windows.rs b/src/windows.rs index 0300b27..5f96b4b 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,6 +1,7 @@ use std::ffi::{c_void, CString}; use std::mem::{transmute, size_of_val}; use std::ptr::null_mut; +use std::time::{SystemTime, UNIX_EPOCH}; use widestring::U16CString; use winapi::shared::ntdef::*; @@ -18,6 +19,7 @@ use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS}; use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle}; use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress}; use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; +use winapi::um::sysinfoapi::{GetTickCount64}; use winapi::um::securitybaseapi::{AdjustTokenPrivileges}; use winapi::um::winbase::{LookupPrivilegeValueA}; use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE}; @@ -210,21 +212,30 @@ impl WindowsFFI { ); } + pub fn valid_process_time(&self, filetime: u64) -> bool { + // https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ + let windows_epoch_diff = 11644473600000 * 10000; + if filetime < windows_epoch_diff { + return false; + } + let system_up_time_ms = unsafe { GetTickCount64() }; + let process_time_epoch = (filetime - windows_epoch_diff) / 10000; + 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; + + if process_time_epoch < system_start_up_time_ms { + false + } else if process_time_epoch > now_ms { + false + } else { + true + } + } + pub fn device_io(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD { - // input_ptr: *mut c_void, input_len: DWORD, output_ptr: *mut c_void, output_len: DWORD) { - // println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code); - // TODO: call device_io_raw - let mut bytes_returned: DWORD = 0; - unsafe { - let status = DeviceIoControl(self.driver_handle, code, - inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD, - outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD, - &mut bytes_returned, null_mut()); - if status == 0 { - println!("device io failed: last error {}", GetLastError()); - } - }; - bytes_returned + self.device_io_raw(code, + inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD, + outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD) } pub fn device_io_raw(&self, code: DWORD, From 862a5c0788026172107c452314310bc3639d6992 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Thu, 27 Feb 2020 23:37:04 +0700 Subject: [PATCH 6/9] hide process call --- src/driver_state.rs | 33 +++++++++++++++++++++++++++------ src/ioctl_protocol.rs | 8 ++++++++ src/main.rs | 7 +++++-- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/driver_state.rs b/src/driver_state.rs index bf19ad3..43984d0 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -11,7 +11,7 @@ use winapi::um::winioctl::{ use crate::pdb_store::{PdbStore}; use crate::windows::{WindowsFFI, WindowsVersion}; use crate::ioctl_protocol::{ - InputData, OffsetData, DerefAddr, ScanRange, + InputData, OffsetData, DerefAddr, ScanRange, HideProcess, OutputData, Nothing }; @@ -25,7 +25,8 @@ pub enum DriverAction { ScanPsActiveHead, ScanPool, ScanPoolRemote, - DereferenceAddress + DereferenceAddress, + HideProcess } impl DriverAction { @@ -36,7 +37,8 @@ impl DriverAction { DriverAction::ScanPsActiveHead => CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS), DriverAction::ScanPool => CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS), DriverAction::ScanPoolRemote => CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS), - DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS), + DriverAction::HideProcess => CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS) } } } @@ -124,7 +126,9 @@ impl DriverState { self.eprocess_traverse_result.push(EprocessPoolChunk { pool_addr: 0, eprocess_addr: eprocess, - eprocess_name: n.to_string() + eprocess_name: n.to_string().trim_end_matches(char::from(0)) + .to_string() + }); }, _ => {} @@ -190,12 +194,14 @@ impl DriverState { let mut image_name = [0u8; 15]; self.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); // println!("_EPROCESS at 0x{:x} of {}", - // try_eprocess_ptr, std::str::from_utf8(&image_name).unwrap()); + // try_eprocess_ptr, std::str::from_utf8(&image_name).unwrap()); // TODO: save result self.pool_scan_result.push(EprocessPoolChunk { pool_addr, eprocess_addr: try_eprocess_ptr, - eprocess_name: std::str::from_utf8(&image_name).unwrap().to_string() + eprocess_name: std::str::from_utf8(&image_name).unwrap() + .to_string().trim_end_matches(char::from(0)) + .to_string() }); break; } @@ -206,6 +212,21 @@ impl DriverState { } } }, + DriverAction::HideProcess => { + let s = String::from("notepad.exe"); + let s_bytes = s.as_bytes(); + let mut name = [0u8; 15]; + for i in 0..s.len() { + name[i] = s_bytes[i]; + }; + let mut input = InputData { + hide_process: HideProcess { + name, + size: s.len() as u64 + } + }; + self.windows_ffi.device_io(code, &mut input, &mut Nothing); + } _ => {} }; } diff --git a/src/ioctl_protocol.rs b/src/ioctl_protocol.rs index 82f5ac7..22bbf99 100644 --- a/src/ioctl_protocol.rs +++ b/src/ioctl_protocol.rs @@ -78,11 +78,19 @@ impl ScanRange { } } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct HideProcess { + pub name: [u8; 15], + pub size: u64 +} + #[repr(C)] pub union InputData { pub offset_value: OffsetData, pub deref_addr: DerefAddr, pub scan_range: ScanRange, + pub hide_process: HideProcess, } #[repr(C)] diff --git a/src/main.rs b/src/main.rs index 58977a3..7fbd2e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,9 @@ fn main() { driver.interact(DriverAction::SetupOffset); driver.interact(DriverAction::GetKernelBase); + + driver.interact(DriverAction::HideProcess); + driver.interact(DriverAction::ScanPsActiveHead); driver.interact(DriverAction::ScanPoolRemote); @@ -25,7 +28,7 @@ fn main() { for result in &driver.eprocess_traverse_result { println!("- [{}] 0x{:x} {}", driver.pool_scan_result.contains(&result), - result.eprocess_addr, result.eprocess_name.trim_end_matches(char::from(0))); + result.eprocess_addr, result.eprocess_name); } println!("Pool tag (quick) scanning"); @@ -33,7 +36,7 @@ fn main() { for result in &driver.pool_scan_result { println!("- [{}] 0x{:x} 0x{:x} {}", driver.eprocess_traverse_result.contains(&result), - result.pool_addr, result.eprocess_addr, result.eprocess_name.trim_end_matches(char::from(0))); + result.pool_addr, result.eprocess_addr, result.eprocess_name); } println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); From cbc3cb7e15665468e20681eb8af5310436f1c95d Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 4 May 2020 11:40:31 +0000 Subject: [PATCH 7/9] update new design in code call, no test build --- Cargo.lock | 31 +++++ Cargo.toml | 1 + src/driver_state.rs | 268 +++++++++++++++++------------------------- src/ioctl_protocol.rs | 12 +- src/main.rs | 120 +++++++++++++++---- 5 files changed, 245 insertions(+), 187 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b777d89..51d9981 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,16 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core-foundation" version = "0.6.4" @@ -416,6 +426,23 @@ dependencies = [ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num_cpus" version = "1.12.0" @@ -459,6 +486,7 @@ dependencies = [ name = "parse_pdb_for_offsets" version = "0.1.0" dependencies = [ + "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)", @@ -1081,6 +1109,7 @@ dependencies = [ "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" @@ -1125,6 +1154,8 @@ dependencies = [ "checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)" = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" diff --git a/Cargo.toml b/Cargo.toml index 16ac852..4fa6068 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] 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"] } diff --git a/src/driver_state.rs b/src/driver_state.rs index 43984d0..d6b38d7 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -17,6 +17,15 @@ use crate::ioctl_protocol::{ const SIOCTL_TYPE: DWORD = 40000; +fn to_epoch(filetime: u64) -> u64 { + let windows_epoch_diff: u64 = 11644473600000 * 10000; + if filetime < windows_epoch_diff { + return 0; + } + let process_time_epoch: u64 = (filetime - windows_epoch_diff) / 10000; + process_time_epoch +} + #[allow(dead_code)] #[derive(Debug)] pub enum DriverAction { @@ -47,7 +56,9 @@ impl DriverAction { pub struct EprocessPoolChunk { pub pool_addr: u64, pub eprocess_addr: u64, - pub eprocess_name: String + pub eprocess_name: String, + pub create_time: u64, + pub exit_time: u64 } impl PartialEq for EprocessPoolChunk { @@ -58,12 +69,8 @@ impl PartialEq for EprocessPoolChunk { #[allow(dead_code)] pub struct DriverState { - pdb_store: PdbStore, + pub pdb_store: PdbStore, windows_ffi: WindowsFFI, - ntosbase: u64, - nonpaged_range: [u64; 2], - pub eprocess_traverse_result: Vec, - pub pool_scan_result: Vec } impl DriverState { @@ -82,156 +89,80 @@ impl DriverState { pub fn startup(&mut self) -> NTSTATUS { self.windows_ffi.load_driver() + let mut input = InputData { + offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version) + }; + self.windows_ffi.device_io(code, &mut input, &mut Nothing); } pub fn shutdown(&self) -> NTSTATUS { self.windows_ffi.unload_driver() } - // TODO: Function output and input data???? - pub fn interact(&mut self, action: DriverAction) { - let code = action.get_code(); - println!("Driver action: {:?}", action); - match action { - DriverAction::SetupOffset => { - let mut input = InputData { - offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version) - }; - self.windows_ffi.device_io(code, &mut input, &mut Nothing); - }, - DriverAction::GetKernelBase => { - self.windows_ffi.device_io(code, &mut Nothing, &mut self.ntosbase); - println!("ntosbase: 0x{:x}", self.ntosbase); - }, - DriverAction::ScanPsActiveHead => { - self.interact(DriverAction::GetKernelBase); - let ps_active_head = self.ntosbase + self.pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64); - let flink_offset = self.pdb_store.get_offset("_LIST_ENTRY.Flink").unwrap_or(0u64); - let eprocess_link_offset = self.pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64); - let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64); - - let mut ptr = ps_active_head; - self.deref_addr(ptr + flink_offset, &mut ptr); - - // println!("========================"); - // println!("Scan PsActiveProcessHead"); - 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) => { - // TODO: save to somewhere - // println!("_EPROCESS at 0x{:x} of {}", eprocess, n); - self.eprocess_traverse_result.push(EprocessPoolChunk { - pool_addr: 0, - eprocess_addr: eprocess, - eprocess_name: n.to_string().trim_end_matches(char::from(0)) - .to_string() - - }); - }, - _ => {} - }; - self.deref_addr(ptr + flink_offset, &mut ptr); - } - // println!("========================"); - - // test call to check result - self.windows_ffi.device_io(code, &mut Nothing, &mut Nothing); - }, - DriverAction::ScanPool => { - self.get_nonpaged_range(); - let mut input = InputData { - scan_range: ScanRange::new(&self.nonpaged_range) - }; - self.windows_ffi.device_io(code, &mut input, &mut Nothing); - }, - DriverAction::ScanPoolRemote => { - self.get_nonpaged_range(); - let start_address = self.nonpaged_range[0]; - let end_address = self.nonpaged_range[1]; - - let pool_header_size = self.pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64); - let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64); - let eprocess_create_time_offset = self.pdb_store.get_offset("_EPROCESS.CreateTime").unwrap_or(0u64); - let eprocess_size = self.pdb_store.get_offset("_EPROCESS.struct_size").unwrap_or(0u64); - - let mut ptr = start_address; - while ptr < end_address { - let mut input = InputData { - scan_range: ScanRange::new(&[ptr, end_address]) - }; - self.windows_ffi.device_io(code, &mut input, &mut ptr); - if ptr >= end_address { - break; - } - let pool_addr = ptr; - ptr += pool_header_size; - - let mut pool = vec![0u8; pool_header_size as usize]; - self.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); - // TODO: Use pdb to parse, bit mangling and stuff - // println!("========================="); - // println!("Pool at 0x{:x}", pool_addr); - // println!("Previos Size: 0x{:x}", pool[0]); - // println!("Pool index : {:x}", pool[1]); - // println!("Block size : 0x{:x}", (pool[2] as u64) * 16u64); // CHUNK_SIZE = 16 - // println!("Pool type : {}", pool[3]); - // println!("Pool tag : {}", std::str::from_utf8(&pool[4..8]).unwrap()); - - let pool_size = (pool[2] as u64) * 16u64; - let eprocess_valid_start = pool_addr + pool_header_size; - let eprocess_valid_end = pool_addr + pool_size - eprocess_size; - let mut found_valid = false; - let mut try_eprocess_ptr = eprocess_valid_start; - - while !found_valid || try_eprocess_ptr < eprocess_valid_end { - let mut create_time = 0u64; - self.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time); - if self.windows_ffi.valid_process_time(create_time) { - found_valid = true; - let mut image_name = [0u8; 15]; - self.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); - // println!("_EPROCESS at 0x{:x} of {}", - // try_eprocess_ptr, std::str::from_utf8(&image_name).unwrap()); - // TODO: save result - self.pool_scan_result.push(EprocessPoolChunk { - pool_addr, - eprocess_addr: try_eprocess_ptr, - eprocess_name: std::str::from_utf8(&image_name).unwrap() - .to_string().trim_end_matches(char::from(0)) - .to_string() - }); - break; - } - try_eprocess_ptr += 0x4; // search exhaustively - } - if !found_valid { - println!("Not an eprocess maybe"); - } - } - }, - DriverAction::HideProcess => { - let s = String::from("notepad.exe"); - let s_bytes = s.as_bytes(); - let mut name = [0u8; 15]; - for i in 0..s.len() { - name[i] = s_bytes[i]; - }; - let mut input = InputData { - hide_process: HideProcess { - name, - size: s.len() as u64 - } - }; - self.windows_ffi.device_io(code, &mut input, &mut Nothing); - } - _ => {} - }; + pub fn get_kernel_base(&self) -> Result { + let mut ntosbase = 0u64; + self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(), + &mut Nothing, &mut ntosbase); + // println!("ntosbase: 0x{:x}", self.ntosbase); + Ok(ntosbase) } - fn deref_addr(&self, addr: u64, outbuf: &mut T) { + pub fn scan_active_head(&self, ntosbase: u64) -> Result, io::Error> { + let ps_active_head = ntosbase + self.pdb_store.get_offset("PsActiveProcessHead"); + let flink_offset = self.pdb_store.get_offset("_LIST_ENTRY.Flink"); + let eprocess_link_offset = self.pdb_store.get_offset("_EPROCESS.ActiveProcessLinks"); + let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName"); + + let mut ptr = ps_active_head; + self.deref_addr(ptr + flink_offset, &mut ptr); + + let mut result: Vec; + 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, ntosbase: u64, tag: [u8; 4], + handler: FnMut(&DriverState, u64) -> Result + ) -> Result { + let range = self.get_nonpaged_range(ntosbase); + let start_address = range[0]; + let end_address = range[1]; + let mut ptr = start_address; + while ptr < end_address { + let mut input = InputData { + scan_range: ScanPoolData::new(&[ptr, end_address], tag) + }; + self.windows_ffi.device_io(code, &mut input, &mut ptr); + if ptr >= end_address { + break; + } + handler(&self, ptr)?; + ptr += pool_header_size; + } + Ok(true) + } + + pub fn deref_addr(&self, addr: u64, outbuf: &mut T) { let code = DriverAction::DereferenceAddress.get_code(); let size: usize = size_of_val(outbuf); let mut input = InputData { @@ -244,7 +175,7 @@ impl DriverState { self.windows_ffi.device_io(code, &mut input, outbuf); } - fn deref_addr_ptr(&self, addr: u64, outptr: *mut T, output_len: u64) { + pub fn deref_addr_ptr(&self, addr: u64, outptr: *mut T, output_len: u64) { let code = DriverAction::DereferenceAddress.get_code(); let mut input = InputData { deref_addr: DerefAddr { @@ -257,15 +188,29 @@ impl DriverState { outptr as *mut c_void, output_len as DWORD); } - #[allow(dead_code)] - fn get_nonpaged_range(&mut self) { + pub fn get_unicode_string(&self, unicode_str_addr: u64) -> Result<&str, io::Error> { + let mut strlen: u16; + let mut bufaddr : u64; + let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset("_UNICODE_STRING.Buffer")?; + + self.defer_addr(unicode_str_addr, &mut strlen); + self.defer_addr(buffer_ptr, &mut bufaddr); + + let mut buf = vec![0u8; strlen as usize]; + dr.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen); + + prinln!("unicode string {?}", buf); + + Ok(str::from_utf8(&buf)?) + } + + pub fn get_nonpaged_range(&self, ntosbase: u64) -> Result<[u64; 2], io::Error> { // TODO: Add support for other Windows version here match self.windows_ffi.short_version { WindowsVersion::Windows10FastRing => { - let mistate = self.ntosbase + self.pdb_store.get_offset("MiState").unwrap_or(0u64); + let mistate = ntosbase + self.pdb_store.get_offset("MiState")?; let system_node_ptr = self.pdb_store.addr_decompose( - mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") - .unwrap_or(0u64); + mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool")?; let mut system_node_addr = 0u64; self.deref_addr(system_node_ptr, &mut system_node_addr); @@ -273,19 +218,20 @@ impl DriverState { let mut last_va = 0u64; self.deref_addr( system_node_addr + self.pdb_store.get_offset( - "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64), + "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")?, &mut first_va); self.deref_addr( system_node_addr + self.pdb_store.get_offset( - "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64), + "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")?, &mut last_va); - self.nonpaged_range[0] = first_va; - self.nonpaged_range[1] = last_va; + Ok([first_va, last_va]) } - _ => {} - }; - println!("Nonpaged pool range: 0x{:x} - 0x{:x}", self.nonpaged_range[0], self.nonpaged_range[1]); + _ => { + Err("Windows version for nonpaged pool algorithm is not implemented") + } + } } + } diff --git a/src/ioctl_protocol.rs b/src/ioctl_protocol.rs index 22bbf99..8e3c17a 100644 --- a/src/ioctl_protocol.rs +++ b/src/ioctl_protocol.rs @@ -64,16 +64,18 @@ pub struct DerefAddr { #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct ScanRange { +pub struct ScanPoolData { pub start: u64, - pub end: u64 + pub end: u64, + pub tag: [u8; 4] } -impl ScanRange { - pub fn new(arr: &[u64; 2]) -> Self { +impl ScanPoolData{ + pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self { Self { start: arr[0], - end: arr[1] + end: arr[1], + tag: tag } } } diff --git a/src/main.rs b/src/main.rs index 7fbd2e3..a951247 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,43 +1,121 @@ +extern crate chrono; + mod pdb_store; mod windows; mod ioctl_protocol; mod driver_state; +use chrono::prelude::DateTime; +use chrono::Utc; +use chrono::{Local, DateTime}; +use std::time::{SystemTime, UNIX_EPOCH, Duration}; + use pdb_store::parse_pdb; use windows::WindowsFFI; use driver_state::{DriverState, DriverAction}; -fn main() { +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::::from(d); + let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string(); + timestamp_str +} + +fn main() -> Result<(), io::Error> { // for windows admin require // https://github.com/nabijaczleweli/rust-embed-resource let mut driver = DriverState::new(parse_pdb(), WindowsFFI::new()); - println!("NtLoadDriver() -> 0x{:x}", driver.startup()); - driver.interact(DriverAction::SetupOffset); - driver.interact(DriverAction::GetKernelBase); + let ntosbase = driver.get_ntosbase()?; + let pool_header_size = driver.pdb_store.get_offset("_POOL_HEADER.struct_size")?; - driver.interact(DriverAction::HideProcess); + let eprocess_tag: [u8; 4] = [80, 114, 111, 99]; // Proc + let eprocess_name_offset = driver.pdb_store.get_offset("_EPROCESS.ImageFileName")?; + let eprocess_create_time_offset = driver.pdb_store.get_offset("_EPROCESS.CreateTime")?; + let eprocess_exit_time_offset = driver.pdb_store.get_offset("_EPROCESS.ExitTime")?; + let eprocess_size = driver.pdb_store.get_offset("_EPROCESS.struct_size")?; - driver.interact(DriverAction::ScanPsActiveHead); - driver.interact(DriverAction::ScanPoolRemote); + let eprocess_scan_head = driver.scan_active_head(ntosbase)?; + let mut eprocess_list: Vec; + driver.scan_pool(ntosbase, eprocess_tag, |dr, pool_addr| { + let mut pool = vec![0u8; pool_header_size as usize]; + dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); - println!("PsActiveProcessHead traversal"); - println!("- [is in scan list?] eprocess_addr eprocess_name"); - for result in &driver.eprocess_traverse_result { - println!("- [{}] 0x{:x} {}", - driver.pool_scan_result.contains(&result), - result.eprocess_addr, result.eprocess_name); - } + let pool_size = (pool[2] as u64) * 16u64; + let eprocess_valid_start = pool_addr + pool_header_size; + let eprocess_valid_end = pool_addr + pool_size - eprocess_size; + let mut try_eprocess_ptr = eprocess_valid_start; - println!("Pool tag (quick) scanning"); - println!("- [is in pslist?] pool_addr eprocess_addr eprocess_name"); - for result in &driver.pool_scan_result { - println!("- [{}] 0x{:x} 0x{:x} {}", - driver.eprocess_traverse_result.contains(&result), - result.pool_addr, result.eprocess_addr, result.eprocess_name); - } + let mut create_time = 0u64; + let mut exit_time = 0u64; + while try_eprocess_ptr <= eprocess_valid_end { + dr.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time); + dr.deref_addr(try_eprocess_ptr + eprocess_exit_time_offset, &mut exit_time); + if dr.windows_ffi.valid_process_time(create_time) { + break; + } + try_eprocess_ptr += 0x4; // search exhaustively + } + let mut image_name = [0u8; 15]; + dr.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); + let eprocess_name = std::str::from_utf8(&image_name)? + .to_string() + .trim_end_matches(char::from(0)) + .to_string(); + 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(try_eprocess_ptr <= eprocess_valid_end) + }); + + let ethread_tag: [u8; 4] = [84, 104, 114, 101]; // Thre + let ethread_create_time_offset = driver.pdb_store.get_offset("_ETHREAD.CreateTime")?; + let ethread_exit_time_offset = driver.pdb_store.get_offset("_ETHREAD.ExitTime")?; + let ethread_threadname_offset = driver.pdb_store.get_offset("_ETHREAD.TheadName")?; + let ethread_size = driver.pdb_store.get_offset("_ETHREAD.struct_size")?; + + // let mut ethread_list: Vec; + driver.scan_pool(ntosbase, ethread_tag, |dr, pool_addr| { + let mut pool = vec![0u8; pool_header_size as usize]; + dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); + + let pool_size = (pool[2] as u64) * 16u64; + let ethread_valid_start = pool_addr + pool_header_size; + let ethread_valid_end = pool_addr + pool_size - ethread_size; + let mut try_ethread_ptr = ethread_valid_start; + + let mut create_time = 0u64; + let mut exit_time = 0u64; + while try_ethread_ptr <= ethread_valid_end { + dr.deref_addr(try_ethread_ptr + ethread_create_time_offset, &mut create_time); + dr.deref_addr(try_ethread_ptr + ethread_exit_time_offset, &mut exit_time); + if dr.windows_ffi.valid_process_time(create_time) { + break; + } + try_ethread_ptr += 0x4; // search exhaustively + } + let mut threadname_ptr = 0u64; + dr.deref_addr(try_ethread_ptr + ethread_threadname_offset, &mut threadname_ptr); + let threadname = dr.get_unicode_string(threadname_ptr)? + println!("threadname: {}", threadname); + Ok(try_ethread_ptr <= ethread_valid_end) + }); + + // for result in &driver.eprocess_traverse_result { + // println!("- [{}] 0x{:x} {}", + // driver.pool_scan_result.contains(&result), + // result.eprocess_addr, result.eprocess_name); + // } println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); + Ok(()) } From 3214e79d63258270336eb5ce8c63b5b321909224 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 18 May 2020 04:04:40 +0700 Subject: [PATCH 8/9] code renew build ok --- src/driver_state.rs | 97 ++++++++++++++++++++++++------------------- src/ioctl_protocol.rs | 4 +- src/main.rs | 71 ++++++++++++++++--------------- src/pdb_store.rs | 15 ++++--- 4 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/driver_state.rs b/src/driver_state.rs index d6b38d7..70a87a6 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -1,3 +1,5 @@ +use std::error::Error; +// use std::io::{Error, ErrorKind}; use std::ffi::c_void; use std::mem::{size_of_val}; @@ -5,19 +7,21 @@ use winapi::shared::ntdef::{NTSTATUS}; use winapi::shared::minwindef::{DWORD}; use winapi::um::winioctl::{ CTL_CODE, FILE_ANY_ACCESS, - METHOD_IN_DIRECT, METHOD_OUT_DIRECT, METHOD_BUFFERED, METHOD_NEITHER + METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER }; use crate::pdb_store::{PdbStore}; use crate::windows::{WindowsFFI, WindowsVersion}; use crate::ioctl_protocol::{ - InputData, OffsetData, DerefAddr, ScanRange, HideProcess, - OutputData, Nothing + InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */ + /* OutputData, */ Nothing }; +type BoxResult = Result>; + const SIOCTL_TYPE: DWORD = 40000; -fn to_epoch(filetime: u64) -> u64 { +pub fn to_epoch(filetime: u64) -> u64 { let windows_epoch_diff: u64 = 11644473600000 * 10000; if filetime < windows_epoch_diff { return 0; @@ -69,8 +73,9 @@ impl PartialEq for EprocessPoolChunk { #[allow(dead_code)] pub struct DriverState { + // TODO: Make private, only call methods of DriverState pub pdb_store: PdbStore, - windows_ffi: WindowsFFI, + pub windows_ffi: WindowsFFI, } impl DriverState { @@ -79,27 +84,25 @@ impl DriverState { windows_ffi.print_version(); Self { pdb_store, - windows_ffi, - ntosbase: 0u64, - nonpaged_range: [0, 0], - eprocess_traverse_result: Vec::new(), - pool_scan_result: Vec::new() + windows_ffi } } pub fn startup(&mut self) -> NTSTATUS { - self.windows_ffi.load_driver() + let s = self.windows_ffi.load_driver(); let mut input = InputData { offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version) }; - self.windows_ffi.device_io(code, &mut input, &mut Nothing); + self.windows_ffi.device_io(DriverAction::SetupOffset.get_code(), + &mut input, &mut Nothing); + s } pub fn shutdown(&self) -> NTSTATUS { self.windows_ffi.unload_driver() } - pub fn get_kernel_base(&self) -> Result { + pub fn get_kernel_base(&self) -> BoxResult { let mut ntosbase = 0u64; self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(), &mut Nothing, &mut ntosbase); @@ -107,16 +110,16 @@ impl DriverState { Ok(ntosbase) } - pub fn scan_active_head(&self, ntosbase: u64) -> Result, io::Error> { - let ps_active_head = ntosbase + self.pdb_store.get_offset("PsActiveProcessHead"); - let flink_offset = self.pdb_store.get_offset("_LIST_ENTRY.Flink"); - let eprocess_link_offset = self.pdb_store.get_offset("_EPROCESS.ActiveProcessLinks"); - let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName"); + pub fn scan_active_head(&self, ntosbase: u64) -> BoxResult> { + 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, &mut ptr); - let mut result: Vec; + let mut result: Vec = Vec::new(); while ptr != ps_active_head { let mut image_name = [0u8; 15]; let eprocess = ptr - eprocess_link_offset; @@ -141,23 +144,33 @@ impl DriverState { Ok(result) } - pub fn scan_pool(&self, ntosbase: u64, tag: [u8; 4], - handler: FnMut(&DriverState, u64) -> Result - ) -> Result { - let range = self.get_nonpaged_range(ntosbase); + pub fn scan_pool(&self, ntosbase: u64, tag: [u8; 4], mut handler: F) -> BoxResult + where F: FnMut(&DriverState, u64) -> BoxResult + { + let code = DriverAction::ScanPoolRemote.get_code(); + let range = self.get_nonpaged_range(ntosbase)?; let start_address = range[0]; let end_address = range[1]; let mut ptr = start_address; while ptr < end_address { let mut input = InputData { - scan_range: ScanPoolData::new(&[ptr, end_address], tag) + scan_range: ScanPoolData::new(&[ptr, end_address], &tag) }; self.windows_ffi.device_io(code, &mut input, &mut ptr); if ptr >= end_address { break; } - handler(&self, ptr)?; - ptr += pool_header_size; + ptr += match handler(&self, ptr) { + Ok(success) => { + if success { + } + else { + } + }, + Err(e) => println!("Handle error {:?}", e), + // found, ptr += chunk size + // ptr += pool_header_size; + }; } Ok(true) } @@ -188,27 +201,27 @@ impl DriverState { outptr as *mut c_void, output_len as DWORD); } - pub fn get_unicode_string(&self, unicode_str_addr: u64) -> Result<&str, io::Error> { - let mut strlen: u16; - let mut bufaddr : u64; - let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset("_UNICODE_STRING.Buffer")?; + pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult { + let mut strlen = 0u16; + let mut bufaddr = 0u64; + let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?; - self.defer_addr(unicode_str_addr, &mut strlen); - self.defer_addr(buffer_ptr, &mut bufaddr); + self.deref_addr(unicode_str_addr, &mut strlen); + self.deref_addr(buffer_ptr, &mut bufaddr); let mut buf = vec![0u8; strlen as usize]; - dr.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen); + self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64); - prinln!("unicode string {?}", buf); + println!("unicode string {:?}", buf); - Ok(str::from_utf8(&buf)?) + Ok(std::str::from_utf8(&buf)?.to_string()) } - pub fn get_nonpaged_range(&self, ntosbase: u64) -> Result<[u64; 2], io::Error> { + pub fn get_nonpaged_range(&self, ntosbase: u64) -> BoxResult<[u64; 2]> { // TODO: Add support for other Windows version here match self.windows_ffi.short_version { WindowsVersion::Windows10FastRing => { - let mistate = ntosbase + self.pdb_store.get_offset("MiState")?; + let mistate = ntosbase + self.pdb_store.get_offset_r("MiState")?; let system_node_ptr = self.pdb_store.addr_decompose( mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool")?; let mut system_node_addr = 0u64; @@ -217,19 +230,19 @@ impl DriverState { let mut first_va = 0u64; let mut last_va = 0u64; self.deref_addr( - system_node_addr + self.pdb_store.get_offset( - "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")?, + system_node_addr + + self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")?, &mut first_va); self.deref_addr( - system_node_addr + self.pdb_store.get_offset( - "_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")?, + system_node_addr + + self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")?, &mut last_va); Ok([first_va, last_va]) } _ => { - Err("Windows version for nonpaged pool algorithm is not implemented") + Err("Windows version for nonpaged pool algorithm is not implemented".into()) } } } diff --git a/src/ioctl_protocol.rs b/src/ioctl_protocol.rs index 8e3c17a..18cba43 100644 --- a/src/ioctl_protocol.rs +++ b/src/ioctl_protocol.rs @@ -75,7 +75,7 @@ impl ScanPoolData{ Self { start: arr[0], end: arr[1], - tag: tag + tag: *tag } } } @@ -91,7 +91,7 @@ pub struct HideProcess { pub union InputData { pub offset_value: OffsetData, pub deref_addr: DerefAddr, - pub scan_range: ScanRange, + pub scan_range: ScanPoolData, pub hide_process: HideProcess, } diff --git a/src/main.rs b/src/main.rs index a951247..634bc5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,50 +5,53 @@ mod windows; mod ioctl_protocol; mod driver_state; -use chrono::prelude::DateTime; -use chrono::Utc; -use chrono::{Local, DateTime}; -use std::time::{SystemTime, UNIX_EPOCH, Duration}; +use std::error::Error; +use std::str::{from_utf8}; +// use chrono::prelude::DateTime; +// use chrono::Utc; +// use chrono::{Local, DateTime}; +// use std::time::{SystemTime, UNIX_EPOCH, Duration}; use pdb_store::parse_pdb; use windows::WindowsFFI; -use driver_state::{DriverState, DriverAction}; +use driver_state::{DriverState, EprocessPoolChunk, to_epoch}; -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::::from(d); - let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string(); - timestamp_str +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::::from(d); + // let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string(); + // timestamp_str + "".to_string() } -fn main() -> Result<(), io::Error> { +fn main() -> Result<(), Box> { // for windows admin require // https://github.com/nabijaczleweli/rust-embed-resource let mut driver = DriverState::new(parse_pdb(), WindowsFFI::new()); println!("NtLoadDriver() -> 0x{:x}", driver.startup()); - let ntosbase = driver.get_ntosbase()?; - let pool_header_size = driver.pdb_store.get_offset("_POOL_HEADER.struct_size")?; + let ntosbase = driver.get_kernel_base()?; + let pool_header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?; let eprocess_tag: [u8; 4] = [80, 114, 111, 99]; // Proc - let eprocess_name_offset = driver.pdb_store.get_offset("_EPROCESS.ImageFileName")?; - let eprocess_create_time_offset = driver.pdb_store.get_offset("_EPROCESS.CreateTime")?; - let eprocess_exit_time_offset = driver.pdb_store.get_offset("_EPROCESS.ExitTime")?; - let eprocess_size = driver.pdb_store.get_offset("_EPROCESS.struct_size")?; + let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?; + let eprocess_create_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.CreateTime")?; + let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?; + let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?; let eprocess_scan_head = driver.scan_active_head(ntosbase)?; - let mut eprocess_list: Vec; + let mut eprocess_list: Vec = Vec::new(); driver.scan_pool(ntosbase, eprocess_tag, |dr, pool_addr| { let mut pool = vec![0u8; pool_header_size as usize]; dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); - let pool_size = (pool[2] as u64) * 16u64; + let chunk_size = (pool[2] as u64) * 16u64; let eprocess_valid_start = pool_addr + pool_header_size; - let eprocess_valid_end = pool_addr + pool_size - eprocess_size; + let eprocess_valid_end = pool_addr + chunk_size - eprocess_size; let mut try_eprocess_ptr = eprocess_valid_start; let mut create_time = 0u64; @@ -63,7 +66,7 @@ fn main() -> Result<(), io::Error> { } let mut image_name = [0u8; 15]; dr.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); - let eprocess_name = std::str::from_utf8(&image_name)? + let eprocess_name = from_utf8(&image_name)? .to_string() .trim_end_matches(char::from(0)) .to_string(); @@ -75,22 +78,22 @@ fn main() -> Result<(), io::Error> { exit_time: to_epoch(exit_time) }); Ok(try_eprocess_ptr <= eprocess_valid_end) - }); + })?; let ethread_tag: [u8; 4] = [84, 104, 114, 101]; // Thre - let ethread_create_time_offset = driver.pdb_store.get_offset("_ETHREAD.CreateTime")?; - let ethread_exit_time_offset = driver.pdb_store.get_offset("_ETHREAD.ExitTime")?; - let ethread_threadname_offset = driver.pdb_store.get_offset("_ETHREAD.TheadName")?; - let ethread_size = driver.pdb_store.get_offset("_ETHREAD.struct_size")?; + let ethread_create_time_offset = driver.pdb_store.get_offset_r("_ETHREAD.CreateTime")?; + let ethread_exit_time_offset = driver.pdb_store.get_offset_r("_ETHREAD.ExitTime")?; + let ethread_threadname_offset = driver.pdb_store.get_offset_r("_ETHREAD.TheadName")?; + let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?; - // let mut ethread_list: Vec; + // let mut ethread_list: Vec = Vec::new(); driver.scan_pool(ntosbase, ethread_tag, |dr, pool_addr| { let mut pool = vec![0u8; pool_header_size as usize]; dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); - let pool_size = (pool[2] as u64) * 16u64; + let chunk_size = (pool[2] as u64) * 16u64; let ethread_valid_start = pool_addr + pool_header_size; - let ethread_valid_end = pool_addr + pool_size - ethread_size; + let ethread_valid_end = pool_addr + chunk_size - ethread_size; let mut try_ethread_ptr = ethread_valid_start; let mut create_time = 0u64; @@ -105,10 +108,10 @@ fn main() -> Result<(), io::Error> { } let mut threadname_ptr = 0u64; dr.deref_addr(try_ethread_ptr + ethread_threadname_offset, &mut threadname_ptr); - let threadname = dr.get_unicode_string(threadname_ptr)? + let threadname = dr.get_unicode_string(threadname_ptr)?; println!("threadname: {}", threadname); Ok(try_ethread_ptr <= ethread_valid_end) - }); + })?; // for result in &driver.eprocess_traverse_result { // println!("- [{}] 0x{:x} {}", diff --git a/src/pdb_store.rs b/src/pdb_store.rs index 0514de4..f58a4be 100644 --- a/src/pdb_store.rs +++ b/src/pdb_store.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::io; use std::io::{Read}; use std::path::Path; @@ -29,6 +30,10 @@ pub struct PdbStore { } impl PdbStore { + pub fn get_offset_r(&self, name: &str) -> Result> { + self.get_offset(name) + .ok_or(format!("{} is not found in PDB", name).into()) + } #[allow(dead_code)] pub fn get_offset(&self, name: &str) -> Option { if name.contains(".") { @@ -52,9 +57,9 @@ impl PdbStore { } #[allow(dead_code)] - pub fn addr_decompose(&self, addr: u64, full_name: &str) -> Result{ + pub fn addr_decompose(&self, addr: u64, full_name: &str) -> Result>{ if !full_name.contains(".") { - return Err("Not decomposable".to_string()); + return Err("Not decomposable".into()); } let mut name_part: Vec<&str> = full_name.split_terminator('.').collect(); @@ -65,7 +70,7 @@ impl PdbStore { Some((memtype, offset)) => { if next.len() != 0 { if memtype.contains("*") { - return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1])); + return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1]).into()); } next.insert(0, memtype); self.addr_decompose(addr + *offset, &next.join(".")) @@ -74,10 +79,10 @@ impl PdbStore { Ok(addr + *offset) } }, - None => Err(format!("Not found member {}", name_part[1])) + None => Err(format!("Not found member {}", name_part[1]).into()) } }, - None => Err(format!("Struct {} not found", name_part[0])) + None => Err(format!("Struct {} not found", name_part[0]).into()) } } From dae10a5312cbde9a0589276d4f834b8ea68b81ae Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Tue, 19 May 2020 03:52:18 +0700 Subject: [PATCH 9/9] multiple binary and code refactor --- Cargo.lock | 24 ++++---- Cargo.toml | 8 ++- src/bin/eprocess_scan.rs | 73 +++++++++++++++++++++++ src/bin/print_pdb.rs | 12 ++++ src/driver_state.rs | 46 ++++++++------- src/ioctl_protocol.rs | 4 +- src/lib.rs | 7 +++ src/main.rs | 124 --------------------------------------- src/pdb_store.rs | 10 +++- 9 files changed, 146 insertions(+), 162 deletions(-) create mode 100644 src/bin/eprocess_scan.rs create mode 100644 src/bin/print_pdb.rs create mode 100644 src/lib.rs delete mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 51d9981..c6561a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,6 +337,18 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lpus" +version = "0.1.0" +dependencies = [ + "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)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "matches" version = "0.1.8" @@ -482,18 +494,6 @@ dependencies = [ "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parse_pdb_for_offsets" -version = "0.1.0" -dependencies = [ - "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)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pdb" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 4fa6068..2fbe7d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,14 @@ [package] -name = "parse_pdb_for_offsets" +name = "lpus" version = "0.1.0" authors = ["nganhkhoa "] +description = "Live pool tag scanning frontend" edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "lpus" +doctest = false [dependencies] hex = "0.4.2" diff --git a/src/bin/eprocess_scan.rs b/src/bin/eprocess_scan.rs new file mode 100644 index 0000000..718aae3 --- /dev/null +++ b/src/bin/eprocess_scan.rs @@ -0,0 +1,73 @@ +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 */} +}; + +#[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::::from(d); + let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string(); + timestamp_str +} + +fn main() -> Result<(), Box> { + // 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 = Vec::new(); + driver.scan_pool(b"Proc", |pool_addr, header, data_addr| { + let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?; + let eprocess_create_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.CreateTime")?; + let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?; + let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?; + + let chunk_size = (header[2] as u64) * 16u64; + let eprocess_valid_start = data_addr; + let eprocess_valid_end = pool_addr + chunk_size - eprocess_size; + let mut try_eprocess_ptr = eprocess_valid_start; + + let mut create_time = 0u64; + let mut exit_time = 0u64; + while try_eprocess_ptr <= eprocess_valid_end { + driver.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time); + driver.deref_addr(try_eprocess_ptr + eprocess_exit_time_offset, &mut exit_time); + // using heuristics to eliminate false positive + if driver.windows_ffi.valid_process_time(create_time) { + break; + } + try_eprocess_ptr += 0x4; // search exhaustively + } + let mut image_name = [0u8; 15]; + driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); + let eprocess_name = from_utf8(&image_name)? + .to_string() + .trim_end_matches(char::from(0)) + .to_string(); + // 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) + // }); + println!("pool: {} | eprocess: {}: {}", pool_addr, try_eprocess_ptr, eprocess_name); + Ok(try_eprocess_ptr <= eprocess_valid_end) + })?; + + println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); + Ok(()) +} + diff --git a/src/bin/print_pdb.rs b/src/bin/print_pdb.rs new file mode 100644 index 0000000..ba4ad91 --- /dev/null +++ b/src/bin/print_pdb.rs @@ -0,0 +1,12 @@ +use std::error::Error; + +use lpus::{ + driver_state::{DriverState} +}; + +fn main() -> Result<(), Box> { + let driver = DriverState::new(); + driver.windows_ffi.print_version(); + driver.pdb_store.print_default_information(); + Ok(()) +} diff --git a/src/driver_state.rs b/src/driver_state.rs index 70a87a6..6c03983 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -10,7 +10,7 @@ use winapi::um::winioctl::{ METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER }; -use crate::pdb_store::{PdbStore}; +use crate::pdb_store::{PdbStore, parse_pdb}; use crate::windows::{WindowsFFI, WindowsVersion}; use crate::ioctl_protocol::{ InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */ @@ -79,12 +79,10 @@ pub struct DriverState { } impl DriverState { - pub fn new(pdb_store: PdbStore, windows_ffi: WindowsFFI) -> Self { - pdb_store.print_default_information(); - windows_ffi.print_version(); + pub fn new() -> Self { Self { - pdb_store, - windows_ffi + pdb_store: parse_pdb(), + windows_ffi: WindowsFFI::new() } } @@ -102,12 +100,12 @@ impl DriverState { self.windows_ffi.unload_driver() } - pub fn get_kernel_base(&self) -> BoxResult { + pub fn get_kernel_base(&self) -> u64 { let mut ntosbase = 0u64; self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(), &mut Nothing, &mut ntosbase); // println!("ntosbase: 0x{:x}", self.ntosbase); - Ok(ntosbase) + ntosbase } pub fn scan_active_head(&self, ntosbase: u64) -> BoxResult> { @@ -144,9 +142,14 @@ impl DriverState { Ok(result) } - pub fn scan_pool(&self, ntosbase: u64, tag: [u8; 4], mut handler: F) -> BoxResult - where F: FnMut(&DriverState, u64) -> BoxResult + pub fn scan_pool(&self, tag: &[u8; 4], mut handler: F) -> BoxResult + where F: FnMut(u64, &[u8], u64) -> BoxResult + // F(Pool Address, Pool Header Data, Pool Data Address) + // TODO: Pool Header as a real struct { + let ntosbase = self.get_kernel_base(); + // TODO: check valid tag + let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?; let code = DriverAction::ScanPoolRemote.get_code(); let range = self.get_nonpaged_range(ntosbase)?; let start_address = range[0]; @@ -154,22 +157,23 @@ impl DriverState { let mut ptr = start_address; while ptr < end_address { let mut input = InputData { - scan_range: ScanPoolData::new(&[ptr, end_address], &tag) + scan_range: ScanPoolData::new(&[ptr, end_address], tag) }; self.windows_ffi.device_io(code, &mut input, &mut ptr); if ptr >= end_address { break; } - ptr += match handler(&self, ptr) { - Ok(success) => { - if success { - } - else { - } - }, - Err(e) => println!("Handle error {:?}", e), - // found, ptr += chunk size - // ptr += pool_header_size; + let pool_addr = ptr; + let mut header = vec![0u8; pool_header_size as usize]; + self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size); + + let success = handler(ptr, &header, pool_addr + pool_header_size)?; + if success { + let chunk_size = (header[2] as u64) * 16u64; + ptr += chunk_size /* pass this chunk */ + } + else { + ptr += 0x4 /* search next */ }; } Ok(true) diff --git a/src/ioctl_protocol.rs b/src/ioctl_protocol.rs index 18cba43..26113a5 100644 --- a/src/ioctl_protocol.rs +++ b/src/ioctl_protocol.rs @@ -67,7 +67,7 @@ pub struct DerefAddr { pub struct ScanPoolData { pub start: u64, pub end: u64, - pub tag: [u8; 4] + pub tag: u32 } impl ScanPoolData{ @@ -75,7 +75,7 @@ impl ScanPoolData{ Self { start: arr[0], end: arr[1], - tag: *tag + tag: u32::from_le_bytes(*tag) } } } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..cda8c7f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,7 @@ +extern crate chrono; + +pub mod pdb_store; +pub mod windows; +pub mod ioctl_protocol; +pub mod driver_state; + diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 634bc5d..0000000 --- a/src/main.rs +++ /dev/null @@ -1,124 +0,0 @@ -extern crate chrono; - -mod pdb_store; -mod windows; -mod ioctl_protocol; -mod driver_state; - -use std::error::Error; -use std::str::{from_utf8}; -// use chrono::prelude::DateTime; -// use chrono::Utc; -// use chrono::{Local, DateTime}; -// use std::time::{SystemTime, UNIX_EPOCH, Duration}; - -use pdb_store::parse_pdb; -use windows::WindowsFFI; -use driver_state::{DriverState, EprocessPoolChunk, to_epoch}; - -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::::from(d); - // let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string(); - // timestamp_str - "".to_string() -} - -fn main() -> Result<(), Box> { - // for windows admin require - // https://github.com/nabijaczleweli/rust-embed-resource - - let mut driver = DriverState::new(parse_pdb(), WindowsFFI::new()); - println!("NtLoadDriver() -> 0x{:x}", driver.startup()); - - let ntosbase = driver.get_kernel_base()?; - let pool_header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?; - - let eprocess_tag: [u8; 4] = [80, 114, 111, 99]; // Proc - let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?; - let eprocess_create_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.CreateTime")?; - let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?; - let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?; - - let eprocess_scan_head = driver.scan_active_head(ntosbase)?; - let mut eprocess_list: Vec = Vec::new(); - driver.scan_pool(ntosbase, eprocess_tag, |dr, pool_addr| { - let mut pool = vec![0u8; pool_header_size as usize]; - dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); - - let chunk_size = (pool[2] as u64) * 16u64; - let eprocess_valid_start = pool_addr + pool_header_size; - let eprocess_valid_end = pool_addr + chunk_size - eprocess_size; - let mut try_eprocess_ptr = eprocess_valid_start; - - let mut create_time = 0u64; - let mut exit_time = 0u64; - while try_eprocess_ptr <= eprocess_valid_end { - dr.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time); - dr.deref_addr(try_eprocess_ptr + eprocess_exit_time_offset, &mut exit_time); - if dr.windows_ffi.valid_process_time(create_time) { - break; - } - try_eprocess_ptr += 0x4; // search exhaustively - } - let mut image_name = [0u8; 15]; - dr.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name); - let eprocess_name = from_utf8(&image_name)? - .to_string() - .trim_end_matches(char::from(0)) - .to_string(); - 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(try_eprocess_ptr <= eprocess_valid_end) - })?; - - let ethread_tag: [u8; 4] = [84, 104, 114, 101]; // Thre - let ethread_create_time_offset = driver.pdb_store.get_offset_r("_ETHREAD.CreateTime")?; - let ethread_exit_time_offset = driver.pdb_store.get_offset_r("_ETHREAD.ExitTime")?; - let ethread_threadname_offset = driver.pdb_store.get_offset_r("_ETHREAD.TheadName")?; - let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?; - - // let mut ethread_list: Vec = Vec::new(); - driver.scan_pool(ntosbase, ethread_tag, |dr, pool_addr| { - let mut pool = vec![0u8; pool_header_size as usize]; - dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size); - - let chunk_size = (pool[2] as u64) * 16u64; - let ethread_valid_start = pool_addr + pool_header_size; - let ethread_valid_end = pool_addr + chunk_size - ethread_size; - let mut try_ethread_ptr = ethread_valid_start; - - let mut create_time = 0u64; - let mut exit_time = 0u64; - while try_ethread_ptr <= ethread_valid_end { - dr.deref_addr(try_ethread_ptr + ethread_create_time_offset, &mut create_time); - dr.deref_addr(try_ethread_ptr + ethread_exit_time_offset, &mut exit_time); - if dr.windows_ffi.valid_process_time(create_time) { - break; - } - try_ethread_ptr += 0x4; // search exhaustively - } - let mut threadname_ptr = 0u64; - dr.deref_addr(try_ethread_ptr + ethread_threadname_offset, &mut threadname_ptr); - let threadname = dr.get_unicode_string(threadname_ptr)?; - println!("threadname: {}", threadname); - Ok(try_ethread_ptr <= ethread_valid_end) - })?; - - // for result in &driver.eprocess_traverse_result { - // println!("- [{}] 0x{:x} {}", - // driver.pool_scan_result.contains(&result), - // result.eprocess_addr, result.eprocess_name); - // } - - println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); - Ok(()) -} diff --git a/src/pdb_store.rs b/src/pdb_store.rs index f58a4be..97dc398 100644 --- a/src/pdb_store.rs +++ b/src/pdb_store.rs @@ -299,7 +299,15 @@ pub fn download_pdb() { pub fn parse_pdb() -> PdbStore { // TODO: Detect pdb file and ntoskrnl file version differs - // The guid of ntoskrnl and pdb file are different + // Use a folder at %APPDATA% to save pdb files + // %APPDATA%\lpus + // |--ntoskrnl + // |--|--GUID + // |--|--|--ntkrnlmp.pdb + // |--file + // |--|--GUID + // |--|--|--file.pdb + // TODO: Turn function to Result to handle error if !Path::new(PDBNAME).exists() { download_pdb(); }