find eprocess offset base on CreateTime
This commit is contained in:
parent
d08852af55
commit
d0c0161b06
@ -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"] }
|
||||
|
@ -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<EprocessPoolChunk>,
|
||||
pub pool_scan_result: Vec<EprocessPoolChunk>
|
||||
}
|
||||
|
||||
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<u64> = match pool_size {
|
||||
0xf00 => vec![0x40],
|
||||
0xd80 => vec![0x40, 0x70, 0x80],
|
||||
0xe00 => vec![0x60, 0x70, 0x80, 0x90],
|
||||
_ => vec![]
|
||||
};
|
||||
// let eprocess_offset: Vec<u64> = 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");
|
||||
|
19
src/main.rs
19
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());
|
||||
}
|
||||
|
@ -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<T, E>(&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,
|
||||
|
Loading…
Reference in New Issue
Block a user