Update scan frontend
Reject invalid block size Unicode string handle for empty ptr, empty size Add _FILE_OBJECT scan Add FileImage dump of _EPROCESS scan
This commit is contained in:
parent
ee13c6be58
commit
ecc476c604
@ -34,6 +34,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
||||||
let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?;
|
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_create_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.CreateTime")?;
|
||||||
|
let fob_filename_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.FileName")?;
|
||||||
|
let eprocess_image_file_ptr_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFilePointer")?;
|
||||||
// let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?;
|
// let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?;
|
||||||
|
|
||||||
let eprocess_valid_start = data_addr;
|
let eprocess_valid_start = data_addr;
|
||||||
@ -56,16 +58,22 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut image_name = [0u8; 15];
|
let mut image_name = [0u8; 15];
|
||||||
|
let mut file_object_ptr = 0u64;
|
||||||
|
|
||||||
driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
|
driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
|
||||||
|
driver.deref_addr(try_eprocess_ptr + eprocess_image_file_ptr_offset, &mut file_object_ptr);
|
||||||
|
let filename = if file_object_ptr != 0 { driver.get_unicode_string(file_object_ptr + fob_filename_offset)? }
|
||||||
|
else { "".to_string() };
|
||||||
|
|
||||||
if let Ok(name) = from_utf8(&image_name) {
|
if let Ok(name) = from_utf8(&image_name) {
|
||||||
let eprocess_name = name
|
let eprocess_name = name
|
||||||
.to_string()
|
.to_string()
|
||||||
.trim_end_matches(char::from(0))
|
.trim_end_matches(char::from(0))
|
||||||
.to_string();
|
.to_string();
|
||||||
println!("pool: 0x{:x} | eprocess: 0x{:x} | {}", pool_addr, try_eprocess_ptr, eprocess_name);
|
println!("pool: 0x{:x} | eprocess: 0x{:x} | {} | {}", pool_addr, try_eprocess_ptr, filename, eprocess_name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println!("pool: 0x{:x} | eprocess: 0x{:x} | {:?}", pool_addr, try_eprocess_ptr, image_name);
|
println!("pool: 0x{:x} | eprocess: 0x{:x} | {} | {:?}", pool_addr, try_eprocess_ptr, filename, image_name);
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
// eprocess_list.push(EprocessPoolChunk {
|
// eprocess_list.push(EprocessPoolChunk {
|
||||||
|
48
src/bin/file_object_scan.rs
Normal file
48
src/bin/file_object_scan.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use lpus::{
|
||||||
|
driver_state::{DriverState}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut driver = DriverState::new();
|
||||||
|
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||||
|
|
||||||
|
driver.scan_pool(b"File", |pool_addr, header, data_addr| {
|
||||||
|
let chunk_size = (header[2] as u64) * 16u64;
|
||||||
|
|
||||||
|
let fob_size = driver.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
||||||
|
let fob_size_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.Size")?;
|
||||||
|
let fob_filename_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.FileName")?;
|
||||||
|
|
||||||
|
let valid_end = (pool_addr + chunk_size) - fob_size;
|
||||||
|
let mut try_ptr = data_addr;
|
||||||
|
|
||||||
|
let mut ftype = 0u16;
|
||||||
|
let mut size = 0u16;
|
||||||
|
while try_ptr <= valid_end {
|
||||||
|
driver.deref_addr(try_ptr, &mut ftype);
|
||||||
|
driver.deref_addr(try_ptr + fob_size_offset, &mut size);
|
||||||
|
if (size as u64) == fob_size && ftype == 5u16 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try_ptr += 0x4; // search exhaustively
|
||||||
|
}
|
||||||
|
if try_ptr > valid_end {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let fob_addr = try_ptr;
|
||||||
|
// println!("pool: 0x{:x} | file object: 0x{:x} | offsetby: {}", pool_addr, fob_addr, fob_addr - pool_addr);
|
||||||
|
if let Ok(filename) = driver.get_unicode_string(fob_addr + fob_filename_offset) {
|
||||||
|
println!("pool: 0x{:x} | file object: 0x{:x} | offsetby: {} | {}",
|
||||||
|
pool_addr, fob_addr, fob_addr - pool_addr, filename);
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +108,8 @@ impl DriverState {
|
|||||||
ntosbase
|
ntosbase
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_active_head(&self, ntosbase: u64) -> BoxResult<Vec<EprocessPoolChunk>> {
|
pub fn scan_active_head(&self) -> BoxResult<Vec<EprocessPoolChunk>> {
|
||||||
|
let ntosbase = self.get_kernel_base();
|
||||||
let ps_active_head = ntosbase + self.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
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 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_link_offset = self.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
||||||
@ -148,8 +149,8 @@ impl DriverState {
|
|||||||
// TODO: Pool Header as a real struct
|
// TODO: Pool Header as a real struct
|
||||||
{
|
{
|
||||||
let ntosbase = self.get_kernel_base();
|
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 pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
||||||
|
let minimum_block_size = self.get_minimum_block_size(tag)?;
|
||||||
let code = DriverAction::ScanPoolRemote.get_code();
|
let code = DriverAction::ScanPoolRemote.get_code();
|
||||||
let range = self.get_nonpaged_range(ntosbase)?;
|
let range = self.get_nonpaged_range(ntosbase)?;
|
||||||
let start_address = range[0];
|
let start_address = range[0];
|
||||||
@ -165,6 +166,9 @@ impl DriverState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pool_addr = ptr;
|
let pool_addr = ptr;
|
||||||
|
// println!("chunk: 0x{:x}", pool_addr);
|
||||||
|
// ptr += 0x4;
|
||||||
|
// continue;
|
||||||
let mut header = vec![0u8; pool_header_size as usize];
|
let mut header = vec![0u8; pool_header_size as usize];
|
||||||
self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size);
|
self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size);
|
||||||
let chunk_size = (header[2] as u64) * 16u64;
|
let chunk_size = (header[2] as u64) * 16u64;
|
||||||
@ -174,23 +178,14 @@ impl DriverState {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to another function, with tables mapping fromm tag -> struct
|
|
||||||
// automatically reject bad chunk
|
// automatically reject bad chunk
|
||||||
// Proc -> _EPROCESS
|
if chunk_size < minimum_block_size {
|
||||||
// Thre -> _KTHREAD
|
ptr += 0x4;
|
||||||
if tag == b"Proc" {
|
continue;
|
||||||
let eprocess_size = self.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
|
||||||
let minimum_data_size = eprocess_size + pool_header_size;
|
|
||||||
if chunk_size < minimum_data_size {
|
|
||||||
ptr += 0x4;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
println!("Tag unknown");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ptr += 0x4;
|
||||||
|
// continue;
|
||||||
let success = handler(pool_addr, &header, pool_addr + pool_header_size)?;
|
let success = handler(pool_addr, &header, pool_addr + pool_header_size)?;
|
||||||
if success {
|
if success {
|
||||||
ptr += chunk_size; /* pass this chunk */
|
ptr += chunk_size; /* pass this chunk */
|
||||||
@ -202,6 +197,25 @@ impl DriverState {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_minimum_block_size(&self, tag: &[u8; 4]) -> BoxResult<u64> {
|
||||||
|
// Proc -> _EPROCESS
|
||||||
|
// Thre -> _KTHREAD
|
||||||
|
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
||||||
|
if tag == b"Proc" {
|
||||||
|
let eprocess_size = self.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
||||||
|
let minimum_data_size = eprocess_size + pool_header_size;
|
||||||
|
Ok(minimum_data_size)
|
||||||
|
}
|
||||||
|
else if tag == b"File" {
|
||||||
|
let file_object_size = self.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
||||||
|
let minimum_data_size = file_object_size + pool_header_size;
|
||||||
|
Ok(minimum_data_size)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err("Tag unknown".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
||||||
// println!("deref addr: 0x{:x}", addr);
|
// println!("deref addr: 0x{:x}", addr);
|
||||||
let code = DriverAction::DereferenceAddress.get_code();
|
let code = DriverAction::DereferenceAddress.get_code();
|
||||||
@ -231,18 +245,23 @@ impl DriverState {
|
|||||||
|
|
||||||
pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
|
pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
|
||||||
let mut strlen = 0u16;
|
let mut strlen = 0u16;
|
||||||
|
let mut capacity = 0u16;
|
||||||
let mut bufaddr = 0u64;
|
let mut bufaddr = 0u64;
|
||||||
let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
|
let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
|
||||||
|
let capacity_addr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.MaximumLength")?;
|
||||||
|
|
||||||
self.deref_addr(unicode_str_addr, &mut strlen);
|
self.deref_addr(unicode_str_addr, &mut strlen);
|
||||||
|
self.deref_addr(capacity_addr, &mut capacity);
|
||||||
self.deref_addr(buffer_ptr, &mut bufaddr);
|
self.deref_addr(buffer_ptr, &mut bufaddr);
|
||||||
|
|
||||||
let mut buf = vec![0u8; strlen as usize];
|
if bufaddr == 0 || strlen > capacity || strlen == 0 {
|
||||||
|
return Err("Unicode string is empty".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buf = vec![0u16; (strlen / 2) as usize];
|
||||||
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
|
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
|
||||||
|
|
||||||
println!("unicode string {:?}", buf);
|
Ok(String::from_utf16(&buf)?)
|
||||||
|
|
||||||
Ok(std::str::from_utf8(&buf)?.to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_nonpaged_range(&self, ntosbase: u64) -> BoxResult<[u64; 2]> {
|
pub fn get_nonpaged_range(&self, ntosbase: u64) -> BoxResult<[u64; 2]> {
|
||||||
|
Loading…
Reference in New Issue
Block a user