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 eprocess_scan_head = driver.scan_active_head(ntosbase)?;
|
||||||
// let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
|
// let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
|
||||||
driver.scan_pool(b"Proc", |pool_addr, header, data_addr| {
|
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_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 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_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_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 try_eprocess_ptr = eprocess_valid_start;
|
||||||
|
|
||||||
let mut create_time = 0u64;
|
let mut create_time = 0u64;
|
||||||
let mut exit_time = 0u64;
|
let mut exit_time = 0u64;
|
||||||
while try_eprocess_ptr <= eprocess_valid_end {
|
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_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
|
// using heuristics to eliminate false positive
|
||||||
if driver.windows_ffi.valid_process_time(create_time) {
|
if driver.windows_ffi.valid_process_time(create_time) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
try_eprocess_ptr += 0x4; // search exhaustively
|
try_eprocess_ptr += 0x4; // search exhaustively
|
||||||
}
|
}
|
||||||
|
if (try_eprocess_ptr > eprocess_valid_end) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
let mut image_name = [0u8; 15];
|
let mut image_name = [0u8; 15];
|
||||||
driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
|
driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
|
||||||
let eprocess_name = from_utf8(&image_name)?
|
if let Ok(name) = from_utf8(&image_name) {
|
||||||
.to_string()
|
let eprocess_name = name
|
||||||
.trim_end_matches(char::from(0))
|
.to_string()
|
||||||
.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 {
|
// eprocess_list.push(EprocessPoolChunk {
|
||||||
// pool_addr,
|
// pool_addr,
|
||||||
// eprocess_addr: try_eprocess_ptr,
|
// eprocess_addr: try_eprocess_ptr,
|
||||||
@ -63,8 +75,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
// create_time: to_epoch(create_time),
|
// create_time: to_epoch(create_time),
|
||||||
// exit_time: to_epoch(exit_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());
|
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||||
|
@ -163,23 +163,47 @@ impl DriverState {
|
|||||||
if ptr >= end_address {
|
if ptr >= end_address {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pool_addr = ptr;
|
let pool_addr = ptr;
|
||||||
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 success = handler(ptr, &header, pool_addr + pool_header_size)?;
|
if pool_addr + chunk_size > end_address {
|
||||||
if success {
|
// the chunk found is not a valid chunk for sure
|
||||||
let chunk_size = (header[2] as u64) * 16u64;
|
break;
|
||||||
ptr += chunk_size /* pass this chunk */
|
}
|
||||||
|
|
||||||
|
// 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 {
|
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)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
let code = DriverAction::DereferenceAddress.get_code();
|
let code = DriverAction::DereferenceAddress.get_code();
|
||||||
let size: usize = size_of_val(outbuf);
|
let size: usize = size_of_val(outbuf);
|
||||||
let mut input = InputData {
|
let mut input = InputData {
|
||||||
|
@ -99,7 +99,10 @@ impl PdbStore {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let mut need_structs = HashMap::new();
|
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("_PEB", vec![]);
|
||||||
need_structs.insert("_LIST_ENTRY", vec![
|
need_structs.insert("_LIST_ENTRY", vec![
|
||||||
"Flink", "Blink"
|
"Flink", "Blink"
|
||||||
|
Loading…
Reference in New Issue
Block a user