Arch independent helpers in libafl_qemu (#1355)
* Add more features to libafl_qemu to remove some of the heavy lifting from the fuzzers * Refactor qemu_coverage * Minor tweaks to fix other fuzzers * Autofix * Add CallingConvention to write_function_argument * Replay reverted clippy fixes --------- Co-authored-by: Your Name <you@example.com>
This commit is contained in:
parent
109755208e
commit
2002bbca35
@ -51,7 +51,7 @@ use libafl_qemu::{
|
||||
emu::Emulator,
|
||||
filter_qemu_args,
|
||||
hooks::QemuHooks,
|
||||
MmapPerms, QemuForkExecutor, Regs,
|
||||
GuestReg, MmapPerms, QemuForkExecutor, Regs,
|
||||
};
|
||||
#[cfg(unix)]
|
||||
use nix::{self, unistd::dup};
|
||||
@ -318,7 +318,7 @@ fn fuzz(
|
||||
emu.write_mem(input_addr, buf);
|
||||
|
||||
emu.write_reg(Regs::Rdi, input_addr).unwrap();
|
||||
emu.write_reg(Regs::Rsi, len).unwrap();
|
||||
emu.write_reg(Regs::Rsi, len as GuestReg).unwrap();
|
||||
emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap();
|
||||
emu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
||||
|
||||
|
@ -54,6 +54,7 @@ use libafl_qemu::{
|
||||
emu::Emulator,
|
||||
filter_qemu_args,
|
||||
hooks::QemuHooks,
|
||||
GuestReg,
|
||||
//snapshot::QemuSnapshotHelper,
|
||||
MmapPerms,
|
||||
QemuExecutor,
|
||||
@ -330,7 +331,7 @@ fn fuzz(
|
||||
emu.write_mem(input_addr, buf);
|
||||
|
||||
emu.write_reg(Regs::Rdi, input_addr).unwrap();
|
||||
emu.write_reg(Regs::Rsi, len).unwrap();
|
||||
emu.write_reg(Regs::Rsi, len as GuestReg).unwrap();
|
||||
emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap();
|
||||
emu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
||||
|
||||
|
@ -13,12 +13,11 @@ debug = true
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
be = []
|
||||
64bit = []
|
||||
be = ["libafl_qemu/be"]
|
||||
arm = ["libafl_qemu/arm"]
|
||||
x86_64 = ["libafl_qemu/x86_64", "64bit"]
|
||||
x86_64 = ["libafl_qemu/x86_64"]
|
||||
i386 = ["libafl_qemu/i386"]
|
||||
aarch64 = ["libafl_qemu/aarch64", "64bit"]
|
||||
aarch64 = ["libafl_qemu/aarch64"]
|
||||
mips = ["libafl_qemu/mips"]
|
||||
ppc = ["libafl_qemu/ppc", "be"]
|
||||
|
||||
|
@ -28,17 +28,11 @@ use libafl::{
|
||||
Error,
|
||||
};
|
||||
use libafl_qemu::{
|
||||
drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, MmapPerms, QemuExecutor, QemuHooks,
|
||||
QemuInstrumentationFilter, Regs,
|
||||
drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, ArchExtras, CallingConvention, GuestAddr,
|
||||
GuestReg, MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs,
|
||||
};
|
||||
use rangemap::RangeMap;
|
||||
|
||||
#[cfg(feature = "64bit")]
|
||||
type GuestReg = u64;
|
||||
|
||||
#[cfg(not(feature = "64bit"))]
|
||||
type GuestReg = u32;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Version;
|
||||
|
||||
@ -141,60 +135,10 @@ pub fn fuzz() {
|
||||
);
|
||||
}
|
||||
|
||||
let read_reg = |emu: &Emulator, reg: Regs| -> GuestReg {
|
||||
let val: GuestReg = emu.read_reg(reg).unwrap();
|
||||
|
||||
#[cfg(feature = "be")]
|
||||
return GuestReg::from_be(val);
|
||||
|
||||
#[cfg(not(feature = "be"))]
|
||||
return GuestReg::from_le(val);
|
||||
};
|
||||
|
||||
let write_reg = |emu: &Emulator, reg: Regs, val: GuestReg| {
|
||||
#[cfg(feature = "be")]
|
||||
let val = GuestReg::to_be(val);
|
||||
|
||||
#[cfg(not(feature = "be"))]
|
||||
let val = GuestReg::to_le(val);
|
||||
|
||||
emu.write_reg(reg, val).unwrap();
|
||||
};
|
||||
|
||||
println!("Break at {:#x}", read_reg(&emu, Regs::Pc));
|
||||
|
||||
#[cfg(feature = "arm")]
|
||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
||||
|
||||
#[cfg(feature = "aarch64")]
|
||||
let ret_addr: u64 = read_reg(&emu, Regs::Lr);
|
||||
|
||||
#[cfg(feature = "x86_64")]
|
||||
let stack_ptr: u64 = read_reg(&emu, Regs::Rsp);
|
||||
|
||||
#[cfg(feature = "x86_64")]
|
||||
let ret_addr: u64 = {
|
||||
let mut ret_addr = [0; 8];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
u64::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(feature = "i386")]
|
||||
let stack_ptr: u32 = read_reg(&emu, Regs::Esp);
|
||||
|
||||
#[cfg(feature = "i386")]
|
||||
let ret_addr: u32 = {
|
||||
let mut ret_addr = [0; 4];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
u32::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(feature = "mips")]
|
||||
let ret_addr: u32 = read_reg(&emu, Regs::Ra);
|
||||
|
||||
#[cfg(feature = "ppc")]
|
||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
||||
let pc: GuestReg = emu.read_reg(Regs::Pc).unwrap();
|
||||
println!("Break at {pc:#x}");
|
||||
|
||||
let ret_addr: GuestAddr = emu.read_return_address().unwrap();
|
||||
println!("Return address = {ret_addr:#x}");
|
||||
|
||||
emu.remove_breakpoint(test_one_input_ptr);
|
||||
@ -203,6 +147,21 @@ pub fn fuzz() {
|
||||
let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap();
|
||||
println!("Placing input at {input_addr:#x}");
|
||||
|
||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Sp).unwrap();
|
||||
|
||||
let reset = |buf: &[u8], len: GuestReg| -> Result<(), String> {
|
||||
unsafe {
|
||||
emu.write_mem(input_addr, buf);
|
||||
emu.write_reg(Regs::Pc, test_one_input_ptr)?;
|
||||
emu.write_reg(Regs::Sp, stack_ptr)?;
|
||||
emu.write_return_address(ret_addr)?;
|
||||
emu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?;
|
||||
emu.write_function_argument(CallingConvention::Cdecl, 1, len)?;
|
||||
emu.run();
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
let mut harness = |input: &BytesInput| {
|
||||
let target = input.target_bytes();
|
||||
let buf = target
|
||||
@ -211,65 +170,7 @@ pub fn fuzz() {
|
||||
.next()
|
||||
.expect("Failed to get chunk");
|
||||
let len = buf.len() as GuestReg;
|
||||
|
||||
unsafe {
|
||||
emu.write_mem(input_addr, buf);
|
||||
|
||||
#[cfg(feature = "arm")]
|
||||
{
|
||||
write_reg(&emu, Regs::R0, input_addr);
|
||||
write_reg(&emu, Regs::R1, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Lr, ret_addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "aarch64")]
|
||||
{
|
||||
write_reg(&emu, Regs::X0, input_addr);
|
||||
write_reg(&emu, Regs::X1, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Lr, ret_addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "x86_64")]
|
||||
{
|
||||
write_reg(&emu, Regs::Rdi, input_addr);
|
||||
write_reg(&emu, Regs::Rsi, len);
|
||||
write_reg(&emu, Regs::Rip, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Rsp, stack_ptr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "i386")]
|
||||
{
|
||||
let input_addr_bytes = input_addr.to_le_bytes();
|
||||
emu.write_mem(stack_ptr + (size_of::<u32>() as u32), &input_addr_bytes);
|
||||
|
||||
let len_bytes = len.to_le_bytes();
|
||||
emu.write_mem(stack_ptr + ((2 * size_of::<u32>()) as u32), &len_bytes);
|
||||
|
||||
write_reg(&emu, Regs::Eip, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Esp, stack_ptr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "mips")]
|
||||
{
|
||||
write_reg(&emu, Regs::A0, input_addr);
|
||||
write_reg(&emu, Regs::A1, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Ra, ret_addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ppc")]
|
||||
{
|
||||
write_reg(&emu, Regs::R3, input_addr);
|
||||
write_reg(&emu, Regs::R4, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Lr, ret_addr);
|
||||
}
|
||||
|
||||
emu.run();
|
||||
}
|
||||
|
||||
reset(buf, len).unwrap();
|
||||
ExitKind::Ok
|
||||
};
|
||||
|
||||
|
@ -7,12 +7,11 @@ edition = "2021"
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
be = []
|
||||
64bit = []
|
||||
be = ["libafl_qemu/be"]
|
||||
arm = ["libafl_qemu/arm"]
|
||||
x86_64 = ["libafl_qemu/x86_64", "64bit"]
|
||||
x86_64 = ["libafl_qemu/x86_64"]
|
||||
i386 = ["libafl_qemu/i386"]
|
||||
aarch64 = ["libafl_qemu/aarch64", "64bit"]
|
||||
aarch64 = ["libafl_qemu/aarch64"]
|
||||
mips = ["libafl_qemu/mips"]
|
||||
ppc = ["libafl_qemu/ppc", "be"]
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
//! A libfuzzer-like fuzzer using qemu for binary-only coverage
|
||||
//!
|
||||
#[cfg(feature = "i386")]
|
||||
use core::mem::size_of;
|
||||
use core::{ptr::addr_of_mut, time::Duration};
|
||||
use std::{env, path::PathBuf, process};
|
||||
|
||||
@ -36,16 +34,11 @@ use libafl_qemu::{
|
||||
edges::{edges_map_mut_slice, QemuEdgeCoverageHelper, MAX_EDGES_NUM},
|
||||
elf::EasyElf,
|
||||
emu::Emulator,
|
||||
MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs,
|
||||
ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, QemuExecutor, QemuHooks,
|
||||
QemuInstrumentationFilter, Regs,
|
||||
};
|
||||
use rangemap::RangeMap;
|
||||
|
||||
#[cfg(feature = "64bit")]
|
||||
type GuestReg = u64;
|
||||
|
||||
#[cfg(not(feature = "64bit"))]
|
||||
type GuestReg = u32;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Version;
|
||||
|
||||
@ -148,60 +141,10 @@ pub fn fuzz() {
|
||||
);
|
||||
}
|
||||
|
||||
let read_reg = |emu: &Emulator, reg: Regs| -> GuestReg {
|
||||
let val: GuestReg = emu.read_reg(reg).unwrap();
|
||||
|
||||
#[cfg(feature = "be")]
|
||||
return GuestReg::from_be(val);
|
||||
|
||||
#[cfg(not(feature = "be"))]
|
||||
return GuestReg::from_le(val);
|
||||
};
|
||||
|
||||
let write_reg = |emu: &Emulator, reg: Regs, val: GuestReg| {
|
||||
#[cfg(feature = "be")]
|
||||
let val = GuestReg::to_be(val);
|
||||
|
||||
#[cfg(not(feature = "be"))]
|
||||
let val = GuestReg::to_le(val);
|
||||
|
||||
emu.write_reg(reg, val).unwrap();
|
||||
};
|
||||
|
||||
println!("Break at {:#x}", read_reg(&emu, Regs::Pc));
|
||||
|
||||
#[cfg(feature = "arm")]
|
||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
||||
|
||||
#[cfg(feature = "aarch64")]
|
||||
let ret_addr: u64 = read_reg(&emu, Regs::Lr);
|
||||
|
||||
#[cfg(feature = "x86_64")]
|
||||
let stack_ptr: u64 = read_reg(&emu, Regs::Rsp);
|
||||
|
||||
#[cfg(feature = "x86_64")]
|
||||
let ret_addr: u64 = {
|
||||
let mut ret_addr = [0; 8];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
u64::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(feature = "i386")]
|
||||
let stack_ptr: u32 = read_reg(&emu, Regs::Esp);
|
||||
|
||||
#[cfg(feature = "i386")]
|
||||
let ret_addr: u32 = {
|
||||
let mut ret_addr = [0; 4];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
u32::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(feature = "mips")]
|
||||
let ret_addr: u32 = read_reg(&emu, Regs::Ra);
|
||||
|
||||
#[cfg(feature = "ppc")]
|
||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
||||
let pc: GuestReg = emu.read_reg(Regs::Pc).unwrap();
|
||||
println!("Break at {pc:#x}");
|
||||
|
||||
let ret_addr: GuestAddr = emu.read_return_address().unwrap();
|
||||
println!("Return address = {ret_addr:#x}");
|
||||
|
||||
emu.remove_breakpoint(test_one_input_ptr);
|
||||
@ -210,6 +153,21 @@ pub fn fuzz() {
|
||||
let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap();
|
||||
println!("Placing input at {input_addr:#x}");
|
||||
|
||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Sp).unwrap();
|
||||
|
||||
let reset = |buf: &[u8], len: GuestReg| -> Result<(), String> {
|
||||
unsafe {
|
||||
emu.write_mem(input_addr, buf);
|
||||
emu.write_reg(Regs::Pc, test_one_input_ptr)?;
|
||||
emu.write_reg(Regs::Sp, stack_ptr)?;
|
||||
emu.write_return_address(ret_addr)?;
|
||||
emu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?;
|
||||
emu.write_function_argument(CallingConvention::Cdecl, 1, len)?;
|
||||
emu.run();
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
let mut harness = |input: &BytesInput| {
|
||||
let target = input.target_bytes();
|
||||
let buf = target
|
||||
@ -218,65 +176,7 @@ pub fn fuzz() {
|
||||
.next()
|
||||
.expect("Failed to get chunk");
|
||||
let len = buf.len() as GuestReg;
|
||||
|
||||
unsafe {
|
||||
emu.write_mem(input_addr, buf);
|
||||
|
||||
#[cfg(feature = "arm")]
|
||||
{
|
||||
write_reg(&emu, Regs::R0, input_addr);
|
||||
write_reg(&emu, Regs::R1, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Lr, ret_addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "aarch64")]
|
||||
{
|
||||
write_reg(&emu, Regs::X0, input_addr);
|
||||
write_reg(&emu, Regs::X1, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Lr, ret_addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "x86_64")]
|
||||
{
|
||||
write_reg(&emu, Regs::Rdi, input_addr);
|
||||
write_reg(&emu, Regs::Rsi, len);
|
||||
write_reg(&emu, Regs::Rip, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Rsp, stack_ptr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "i386")]
|
||||
{
|
||||
let input_addr_bytes = input_addr.to_le_bytes();
|
||||
emu.write_mem(stack_ptr + (size_of::<u32>() as u32), &input_addr_bytes);
|
||||
|
||||
let len_bytes = len.to_le_bytes();
|
||||
emu.write_mem(stack_ptr + ((2 * size_of::<u32>()) as u32), &len_bytes);
|
||||
|
||||
write_reg(&emu, Regs::Eip, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Esp, stack_ptr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "mips")]
|
||||
{
|
||||
write_reg(&emu, Regs::A0, input_addr);
|
||||
write_reg(&emu, Regs::A1, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Ra, ret_addr);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ppc")]
|
||||
{
|
||||
write_reg(&emu, Regs::R3, input_addr);
|
||||
write_reg(&emu, Regs::R4, len);
|
||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
||||
write_reg(&emu, Regs::Lr, ret_addr);
|
||||
}
|
||||
|
||||
emu.run();
|
||||
}
|
||||
|
||||
reset(buf, len).unwrap();
|
||||
ExitKind::Ok
|
||||
};
|
||||
|
||||
|
@ -1867,13 +1867,13 @@ mod tests {
|
||||
#[test]
|
||||
fn test_read_tokens() {
|
||||
let _res = fs::remove_file("test.tkns");
|
||||
let data = r###"
|
||||
let data = r#"
|
||||
# comment
|
||||
token1@123="AAA"
|
||||
token1="A\x41A"
|
||||
"A\AA"
|
||||
token2="B"
|
||||
"###;
|
||||
"#;
|
||||
fs::write("test.tkns", data).expect("Unable to write test.tkns");
|
||||
let tokens = Tokens::from_file("test.tkns").unwrap();
|
||||
log::info!("Token file entries: {:?}", tokens.tokens());
|
||||
|
@ -385,14 +385,13 @@ impl Allocator {
|
||||
metadatas.sort_by(|a, b| a.address.cmp(&b.address));
|
||||
let mut offset_to_closest = i64::max_value();
|
||||
let mut closest = None;
|
||||
let ptr: i64 = ptr.try_into().unwrap();
|
||||
for metadata in metadatas {
|
||||
let address: i64 = metadata.address.try_into().unwrap();
|
||||
let new_offset = if hint_base == metadata.address {
|
||||
(ptr as i64 - metadata.address as i64).abs()
|
||||
(ptr - address).abs()
|
||||
} else {
|
||||
std::cmp::min(
|
||||
offset_to_closest,
|
||||
(ptr as i64 - metadata.address as i64).abs(),
|
||||
)
|
||||
std::cmp::min(offset_to_closest, (ptr - address).abs())
|
||||
};
|
||||
if new_offset < offset_to_closest {
|
||||
offset_to_closest = new_offset;
|
||||
|
@ -251,14 +251,13 @@ impl AsanErrors {
|
||||
cs.set_skipdata(true).expect("failed to set skipdata");
|
||||
|
||||
let start_pc = error.pc - 4 * 5;
|
||||
for insn in cs
|
||||
for insn in &*cs
|
||||
.disasm_count(
|
||||
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
|
||||
start_pc as u64,
|
||||
11,
|
||||
)
|
||||
.expect("failed to disassemble instructions")
|
||||
.iter()
|
||||
{
|
||||
if insn.address() as usize == error.pc {
|
||||
output
|
||||
@ -276,7 +275,9 @@ impl AsanErrors {
|
||||
|
||||
#[allow(clippy::non_ascii_literal)]
|
||||
writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap();
|
||||
let offset: i64 = fault_address as i64 - (error.metadata.address + 0x1000) as i64;
|
||||
let fault_address: i64 = fault_address.try_into().unwrap();
|
||||
let metadata_address: i64 = error.metadata.address.try_into().unwrap();
|
||||
let offset: i64 = fault_address - (metadata_address + 0x1000);
|
||||
let direction = if offset > 0 { "right" } else { "left" };
|
||||
writeln!(
|
||||
output,
|
||||
@ -505,14 +506,13 @@ impl AsanErrors {
|
||||
cs.set_skipdata(true).expect("failed to set skipdata");
|
||||
|
||||
let start_pc = pc;
|
||||
for insn in cs
|
||||
for insn in &*cs
|
||||
.disasm_count(
|
||||
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
|
||||
start_pc as u64,
|
||||
11,
|
||||
)
|
||||
.expect("failed to disassemble instructions")
|
||||
.iter()
|
||||
{
|
||||
if insn.address() as usize == pc {
|
||||
output
|
||||
|
@ -150,7 +150,7 @@ impl CoverageRuntime {
|
||||
; mov QWORD [rsp-0x98], rbx
|
||||
|
||||
// Load the previous_pc
|
||||
; mov rax, QWORD prev_loc_ptr as *mut u64 as _
|
||||
; mov rax, QWORD prev_loc_ptr as _
|
||||
; mov rax, QWORD [rax]
|
||||
|
||||
// Calculate the edge id
|
||||
@ -158,7 +158,7 @@ impl CoverageRuntime {
|
||||
; xor rax, rbx
|
||||
|
||||
// Load the map byte address
|
||||
; mov rbx, QWORD map_addr_ptr as *mut [u8; MAP_SIZE] as _
|
||||
; mov rbx, QWORD map_addr_ptr as _
|
||||
; add rax, rbx
|
||||
|
||||
// Update the map byte
|
||||
@ -168,7 +168,7 @@ impl CoverageRuntime {
|
||||
; mov BYTE [rax],bl
|
||||
|
||||
// Update the previous_pc value
|
||||
; mov rax, QWORD prev_loc_ptr as *mut u64 as _
|
||||
; mov rax, QWORD prev_loc_ptr as _
|
||||
; mov ebx, WORD (h64 >> 1) as i32
|
||||
; mov QWORD [rax], rbx
|
||||
|
||||
|
@ -4,6 +4,8 @@ use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
pub use syscall_numbers::aarch64::*;
|
||||
|
||||
use crate::CallingConvention;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
pub enum Regs {
|
||||
@ -62,3 +64,42 @@ impl IntoPy<PyObject> for Regs {
|
||||
pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new().arm64()
|
||||
}
|
||||
|
||||
pub type GuestReg = u64;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
self.read_reg(Regs::Lr)
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.write_reg(Regs::Lr, val)
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
let val: GuestReg = val.into();
|
||||
match idx {
|
||||
0 => self.write_reg(Regs::X0, val),
|
||||
1 => self.write_reg(Regs::X1, val),
|
||||
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
pub use syscall_numbers::arm::*;
|
||||
|
||||
use crate::CallingConvention;
|
||||
|
||||
/// Registers for the ARM instruction set.
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
@ -62,3 +64,42 @@ pub fn capstone_thumb() -> capstone::arch::arm::ArchCapstoneBuilder {
|
||||
.arm()
|
||||
.mode(capstone::arch::arm::ArchMode::Thumb)
|
||||
}
|
||||
|
||||
pub type GuestReg = u32;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
self.read_reg(Regs::Lr)
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.write_reg(Regs::Lr, val)
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
let val: GuestReg = val.into();
|
||||
match idx {
|
||||
0 => self.write_reg(Regs::R0, val),
|
||||
1 => self.write_reg(Regs::R1, val),
|
||||
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ impl AsanGiovese {
|
||||
if self.snapshot_shadow {
|
||||
let set = self.dirty_shadow.lock().unwrap();
|
||||
|
||||
for &page in set.iter() {
|
||||
for &page in &*set {
|
||||
let data = Self::get_shadow_page(emu, page).to_vec();
|
||||
self.saved_shadow.insert(page, data);
|
||||
}
|
||||
@ -425,7 +425,7 @@ impl AsanGiovese {
|
||||
if self.snapshot_shadow {
|
||||
let mut set = self.dirty_shadow.lock().unwrap();
|
||||
|
||||
for &page in set.iter() {
|
||||
for &page in &*set {
|
||||
let original = self.saved_shadow.get(&page);
|
||||
if let Some(data) = original {
|
||||
let cur = Self::get_shadow_page(emu, page);
|
||||
@ -472,7 +472,7 @@ pub fn init_with_asan(
|
||||
|e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..];
|
||||
|
||||
let mut added = false;
|
||||
for (k, v) in env.iter_mut() {
|
||||
for (k, v) in &mut *env {
|
||||
if k == "QEMU_SET_ENV" {
|
||||
let mut new_v = vec![];
|
||||
for e in v.split(',') {
|
||||
|
@ -10,10 +10,10 @@ use libafl::{
|
||||
|
||||
use crate::{
|
||||
capstone,
|
||||
emu::Emulator,
|
||||
emu::{ArchExtras, Emulator},
|
||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
GuestAddr, Regs,
|
||||
GuestAddr,
|
||||
};
|
||||
|
||||
pub trait CallTraceCollector: 'static + Debug {
|
||||
@ -242,51 +242,7 @@ where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
#[cfg(cpu_target = "x86_64")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Rsp).unwrap();
|
||||
let mut ret_addr = [0; 8];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
GuestAddr::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(cpu_target = "i386")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Esp).unwrap();
|
||||
let mut ret_addr = [0; 4];
|
||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
||||
GuestAddr::from_le_bytes(ret_addr)
|
||||
};
|
||||
|
||||
#[cfg(any(cpu_target = "arm", cpu_target = "aarch64"))]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
||||
ret_addr
|
||||
};
|
||||
|
||||
#[cfg(cpu_target = "mips")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Ra).unwrap();
|
||||
ret_addr
|
||||
};
|
||||
|
||||
#[cfg(cpu_target = "ppc")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
||||
ret_addr
|
||||
};
|
||||
|
||||
#[cfg(cpu_target = "hexagon")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
||||
ret_addr
|
||||
};
|
||||
let ret_addr: GuestAddr = hooks.emulator().read_return_address().unwrap();
|
||||
|
||||
// log::info!("RET @ 0x{:#x}", ret_addr);
|
||||
|
||||
|
@ -102,8 +102,8 @@ where
|
||||
if self.full_trace {
|
||||
if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
||||
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
||||
for id in DRCOV_IDS.lock().unwrap().as_ref().unwrap().iter() {
|
||||
'pcs_full: for (pc, idm) in DRCOV_MAP.lock().unwrap().as_ref().unwrap().iter() {
|
||||
for id in DRCOV_IDS.lock().unwrap().as_ref().unwrap() {
|
||||
'pcs_full: for (pc, idm) in DRCOV_MAP.lock().unwrap().as_ref().unwrap() {
|
||||
let mut module_found = false;
|
||||
for module in self.module_mapping.iter() {
|
||||
let (range, (_, _)) = module;
|
||||
@ -141,7 +141,7 @@ where
|
||||
} else {
|
||||
if DRCOV_MAP.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
||||
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
||||
'pcs: for (pc, _) in DRCOV_MAP.lock().unwrap().as_ref().unwrap().iter() {
|
||||
'pcs: for (pc, _) in DRCOV_MAP.lock().unwrap().as_ref().unwrap() {
|
||||
let mut module_found = false;
|
||||
for module in self.module_mapping.iter() {
|
||||
let (range, (_, _)) = module;
|
||||
|
@ -41,7 +41,7 @@ impl<'a> EasyElf<'a> {
|
||||
|
||||
#[must_use]
|
||||
pub fn resolve_symbol(&self, name: &str, load_addr: GuestAddr) -> Option<GuestAddr> {
|
||||
for sym in self.elf.syms.iter() {
|
||||
for sym in &self.elf.syms {
|
||||
if let Some(sym_name) = self.elf.strtab.get_at(sym.st_name) {
|
||||
if sym_name == name {
|
||||
return if sym.st_value == 0 {
|
||||
|
@ -17,6 +17,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use num_traits::Num;
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use crate::GuestReg;
|
||||
|
||||
pub type GuestAddr = libafl_qemu_sys::target_ulong;
|
||||
pub type GuestUsize = libafl_qemu_sys::target_ulong;
|
||||
pub type GuestIsize = libafl_qemu_sys::target_long;
|
||||
@ -485,6 +487,28 @@ pub struct CPU {
|
||||
ptr: CPUStatePtr,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum CallingConvention {
|
||||
Cdecl,
|
||||
}
|
||||
|
||||
pub trait ArchExtras {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>;
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>;
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>;
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
impl CPU {
|
||||
#[must_use]
|
||||
@ -617,8 +641,15 @@ impl CPU {
|
||||
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
|
||||
where
|
||||
R: Into<i32>,
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
let reg = reg.into();
|
||||
#[cfg(feature = "be")]
|
||||
let val = GuestReg::to_be(val.into());
|
||||
|
||||
#[cfg(not(feature = "be"))]
|
||||
let val = GuestReg::to_le(val.into());
|
||||
|
||||
let success = unsafe { libafl_qemu_write_reg(self.ptr, reg, addr_of!(val) as *const u8) };
|
||||
if success == 0 {
|
||||
Err(format!("Failed to write to register {reg}"))
|
||||
@ -630,6 +661,7 @@ impl CPU {
|
||||
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
|
||||
where
|
||||
R: Into<i32>,
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
unsafe {
|
||||
let reg = reg.into();
|
||||
@ -638,7 +670,11 @@ impl CPU {
|
||||
if success == 0 {
|
||||
Err(format!("Failed to read register {reg}"))
|
||||
} else {
|
||||
Ok(val.assume_init())
|
||||
#[cfg(feature = "be")]
|
||||
return Ok(GuestReg::from_be(val.assume_init()).into());
|
||||
|
||||
#[cfg(not(feature = "be"))]
|
||||
return Ok(GuestReg::from_le(val.assume_init()).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -739,11 +775,7 @@ impl Emulator {
|
||||
envp.push(null());
|
||||
unsafe {
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
qemu_user_init(
|
||||
argc,
|
||||
argv.as_ptr() as *const *const u8,
|
||||
envp.as_ptr() as *const *const u8,
|
||||
);
|
||||
qemu_user_init(argc, argv.as_ptr(), envp.as_ptr());
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
{
|
||||
qemu_init(
|
||||
@ -861,7 +893,7 @@ impl Emulator {
|
||||
|
||||
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Num + PartialOrd + Copy,
|
||||
T: Num + PartialOrd + Copy + Into<GuestReg>,
|
||||
R: Into<i32>,
|
||||
{
|
||||
self.current_cpu().unwrap().write_reg(reg, val)
|
||||
@ -869,7 +901,7 @@ impl Emulator {
|
||||
|
||||
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
|
||||
where
|
||||
T: Num + PartialOrd + Copy,
|
||||
T: Num + PartialOrd + Copy + From<GuestReg>,
|
||||
R: Into<i32>,
|
||||
{
|
||||
self.current_cpu().unwrap().read_reg(reg)
|
||||
@ -1154,6 +1186,40 @@ impl Emulator {
|
||||
}
|
||||
}
|
||||
|
||||
impl ArchExtras for Emulator {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
self.current_cpu()
|
||||
.ok_or("Failed to get current CPU")?
|
||||
.read_return_address::<T>()
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.current_cpu()
|
||||
.ok_or("Failed to get current CPU")?
|
||||
.write_return_address::<T>(val)
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.current_cpu()
|
||||
.ok_or("Failed to get current CPU")?
|
||||
.write_function_argument::<T>(conv, idx, val)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
pub mod pybind {
|
||||
use std::convert::TryFrom;
|
||||
|
@ -3,6 +3,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
|
||||
use crate::CallingConvention;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
pub enum Regs {
|
||||
@ -66,3 +68,37 @@ impl Regs {
|
||||
pub const Fp: Regs = Regs::R30;
|
||||
pub const Lr: Regs = Regs::R31;
|
||||
}
|
||||
|
||||
pub type GuestReg = u32;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
self.read_reg(Regs::Lr)
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.write_reg(Regs::Lr, val)
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
Err(format!("Unsupported argument: {idx:}"))
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::mem::size_of;
|
||||
|
||||
use capstone::arch::BuildsCapstone;
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
#[cfg(feature = "python")]
|
||||
@ -5,6 +7,8 @@ use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
pub use syscall_numbers::x86::*;
|
||||
|
||||
use crate::{CallingConvention, GuestAddr};
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
pub enum Regs {
|
||||
@ -41,3 +45,62 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
|
||||
.x86()
|
||||
.mode(capstone::arch::x86::ArchMode::Mode32)
|
||||
}
|
||||
|
||||
pub type GuestReg = u32;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?;
|
||||
let mut ret_addr = [0; size_of::<GuestReg>()];
|
||||
unsafe { self.read_mem(stack_ptr, &mut ret_addr) };
|
||||
Ok(GuestReg::from_le_bytes(ret_addr).into())
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?;
|
||||
let val: GuestReg = val.into();
|
||||
let ret_addr = val.to_le_bytes();
|
||||
unsafe { self.write_mem(stack_ptr, &ret_addr) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
match idx {
|
||||
0..=1 => {
|
||||
let val: GuestReg = val.into();
|
||||
let stack_ptr: GuestAddr = self.read_reg(Regs::Sp)?;
|
||||
/*
|
||||
* Stack is full and descending. SP points to return address, arguments
|
||||
* are in reverse order above that.
|
||||
*/
|
||||
let size: GuestAddr = size_of::<GuestReg>() as GuestAddr;
|
||||
let offset = size * (idx as GuestAddr + 1);
|
||||
|
||||
let arg = val.to_le_bytes();
|
||||
unsafe {
|
||||
self.write_mem(stack_ptr + offset, &arg);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
pub use syscall_numbers::mips::*;
|
||||
|
||||
use crate::CallingConvention;
|
||||
|
||||
/// Registers for the MIPS instruction set.
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
@ -62,3 +64,42 @@ impl IntoPy<PyObject> for Regs {
|
||||
pub fn capstone() -> capstone::arch::mips::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new().mips()
|
||||
}
|
||||
|
||||
pub type GuestReg = u32;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
self.read_reg(Regs::Ra)
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.write_reg(Regs::Ra, val)
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
let val: GuestReg = val.into();
|
||||
match idx {
|
||||
0 => self.write_reg(Regs::A0, val),
|
||||
1 => self.write_reg(Regs::A1, val),
|
||||
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
pub use syscall_numbers::powerpc::*;
|
||||
|
||||
use crate::CallingConvention;
|
||||
|
||||
/// Registers for the MIPS instruction set.
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
@ -87,6 +89,7 @@ pub enum Regs {
|
||||
#[allow(non_upper_case_globals)]
|
||||
impl Regs {
|
||||
pub const Pc: Regs = Regs::Nip;
|
||||
pub const Sp: Regs = Regs::R1;
|
||||
}
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
@ -101,3 +104,42 @@ impl IntoPy<PyObject> for Regs {
|
||||
pub fn capstone() -> capstone::arch::ppc::ArchCapstoneBuilder {
|
||||
capstone::Capstone::new().ppc()
|
||||
}
|
||||
|
||||
pub type GuestReg = u32;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
self.read_reg(Regs::Lr)
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
self.write_reg(Regs::Lr, val)
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
let val: GuestReg = val.into();
|
||||
match idx {
|
||||
0 => self.write_reg(Regs::R3, val),
|
||||
1 => self.write_reg(Regs::R4, val),
|
||||
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ impl QemuSnapshotHelper {
|
||||
{
|
||||
let new_maps = self.new_maps.get_mut().unwrap();
|
||||
|
||||
for acc in self.accesses.iter_mut() {
|
||||
for acc in &mut self.accesses {
|
||||
unsafe { &mut (*acc.get()) }.dirty.retain(|page| {
|
||||
if let Some(info) = self.pages.get_mut(page) {
|
||||
// TODO avoid duplicated memcpy
|
||||
@ -251,7 +251,7 @@ impl QemuSnapshotHelper {
|
||||
self.reset_maps(emulator);
|
||||
|
||||
// This one is after that we remapped potential regions mapped at snapshot time but unmapped during execution
|
||||
for acc in self.accesses.iter_mut() {
|
||||
for acc in &mut self.accesses {
|
||||
for page in unsafe { &(*acc.get()).dirty } {
|
||||
for entry in self
|
||||
.maps
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::mem::size_of;
|
||||
|
||||
use capstone::arch::BuildsCapstone;
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
#[cfg(feature = "python")]
|
||||
@ -5,6 +7,8 @@ use pyo3::prelude::*;
|
||||
pub use strum_macros::EnumIter;
|
||||
pub use syscall_numbers::x86_64::*;
|
||||
|
||||
use crate::CallingConvention;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[repr(i32)]
|
||||
pub enum Regs {
|
||||
@ -50,3 +54,49 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
|
||||
.x86()
|
||||
.mode(capstone::arch::x86::ArchMode::Mode64)
|
||||
}
|
||||
|
||||
pub type GuestReg = u64;
|
||||
|
||||
impl crate::ArchExtras for crate::CPU {
|
||||
fn read_return_address<T>(&self) -> Result<T, String>
|
||||
where
|
||||
T: From<GuestReg>,
|
||||
{
|
||||
let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?;
|
||||
let mut ret_addr = [0; size_of::<GuestReg>()];
|
||||
unsafe { self.read_mem(stack_ptr, &mut ret_addr) };
|
||||
Ok(GuestReg::from_le_bytes(ret_addr).into())
|
||||
}
|
||||
|
||||
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?;
|
||||
let val: GuestReg = val.into();
|
||||
let ret_addr = val.to_le_bytes();
|
||||
unsafe { self.write_mem(stack_ptr, &ret_addr) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_function_argument<T>(
|
||||
&self,
|
||||
conv: CallingConvention,
|
||||
idx: i32,
|
||||
val: T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Into<GuestReg>,
|
||||
{
|
||||
if conv != CallingConvention::Cdecl {
|
||||
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||
}
|
||||
|
||||
let val: GuestReg = val.into();
|
||||
match idx {
|
||||
0 => self.write_reg(Regs::Rdi, val),
|
||||
1 => self.write_reg(Regs::Rsi, val),
|
||||
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ mod observers {
|
||||
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
|
||||
for map in unsafe { &COUNTERS_MAPS } {
|
||||
let slice = map.as_slice();
|
||||
let ptr = slice.as_ptr() as *const u8;
|
||||
let ptr = slice.as_ptr();
|
||||
let map_size = slice.len() / core::mem::size_of::<u8>();
|
||||
unsafe {
|
||||
hasher.write(from_raw_parts(ptr, map_size));
|
||||
|
@ -22,11 +22,11 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
||||
{
|
||||
#[cfg(feature = "sancov_pcguard_edges")]
|
||||
{
|
||||
(EDGES_MAP_PTR as *mut u8).add(pos).write(1);
|
||||
EDGES_MAP_PTR.add(pos).write(1);
|
||||
}
|
||||
#[cfg(feature = "sancov_pcguard_hitcounts")]
|
||||
{
|
||||
let addr = (EDGES_MAP_PTR as *mut u8).add(pos);
|
||||
let addr = EDGES_MAP_PTR.add(pos);
|
||||
let val = addr.read().wrapping_add(1);
|
||||
addr.write(val);
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton {
|
||||
//let mut culled_pda_unique = HashSet::new();
|
||||
|
||||
for final_state in &finals {
|
||||
for transition in pda.iter() {
|
||||
for transition in pda {
|
||||
if transition.dest == *final_state && transition.stack.len() > 0 {
|
||||
blocklist.insert(transition.dest);
|
||||
} else {
|
||||
@ -267,7 +267,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton {
|
||||
}
|
||||
} else {
|
||||
// Running FSA construction in exact approximation mode and postprocessing it like so
|
||||
for transition in pda.iter() {
|
||||
for transition in pda {
|
||||
num_transition += 1;
|
||||
let state = transition.source;
|
||||
if state >= memoized.len() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user