Qemu read memory mappings (#228)

* add x64 syscalls numbers

* syscall hook

* update commit

* read guest mappings

* clippy
This commit is contained in:
Andrea Fioraldi 2021-07-16 10:38:00 +02:00 committed by GitHub
parent 5a14b870e2
commit 5cd7339b1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 139 additions and 15 deletions

View File

@ -33,7 +33,7 @@ target/$(BUILD_TARGET)/lib$(FUZZER_NAME).a: src/*
qemu-libafl-bridge: qemu-libafl-bridge:
git clone git@github.com:AFLplusplus/qemu-libafl-bridge.git git clone git@github.com:AFLplusplus/qemu-libafl-bridge.git
cd qemu-libafl-bridge && git checkout beb8bf68beac1f3b522dab9cda2d00d4a2912c5b cd qemu-libafl-bridge && git checkout 03dfdbd7da90b2d3b9e4df1a52b5a48e8d453a84
build/config.status: qemu-libafl-bridge qemu-libafl-bridge/configure build/config.status: qemu-libafl-bridge qemu-libafl-bridge/configure
mkdir -p build mkdir -p build

View File

@ -72,8 +72,8 @@ impl<E> TimeoutExecutor<E> {
tv_usec: 0, tv_usec: 0,
}; };
let itimerval = Itimerval { let itimerval = Itimerval {
it_value,
it_interval, it_interval,
it_value,
}; };
Self { Self {
executor, executor,

View File

@ -1,18 +1,88 @@
//! Expose QEMU user `LibAFL` C api to Rust //! Expose QEMU user `LibAFL` C api to Rust
use core::{convert::Into, mem::transmute, ptr::copy_nonoverlapping}; use core::{
convert::Into,
convert::TryFrom,
ffi::c_void,
mem::{size_of, transmute, MaybeUninit},
ptr::copy_nonoverlapping,
};
use num::Num; use num::Num;
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::{mem::size_of, slice::from_raw_parts, str::from_utf8_unchecked}; use std::{slice::from_raw_parts, str::from_utf8_unchecked};
pub const SKIP_EXEC_HOOK: u32 = u32::MAX; pub const SKIP_EXEC_HOOK: u32 = u32::MAX;
#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)]
#[repr(i32)]
#[allow(clippy::pub_enum_variant_names)]
pub enum MmapPerms {
Read = libc::PROT_READ,
Write = libc::PROT_WRITE,
Execute = libc::PROT_EXEC,
ReadWrite = libc::PROT_READ | libc::PROT_WRITE,
ReadExecute = libc::PROT_READ | libc::PROT_EXEC,
WriteExecute = libc::PROT_WRITE | libc::PROT_EXEC,
ReadWriteExecute = libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC,
}
#[repr(C)] #[repr(C)]
pub struct SyscallHookResult { pub struct SyscallHookResult {
retval: u64, retval: u64,
skip_syscall: bool, skip_syscall: bool,
} }
#[repr(C)]
pub struct MapInfo {
start: u64,
end: u64,
offset: u64,
path: *const u8,
flags: i32,
is_priv: i32,
}
impl MapInfo {
#[must_use]
pub fn start(&self) -> u64 {
self.start
}
#[must_use]
pub fn end(&self) -> u64 {
self.end
}
#[must_use]
pub fn offset(&self) -> u64 {
self.offset
}
#[must_use]
pub fn path(&self) -> Option<&str> {
if self.path.is_null() {
None
} else {
unsafe {
Some(from_utf8_unchecked(from_raw_parts(
self.path,
strlen(self.path),
)))
}
}
}
#[must_use]
pub fn flags(&self) -> MmapPerms {
MmapPerms::try_from(self.flags).unwrap()
}
#[must_use]
pub fn is_priv(&self) -> bool {
self.is_priv != 0
}
}
extern "C" { extern "C" {
fn libafl_qemu_write_reg(reg: i32, val: *const u8) -> i32; 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_read_reg(reg: i32, val: *mut u8) -> i32;
@ -31,6 +101,11 @@ extern "C" {
/// int target_munmap(abi_ulong start, abi_ulong len) /// int target_munmap(abi_ulong start, abi_ulong len)
fn target_munmap(start: u64, len: u64) -> i32; fn target_munmap(start: u64, len: u64) -> i32;
fn read_self_maps() -> *const c_void;
fn free_self_maps(map_info: *const c_void);
fn libafl_maps_next(map_info: *const c_void, ret: *mut MapInfo) -> *const c_void;
static exec_path: *const u8; static exec_path: *const u8;
static guest_base: usize; static guest_base: usize;
@ -49,17 +124,49 @@ extern "C" {
unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult; unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult;
} }
#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)] pub struct GuestMaps {
#[repr(i32)] orig_c_iter: *const c_void,
#[allow(clippy::pub_enum_variant_names)] c_iter: *const c_void,
pub enum MmapPerms { }
Read = libc::PROT_READ,
Write = libc::PROT_WRITE, impl GuestMaps {
Execute = libc::PROT_EXEC, #[must_use]
ReadWrite = libc::PROT_READ | libc::PROT_WRITE, #[allow(clippy::new_without_default)]
ReadExecute = libc::PROT_READ | libc::PROT_EXEC, pub fn new() -> Self {
WriteExecute = libc::PROT_WRITE | libc::PROT_EXEC, unsafe {
ReadWriteExecute = libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC, let maps = read_self_maps();
Self {
orig_c_iter: maps,
c_iter: maps,
}
}
}
}
impl Iterator for GuestMaps {
type Item = MapInfo;
#[allow(clippy::uninit_assumed_init)]
fn next(&mut self) -> Option<Self::Item> {
if self.c_iter.is_null() {
return None;
}
unsafe {
let mut ret: MapInfo = MaybeUninit::uninit().assume_init();
self.c_iter = libafl_maps_next(self.c_iter, &mut ret as *mut _);
if self.c_iter.is_null() {
None
} else {
Some(ret)
}
}
}
}
impl Drop for GuestMaps {
fn drop(&mut self) {
unsafe { free_self_maps(self.orig_c_iter) }
}
} }
pub fn write_mem<T>(addr: u64, buf: &[T]) { pub fn write_mem<T>(addr: u64, buf: &[T]) {

View File

@ -79,3 +79,20 @@ struct syshook_ret {
__attribute__((weak)) struct syshook_ret (*libafl_syscall_hook)(int, uint64_t, __attribute__((weak)) struct syshook_ret (*libafl_syscall_hook)(int, uint64_t,
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t, uint64_t); uint64_t, uint64_t, uint64_t);
typedef void GSList;
__attribute__((weak)) GSList * read_self_maps(void) {
return NULL;
}
__attribute__((weak)) void free_self_maps(GSList *map_info) {
(void)map_info;
}
struct libafl_mapinfo {
uint64_t start, end;
uint64_t offset;
const char* path;
int flags, is_priv;
};
__attribute__((weak)) GSList * libafl_maps_next(GSList *map_info, struct libafl_mapinfo* ret);