Skip to content

Commit

Permalink
WIP use a callback to get memory instead of image
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcondiro committed Sep 9, 2024
1 parent 09a1a33 commit d26447d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 27 deletions.
34 changes: 13 additions & 21 deletions libafl_qemu/src/modules/systemmode/intel_pt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use crate::{
//#[derive(Debug)]
pub struct IntelPTModule {
pt: Option<IntelPT>,
image: Option<Image<'static>>,
}

impl Debug for IntelPTModule {
Expand All @@ -27,10 +26,7 @@ impl Debug for IntelPTModule {

impl IntelPTModule {
pub fn new() -> Self {
Self {
pt: None,
image: None,
}
Self { pt: None }
}
}

Expand Down Expand Up @@ -90,17 +86,11 @@ where
) where
ET: EmulatorModuleTuple<S>,
{
if self.image.is_none() {
// emulator_modules.qemu()
// we need the memory map to decode the traces here take it in prexec. use QemuMemoryChunk
// TODO handle self modifying code
self.image = Some(Image::new(Some("empty_image")).expect("Failed to create image"));
}
}

fn post_exec<OT, ET>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, S>,
_input: &S::Input,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
Expand All @@ -112,16 +102,18 @@ where
panic!("Intel PT module not initialized.");
}

if self.image.is_none() {
panic!("Intel PT module: memory image not initialized.");
}
// we need the memory map to decode the traces here take it in prexec. use QemuMemoryChunk
// TODO handle self modifying code

let qemu = emulator_modules.qemu();
// qemu.read_mem()

// TODO: raw traces buff just for debugging
let mut buff = Vec::new();
let block_ips = self
.pt
.as_mut()
.unwrap()
.decode(&mut self.image.as_mut().unwrap(), Some(&mut buff));
let block_ips = self.pt.as_mut().unwrap().decode_with_callback(
|addr, out_buff| unsafe { qemu.read_mem(addr.into(), out_buff) },
Some(&mut buff),
);

let trace_path = "trace.out";
let mut file = OpenOptions::new()
Expand All @@ -131,6 +123,6 @@ where
.expect("Failed to open trace output file");

file.write_all(&buff).unwrap();
println!("Block IPs: {:#x?}", block_ips);
// println!("Block IPs: {:#x?}", block_ips);
}
}
40 changes: 34 additions & 6 deletions libafl_qemu/src/qemu/systemmode/intel_pt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,28 @@ impl IntelPT {
}
}

pub fn decode(&mut self, image: &mut Image, copy_buffer: Option<&mut Vec<u8>>) -> Vec<u64> {
pub fn decode_with_image(
&mut self,
image: &mut Image,
copy_buffer: Option<&mut Vec<u8>>,
) -> Vec<u64> {
self.decode(None::<fn(_: u64, _: &mut [u8])>, Some(image), copy_buffer)
}

pub fn decode_with_callback<F: Fn(u64, &mut [u8])>(
&mut self,
read_memory: F,
copy_buffer: Option<&mut Vec<u8>>,
) -> Vec<u64> {
self.decode(Some(read_memory), None, copy_buffer)
}

fn decode<F: Fn(u64, &mut [u8])>(
&mut self,
read_memory: Option<F>,
image: Option<&mut Image>,
copy_buffer: Option<&mut Vec<u8>>,
) -> Vec<u64> {
let mut ips = Vec::new();

let aux_head = unsafe { ptr::addr_of_mut!((*self.buff_metadata).aux_head) };
Expand All @@ -181,13 +202,19 @@ impl IntelPT {
// apparently the rust library doesn't have the context parameter for the set_callback
// also, under the hood looks like it is passing the callback itself as context to the C fn 🤔
// TODO remove unwrap()
let mut config =
ConfigBuilder::new(unsafe { slice::from_raw_parts_mut(data, len) }).unwrap();
let mut config = if let Some(rm) = read_memory {
//ConfigBuilder::with_callback(unsafe { slice::from_raw_parts_mut(data, len) }, )
todo!();
} else {
ConfigBuilder::new(unsafe { slice::from_raw_parts_mut(data, len) }).unwrap()
};
if let Some(cpu) = current_cpu() {
config.cpu(cpu);
}
let mut decoder = BlockDecoder::new(&config.finish()).unwrap();
decoder.set_image(Some(image)).expect("Failed to set image");
if let Some(i) = image {
decoder.set_image(Some(i)).expect("Failed to set image");
}
// TODO rewrite decently
// TODO consider dropping libipt-rs and using sys, or bindgen ourselves
let mut status;
Expand Down Expand Up @@ -571,8 +598,9 @@ mod test {
}
}
}

let mut trace = Vec::new();
let mut ips = pt.decode(&mut image, Some(&mut trace));
let mut ips = pt.decode_with_image(&mut image, Some(&mut trace));
let _ = dump_trace_to_file(&trace)
.inspect_err(|e| println!("Failed to dump trace to file: {e}"));
// remove kernel ips
Expand All @@ -582,7 +610,7 @@ mod test {
.collect();
ips.sort();
ips.dedup();
println!("Intel PT traces unique non kernel block ips: {:#x?}", ips);
println!("Intel PT traces unique block ips: {:#x?}", ips);
// TODO: it seems like some userspace traces are not decoded
// probably because of smth like this in the traces:
// PSB
Expand Down

0 comments on commit d26447d

Please sign in to comment.