Skip to content

Commit

Permalink
Update scan frontend
Browse files Browse the repository at this point in the history
Reject invalid block size
Unicode string handle for empty ptr, empty size
Add _FILE_OBJECT scan
Add FileImage dump of _EPROCESS scan
  • Loading branch information
nganhkhoa committed May 22, 2020
1 parent ee13c6b commit ecc476c
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 22 deletions.
12 changes: 10 additions & 2 deletions src/bin/eprocess_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ fn main() -> Result<(), Box<dyn Error>> {
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_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_valid_start = data_addr;
Expand All @@ -56,16 +58,22 @@ fn main() -> Result<(), Box<dyn Error>> {
}

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_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) {
let eprocess_name = name
.to_string()
.trim_end_matches(char::from(0))
.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 {
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)
// eprocess_list.push(EprocessPoolChunk {
Expand Down
48 changes: 48 additions & 0 deletions src/bin/file_object_scan.rs
Original file line number Diff line number Diff line change
@@ -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(())
}


59 changes: 39 additions & 20 deletions src/driver_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ impl DriverState {
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 flink_offset = self.pdb_store.get_offset_r("_LIST_ENTRY.Flink")?;
let eprocess_link_offset = self.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
Expand Down Expand Up @@ -148,8 +149,8 @@ impl DriverState {
// 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 minimum_block_size = self.get_minimum_block_size(tag)?;
let code = DriverAction::ScanPoolRemote.get_code();
let range = self.get_nonpaged_range(ntosbase)?;
let start_address = range[0];
Expand All @@ -165,6 +166,9 @@ impl DriverState {
}

let pool_addr = ptr;
// println!("chunk: 0x{:x}", pool_addr);
// ptr += 0x4;
// continue;
let mut header = vec![0u8; pool_header_size as usize];
self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size);
let chunk_size = (header[2] as u64) * 16u64;
Expand All @@ -174,23 +178,14 @@ impl DriverState {
break;
}

// TODO: move to another function, with tables mapping fromm tag -> struct
// automatically reject bad chunk
// Proc -> _EPROCESS
// Thre -> _KTHREAD
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;
if chunk_size < minimum_data_size {
ptr += 0x4;
continue;
}
}
else {
println!("Tag unknown");
break;
if chunk_size < minimum_block_size {
ptr += 0x4;
continue;
}

// ptr += 0x4;
// continue;
let success = handler(pool_addr, &header, pool_addr + pool_header_size)?;
if success {
ptr += chunk_size; /* pass this chunk */
Expand All @@ -202,6 +197,25 @@ impl DriverState {
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) {
// println!("deref addr: 0x{:x}", addr);
let code = DriverAction::DereferenceAddress.get_code();
Expand Down Expand Up @@ -231,18 +245,23 @@ impl DriverState {

pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
let mut strlen = 0u16;
let mut capacity = 0u16;
let mut bufaddr = 0u64;
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(capacity_addr, &mut capacity);
self.deref_addr(buffer_ptr, &mut bufaddr);

let mut buf = vec![0u8; strlen as usize];
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
if bufaddr == 0 || strlen > capacity || strlen == 0 {
return Err("Unicode string is empty".into());
}

println!("unicode string {:?}", buf);
let mut buf = vec![0u16; (strlen / 2) as usize];
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);

Ok(std::str::from_utf8(&buf)?.to_string())
Ok(String::from_utf16(&buf)?)
}

pub fn get_nonpaged_range(&self, ntosbase: u64) -> BoxResult<[u64; 2]> {
Expand Down

0 comments on commit ecc476c

Please sign in to comment.