Qemu read memory mappings (#228)
* add x64 syscalls numbers * syscall hook * update commit * read guest mappings * clippy
This commit is contained in:
parent
5a14b870e2
commit
5cd7339b1a
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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]) {
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user