Fix runtime BOSD
Chunk size and tag is check before handle. Check if heuristics search is not correct, and the try_ptr goes of the bound, making dereference an invalid address.
This commit is contained in:
parent
dd16a31984
commit
ff53a1a31c
@ -29,33 +29,45 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
// let eprocess_scan_head = driver.scan_active_head(ntosbase)?;
|
||||
// let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
|
||||
driver.scan_pool(b"Proc", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
||||
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 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);
|
||||
// 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
|
||||
}
|
||||
if (try_eprocess_ptr > eprocess_valid_end) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
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();
|
||||
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);
|
||||
}
|
||||
else {
|
||||
println!("pool: 0x{:x} | eprocess: 0x{:x} | {:?}", pool_addr, try_eprocess_ptr, image_name);
|
||||
}
|
||||
Ok(true)
|
||||
// eprocess_list.push(EprocessPoolChunk {
|
||||
// pool_addr,
|
||||
// eprocess_addr: try_eprocess_ptr,
|
||||
@ -63,8 +75,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
// 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());
|
||||
|
@ -163,23 +163,47 @@ impl DriverState {
|
||||
if ptr >= end_address {
|
||||
break;
|
||||
}
|
||||
|
||||
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 chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
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 */
|
||||
if pool_addr + chunk_size > end_address {
|
||||
// the chunk found is not a valid chunk for sure
|
||||
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 {
|
||||
ptr += 0x4 /* search next */
|
||||
};
|
||||
println!("Tag unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
let success = handler(pool_addr, &header, pool_addr + pool_header_size)?;
|
||||
if success {
|
||||
ptr += chunk_size; /* pass this chunk */
|
||||
}
|
||||
else {
|
||||
ptr += 0x4; /* search next */
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
||||
// println!("deref addr: 0x{:x}", addr);
|
||||
let code = DriverAction::DereferenceAddress.get_code();
|
||||
let size: usize = size_of_val(outbuf);
|
||||
let mut input = InputData {
|
||||
|
@ -99,7 +99,10 @@ impl PdbStore {
|
||||
];
|
||||
|
||||
let mut need_structs = HashMap::new();
|
||||
need_structs.insert("_POOL_HEADER", vec![]);
|
||||
need_structs.insert("_POOL_HEADER", vec![
|
||||
"struct_size",
|
||||
"PoolType", "BlockSize", "PoolTag"
|
||||
]);
|
||||
need_structs.insert("_PEB", vec![]);
|
||||
need_structs.insert("_LIST_ENTRY", vec![
|
||||
"Flink", "Blink"
|
||||
|
Loading…
Reference in New Issue
Block a user