extract ABBs

This commit is contained in:
Alwin Berger 2024-03-08 14:04:23 +01:00
parent a045b7bcd6
commit 6793d48dbd
2 changed files with 166 additions and 0 deletions

View File

@ -7,11 +7,13 @@ use libafl::prelude::UsesInput;
use libafl_qemu::Emulator;
use libafl_qemu::GuestAddr;
use libafl_qemu::GuestPhysAddr;
use libafl_qemu::GuestReg;
use libafl_qemu::QemuHooks;
use libafl_qemu::edges::QemuEdgesMapMetadata;
use libafl_qemu::emu;
use libafl_qemu::hooks;
use libafl_qemu::Hook;
use crate::systemstate::extract_abbs_from_trace;
use crate::systemstate::RawFreeRTOSSystemState;
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
use crate::systemstate::NUM_PRIOS;
@ -152,6 +154,27 @@ where
fn post_exec<OT>(&mut self, emulator: &Emulator, _input: &S::Input, _observers: &mut OT, _exit_kind: &mut ExitKind) {
trigger_collection(emulator,(None, None), self);
unsafe {
let c = emulator.cpu_from_index(0);
let pc = c.read_reg::<i32, u32>(15).unwrap();;
CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].edge = (Some(pc),None);
CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].capture_point = (CaptureEvent::End,"Breakpoint");
}
// Find the first ISREnd of vPortSVCHandler and drop anything before
unsafe {
let mut index = 0;
while index < CURRENT_SYSTEMSTATE_VEC.len() {
if CaptureEvent::ISREnd == CURRENT_SYSTEMSTATE_VEC[index].capture_point.0 && CURRENT_SYSTEMSTATE_VEC[index].capture_point.1 == "xPortPendSVHandler" {
break;
}
index += 1;
}
CURRENT_SYSTEMSTATE_VEC.drain(..index);
}
unsafe {
let abbs = extract_abbs_from_trace(&CURRENT_SYSTEMSTATE_VEC);
println!("{:?}", abbs);
}
}
}

View File

@ -1,5 +1,7 @@
//! systemstate referes to the State of a FreeRTOS fuzzing target
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use hashbrown::HashSet;
use libafl_bolts::HasRefCnt;
use libafl_bolts::AsSlice;
use libafl_qemu::GuestAddr;
@ -195,3 +197,144 @@ impl HasRefCnt for FreeRTOSSystemStateMetadata {
}
libafl_bolts::impl_serdeany!(FreeRTOSSystemStateMetadata);
#[derive(Default, Serialize, Deserialize, Clone)]
pub struct AtomicBasicBlock {
start: GuestAddr,
ends: HashSet<GuestAddr>,
}
impl fmt::Display for AtomicBasicBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut ends_str = String::new();
for end in &self.ends {
ends_str.push_str(&format!("0x{:#x}, ", end));
}
write!(f, "AtomicBasicBlock {{ start: 0x{:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(','))
}
}
impl fmt::Debug for AtomicBasicBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut ends_str = String::new();
for end in &self.ends {
ends_str.push_str(&format!("{:#x}, ", end));
}
write!(f, "AtomicBasicBlock {{ start: {:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(','))
}
}
fn get_task_names(trace: &Vec<RefinedFreeRTOSSystemState>) -> HashSet<String> {
let mut ret: HashSet<_, _> = HashSet::new();
for state in trace {
ret.insert(state.current_task.0.task_name.to_string());
}
ret
}
fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<String,Vec<AtomicBasicBlock>> {
let mut abbs_of_task : HashMap<String, Vec<AtomicBasicBlock>> = HashMap::new();
let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
// iterate over all states and extract atomic basic blocks
// an atomic base block has a single entry and multiple exits
// the cuts between blocks are api calls
// when capture_point is APIEnd, the destination of the edge is the start of an atomic block
// so the next APIStart with the same current_tcb.pcTaskName is the end of the atomic block
for i in 0..trace.len() {
let tmp = unsafe { std::mem::transmute::<[i8; 10],[u8; 10]>(trace[i].current_tcb.pcTaskName) };
let curr_name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
let last : Option<&usize> = last_abb_of_task.get(&curr_name);
match trace[i].capture_point.0 {
CaptureEvent::APIStart => {
// end the last atomic block
if let Some(&l) = last {
let start = trace[l].edge.1.unwrap();
let end = trace[i].edge.0.unwrap();
match abbs_of_task.get_mut(&curr_name) {
Some(v) => {
match v.iter_mut().find(|x| x.start==start) {
Some(abb) => {
abb.ends.insert(end);
}
None => {
let mut t = HashSet::new();
t.insert(end);
v.push(AtomicBasicBlock {start, ends: t});
}
};
},
None => {
let mut v = Vec::new();
let mut t = HashSet::new();
t.insert(end);
v.push(AtomicBasicBlock {start, ends: t});
abbs_of_task.insert(curr_name, v);
}
}
} else {
// first API call of this task
let mut v = Vec::new();
let mut t = HashSet::new();
let end = trace[i].edge.0.unwrap();
t.insert(end);
v.push(AtomicBasicBlock {start: 0, ends: t});
abbs_of_task.insert(curr_name, v);
}
},
CaptureEvent::APIEnd => {
match last {
Some(&l) => {
//assert!(trace[l].capture_point.0 == CaptureEvent::APIStart);
},
None => (),
}
last_abb_of_task.insert(curr_name, i);
},
CaptureEvent::ISRStart => {
},
CaptureEvent::ISREnd => {
},
CaptureEvent::End => {
// end the last atomic block
if let Some(&l) = last {
let start = trace[l].edge.1.unwrap();
let end = trace[i].edge.0.unwrap();
match abbs_of_task.get_mut(&curr_name) {
Some(v) => {
match v.iter_mut().find(|x| x.start==start) {
Some(abb) => {
abb.ends.insert(end);
}
None => {
let mut t = HashSet::new();
t.insert(end);
v.push(AtomicBasicBlock {start, ends: t});
}
};
},
None => {
let mut v = Vec::new();
let mut t = HashSet::new();
t.insert(end);
v.push(AtomicBasicBlock {start, ends: t});
abbs_of_task.insert(curr_name, v);
}
}
} else {
// first API call of this task
let mut v = Vec::new();
let mut t = HashSet::new();
let end = trace[i].edge.0.unwrap();
t.insert(end);
v.push(AtomicBasicBlock {start: 0, ends: t});
abbs_of_task.insert(curr_name, v);
}
},
CaptureEvent::Undefined => {
},
}
}
abbs_of_task
}
libafl_bolts::impl_serdeany!(AtomicBasicBlock);