From 5e1a634d0c9d13e799f6d0822490ed9da05ba5b4 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 5 Jul 2021 15:44:07 +0200 Subject: [PATCH] libafl bridge as Rust crate --- .gitignore | 2 + configure | 6 +++ qemu_libafl_bridge/Cargo.toml | 11 ++++ qemu_libafl_bridge/src/amd64.rs | 23 +++++++++ qemu_libafl_bridge/src/lib.rs | 92 +++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 qemu_libafl_bridge/Cargo.toml create mode 100644 qemu_libafl_bridge/src/amd64.rs create mode 100644 qemu_libafl_bridge/src/lib.rs diff --git a/.gitignore b/.gitignore index 75a4be0724..da5dcbf8a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/qemu_libafl_bridge/Cargo.lock +/qemu_libafl_bridge/target/ /GNUmakefile /build/ *.pyc diff --git a/configure b/configure index e799d908a3..6e14357a4b 100755 --- a/configure +++ b/configure @@ -446,6 +446,8 @@ slirp_smbd="$default_feature" malloc_trim="auto" gio="$default_feature" +libafl_bridge="" + # parse CC options second for opt do optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') @@ -1558,6 +1560,8 @@ for opt do ;; --disable-slirp-smbd) slirp_smbd=no ;; + --with-libafl-bridge=*) libafl_bridge="$optarg" + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -1566,6 +1570,8 @@ for opt do esac done +QEMU_LDFLAGS="$QEMU_LDFLAGS $libafl_bridge" + case $git_submodules_action in update|validate) if test ! -e "$source_path/.git"; then diff --git a/qemu_libafl_bridge/Cargo.toml b/qemu_libafl_bridge/Cargo.toml new file mode 100644 index 0000000000..64d72aa78b --- /dev/null +++ b/qemu_libafl_bridge/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "qemu_libafl_bridge" +version = "0.1.0" +authors = ["Andrea Fioraldi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num = "0.4" +num_enum = "0.5.1" diff --git a/qemu_libafl_bridge/src/amd64.rs b/qemu_libafl_bridge/src/amd64.rs new file mode 100644 index 0000000000..b52dd4991a --- /dev/null +++ b/qemu_libafl_bridge/src/amd64.rs @@ -0,0 +1,23 @@ +use num_enum::{IntoPrimitive, TryFromPrimitive}; + +#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)] +#[repr(i32)] +#[allow(clippy::pub_enum_variant_names)] +pub enum Amd64Regs { + Rax = 0, + Rcx = 1, + Rdx = 2, + Rbx = 3, + Rsp = 4, + Rbp = 5, + Rsi = 6, + Rdi = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, +} diff --git a/qemu_libafl_bridge/src/lib.rs b/qemu_libafl_bridge/src/lib.rs new file mode 100644 index 0000000000..01f9f5c7b7 --- /dev/null +++ b/qemu_libafl_bridge/src/lib.rs @@ -0,0 +1,92 @@ +use core::{mem::transmute, ptr::copy_nonoverlapping}; +use num::Num; + +pub mod amd64; + +/* + int libafl_qemu_write_reg(int reg, uint8_t* val); + int libafl_qemu_read_reg(int reg, uint8_t* val); + int libafl_qemu_num_regs(void); + int libafl_qemu_set_breakpoint(uint64_t addr); + int libafl_qemu_remove_breakpoint(uint64_t addr); +*/ + +extern "C" { + fn libafl_qemu_write_reg(reg: i32, val: *const u8) -> i32; + fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32; + fn libafl_qemu_num_regs() -> i32; + fn libafl_qemu_set_breakpoint(addr: u64) -> i32; + fn libafl_qemu_remove_breakpoint(addr: u64) -> i32; + fn libafl_qemu_run() -> i32; + + static guest_base: isize; +} + +pub struct QemuEmulator {} + +impl QemuEmulator { + pub fn write_mem(&mut self, addr: isize, buf: &[u8]) { + let host_addr = self.g2h(addr); + unsafe { copy_nonoverlapping(buf.as_ptr() as *const u8, host_addr, buf.len()) } + } + + pub fn read_mem(&mut self, addr: isize, buf: &mut [u8]) { + let host_addr = self.g2h(addr); + unsafe { + copy_nonoverlapping( + host_addr as *const u8, + buf.as_mut_ptr() as *mut u8, + buf.len(), + ) + } + } + + pub fn num_regs(&self) -> i32 { + unsafe { libafl_qemu_num_regs() } + } + + pub fn write_reg(&mut self, reg: i32, val: T) -> Result<(), String> + where + T: Num + PartialOrd + Copy, + { + let success = unsafe { libafl_qemu_write_reg(reg, &val as *const _ as *const u8) }; + if success != 0 { + Ok(()) + } else { + Err(format!("Failed to write to register {}", reg)) + } + } + + pub fn read_reg(&mut self, reg: i32) -> Result + where + T: Num + PartialOrd + Copy, + { + let mut val = T::zero(); + let success = unsafe { libafl_qemu_read_reg(reg, &mut val as *mut _ as *mut u8) }; + if success != 0 { + Ok(val) + } else { + Err(format!("Failed to read register {}", reg)) + } + } + + pub fn set_breakpoint(&mut self, addr: isize) { + unsafe { libafl_qemu_set_breakpoint(addr as u64) }; + } + + pub fn remove_breakpoint(&mut self, addr: isize) { + unsafe { libafl_qemu_remove_breakpoint(addr as u64) }; + } + + pub fn run(&mut self) { + unsafe { libafl_qemu_run() }; + } + + pub fn g2h(&self, addr: isize) -> *mut u8 { + unsafe { transmute(addr + guest_base) } + } + + pub fn h2g(&self, addr: isize) -> *mut u8 { + unsafe { transmute(addr - guest_base) } + } +}