mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-08 16:21:32 +00:00
tried to fix rust example
This commit is contained in:
parent
b0a8bc28d2
commit
fea0286989
@ -1,8 +1,7 @@
|
|||||||
extern crate capstone;
|
extern crate capstone;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use core::cell::{Cell, RefCell};
|
use core::cell::Cell;
|
||||||
use libc::{c_void, munmap};
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
fs::File,
|
fs::File,
|
||||||
@ -12,8 +11,8 @@ use std::{
|
|||||||
|
|
||||||
use unicornafl::{
|
use unicornafl::{
|
||||||
unicorn_const::{uc_error, Arch, Mode, Permission},
|
unicorn_const::{uc_error, Arch, Mode, Permission},
|
||||||
utils::*,
|
RegisterX86::{self, *},
|
||||||
RegisterX86::*,
|
Unicorn, UnicornHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
const BINARY: &str = &"../target";
|
const BINARY: &str = &"../target";
|
||||||
@ -36,17 +35,6 @@ const STACK_ADDRESS: u64 = 0x00400000;
|
|||||||
// Size of the stack (arbitrarily chosen, just make it big enough)
|
// Size of the stack (arbitrarily chosen, just make it big enough)
|
||||||
const STACK_SIZE: u64 = 0x000F0000;
|
const STACK_SIZE: u64 = 0x000F0000;
|
||||||
|
|
||||||
macro_rules! hook {
|
|
||||||
($addr:expr, $func:expr) => {
|
|
||||||
uc.add_code_hook($addr, $addr, Box::new($func))
|
|
||||||
.expect(&format!("failed to set {} hook", stringify!($func)));
|
|
||||||
};
|
|
||||||
($addr:expr, $func:expr, $opt_name:expr) => {
|
|
||||||
uc.add_code_hook($addr, $addr, Box::new($func))
|
|
||||||
.expect(&format!("failed to set {} hook", $opt_name));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> {
|
fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> {
|
||||||
let mut f = File::open(filename)?;
|
let mut f = File::open(filename)?;
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
@ -57,10 +45,10 @@ fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> {
|
|||||||
/// Our location parser
|
/// Our location parser
|
||||||
fn parse_locs(loc_name: &str) -> Result<Vec<u64>, io::Error> {
|
fn parse_locs(loc_name: &str) -> Result<Vec<u64>, io::Error> {
|
||||||
let contents = &read_file(&format!("../target.offsets.{}", loc_name))?;
|
let contents = &read_file(&format!("../target.offsets.{}", loc_name))?;
|
||||||
str_from_u8_unchecked(&contents)
|
Ok(str_from_u8_unchecked(&contents)
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.filter_map(|x| u64::from_str_radix(x, 16))
|
.flat_map(|x| u64::from_str_radix(x, 16))
|
||||||
.collect()
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
// find null terminated string in vec
|
// find null terminated string in vec
|
||||||
@ -89,31 +77,31 @@ fn main() {
|
|||||||
}
|
}
|
||||||
let input_file = &args[1];
|
let input_file = &args[1];
|
||||||
println!("The input testcase is set to {}", input_file);
|
println!("The input testcase is set to {}", input_file);
|
||||||
uclate(input_file).unwrap();
|
fuzz(input_file).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uclate(input_file: &str) -> Result<(), io::Error> {
|
fn fuzz(input_file: &str) -> Result<(), uc_error> {
|
||||||
let mut uc = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?;
|
let unicorn = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?;
|
||||||
|
let mut uc = unicorn.borrow();
|
||||||
|
|
||||||
let binary = read_file(BINARY).expect(&format!("Could not read modem image: {}", BINARY));
|
let binary = read_file(BINARY).expect(&format!("Could not read modem image: {}", BINARY));
|
||||||
let aligned_binary_size = align(binary.len() as u64);
|
let aligned_binary_size = align(binary.len() as u64);
|
||||||
// Apply constraints to the mutated input
|
// Apply constraints to the mutated input
|
||||||
if binary.len() as u64 > CODE_SIZE_MAX {
|
if binary.len() as u64 > CODE_SIZE_MAX {
|
||||||
println!("Binary code is too large (> {} bytes)", CODE_SIZE_MAX);
|
println!("Binary code is too large (> {} bytes)", CODE_SIZE_MAX);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the binary to its place in mem
|
// Write the binary to its place in mem
|
||||||
uc.mem_map(
|
uc.mem_map(
|
||||||
BASE_ADDRESS,
|
BASE_ADDRESS,
|
||||||
CODE_SIZE_MAX,
|
CODE_SIZE_MAX as usize,
|
||||||
Permission::READ | Permission::WRITE,
|
Permission::READ | Permission::WRITE,
|
||||||
)?;
|
)?;
|
||||||
uc.mem_write(BASE_ADDR, binary);
|
uc.mem_write(BASE_ADDRESS, &binary);
|
||||||
|
|
||||||
// Set the program counter to the start of the code
|
// Set the program counter to the start of the code
|
||||||
let main_locs = parse_locs("main")?;
|
let main_locs = parse_locs("main").unwrap();
|
||||||
uc.reg_write(RIP, main_locs[0])?;
|
uc.reg_write(RegisterX86::RIP as i32, main_locs[0])?;
|
||||||
|
|
||||||
// Setup the stack.
|
// Setup the stack.
|
||||||
uc.mem_map(
|
uc.mem_map(
|
||||||
@ -122,30 +110,32 @@ fn uclate(input_file: &str) -> Result<(), io::Error> {
|
|||||||
Permission::READ | Permission::WRITE,
|
Permission::READ | Permission::WRITE,
|
||||||
)?;
|
)?;
|
||||||
// Setup the stack pointer, but allocate two pointers for the pointers to input.
|
// Setup the stack pointer, but allocate two pointers for the pointers to input.
|
||||||
uc.reg_write(RSP, STACK_ADDRESS + STACK_SIZE - 16)?;
|
uc.reg_write(RSP as i32, STACK_ADDRESS + STACK_SIZE - 16)?;
|
||||||
|
|
||||||
// Setup our input space, and push the pointer to it in the function params
|
// Setup our input space, and push the pointer to it in the function params
|
||||||
uc.mem_map(INPUT_ADDRESS, INPUT_MAX as usize, Permission::READ)?;
|
uc.mem_map(INPUT_ADDRESS, INPUT_MAX as usize, Permission::READ)?;
|
||||||
// We have argc = 2
|
// We have argc = 2
|
||||||
uc.reg_write(RDI, 2)?;
|
uc.reg_write(RDI as i32, 2)?;
|
||||||
// RSI points to our little 2 QWORD space at the beginning of the stack...
|
// RSI points to our little 2 QWORD space at the beginning of the stack...
|
||||||
uc.reg_write(RSI, STACK_ADDRESS + STACK_SIZE - 16)?;
|
uc.reg_write(RSI as i32, STACK_ADDRESS + STACK_SIZE - 16)?;
|
||||||
// ... which points to the Input. Write the ptr to mem in little endian.
|
// ... which points to the Input. Write the ptr to mem in little endian.
|
||||||
uc.mem_write(
|
uc.mem_write(
|
||||||
STACK_ADDRESS + STACK_SIZE - 16,
|
STACK_ADDRESS + STACK_SIZE - 16,
|
||||||
(INPUT_ADDRESS as u32).to_le_bytes(),
|
&(INPUT_ADDRESS as u32).to_le_bytes(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let already_allocated = Cell::new(false);
|
let already_allocated = Cell::new(false);
|
||||||
|
|
||||||
let already_allocated_malloc = already_allocated.clone();
|
let already_allocated_malloc = already_allocated.clone();
|
||||||
let hook_malloc = move |mut uc: Unicorn, addr: u64, size: u32| {
|
// We use a very simple malloc/free stub here,
|
||||||
|
// that only works for exactly one allocation at a time.
|
||||||
|
let hook_malloc = move |mut uc: UnicornHandle<'_, _>, addr: u64, size: u32| {
|
||||||
if already_allocated_malloc.get() {
|
if already_allocated_malloc.get() {
|
||||||
println!("Double malloc, not supported right now!");
|
println!("Double malloc, not supported right now!");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
// read the first param
|
// read the first param
|
||||||
let malloc_size = uc.reg_read(RDI).unwrap();
|
let malloc_size = uc.reg_read(RDI as i32).unwrap();
|
||||||
if malloc_size > HEAP_SIZE_MAX {
|
if malloc_size > HEAP_SIZE_MAX {
|
||||||
println!(
|
println!(
|
||||||
"Tried to allocate {} bytes, but we may only allocate up to {}",
|
"Tried to allocate {} bytes, but we may only allocate up to {}",
|
||||||
@ -153,19 +143,21 @@ fn uclate(input_file: &str) -> Result<(), io::Error> {
|
|||||||
);
|
);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
uc.reg_write(RAX, HEAP_ADDRESS).unwrap();
|
uc.reg_write(RAX as i32, HEAP_ADDRESS).unwrap();
|
||||||
uc.reg_write(RIP, addr + size as u64).unwrap();
|
uc.reg_write(RIP as i32, addr + size as u64).unwrap();
|
||||||
already_allocated_malloc.set(true);
|
already_allocated_malloc.set(true);
|
||||||
|
Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let already_allocated_free = already_allocated.clone();
|
let already_allocated_free = already_allocated.clone();
|
||||||
let hook_free = move |mut uc: Unicorn, addr: u64, size: u32| {
|
// No real free, just set the "used"-flag to false.
|
||||||
|
let hook_free = move |mut uc: UnicornHandle<'_, _>, addr, size| {
|
||||||
if already_allocated_free.get() {
|
if already_allocated_free.get() {
|
||||||
println!("Double free detected. Real bug?");
|
println!("Double free detected. Real bug?");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
// read the first param
|
// read the first param
|
||||||
let free_ptr = uc.reg_read(RDI).unwrap();
|
let free_ptr = uc.reg_read(RDI as i32).unwrap();
|
||||||
if free_ptr != HEAP_ADDRESS {
|
if free_ptr != HEAP_ADDRESS {
|
||||||
println!(
|
println!(
|
||||||
"Tried to free wrong mem region {:x} at code loc {:x}",
|
"Tried to free wrong mem region {:x} at code loc {:x}",
|
||||||
@ -173,30 +165,35 @@ fn uclate(input_file: &str) -> Result<(), io::Error> {
|
|||||||
);
|
);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
uc.reg_write(RIP, addr + size as u64);
|
uc.reg_write(RIP as i32, addr + size as u64);
|
||||||
already_allocated_free.set(false);
|
already_allocated_free.set(false);
|
||||||
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
BEGIN FUNCTION HOOKS
|
BEGIN FUNCTION HOOKS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let hook_magicfn =
|
// This is a fancy print function that we're just going to skip for fuzzing.
|
||||||
move |mut uc: Unicorn, addr: u64, size: u32| uc.reg_write(RIP, address + size as u64);
|
let hook_magicfn = move |mut uc: UnicornHandle<'_, _>, addr, size| {
|
||||||
|
uc.reg_write(RIP as i32, addr + size as u64);
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
for addr in parse_locs("malloc")? {
|
for addr in parse_locs("malloc").unwrap() {
|
||||||
hook!(addr, hook_malloc, "malloc");
|
//hook!(addr, hook_malloc, "malloc");
|
||||||
|
uc.add_code_hook(addr, addr, Box::new(hook_malloc))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr in parse_locs("free")? {
|
for addr in parse_locs("free").unwrap() {
|
||||||
hook!(addr, hook_free, "free");
|
uc.add_code_hook(addr, addr, Box::new(hook_free))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr in parse_locs("magicfn")? {
|
for addr in parse_locs("magicfn").unwrap() {
|
||||||
hook!(addr, hook_magicfn, "magicfn");
|
uc.add_code_hook(addr, addr, Box::new(hook_magicfn))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let place_input_callback = |mut uc: Unicorn, afl_input: &[u8], _persistent_round: i32| {
|
let place_input_callback = |mut uc, afl_input, _persistent_round| {
|
||||||
// apply constraints to the mutated input
|
// apply constraints to the mutated input
|
||||||
if afl_input.len() > INPUT_MAX as usize {
|
if afl_input.len() > INPUT_MAX as usize {
|
||||||
//println!("Skipping testcase with leng {}", afl_input.len());
|
//println!("Skipping testcase with leng {}", afl_input.len());
|
||||||
@ -208,10 +205,9 @@ fn uclate(input_file: &str) -> Result<(), io::Error> {
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
let crash_validation_callback =
|
let crash_validation_callback = |uc, result, _input, _persistent_round| result != uc_error::OK;
|
||||||
|uc: Unicorn, result: uc_error, _input: &[u8], _: i32| result != uc_error::OK;
|
|
||||||
|
|
||||||
end_addrs = parse_locs("main_ends")?;
|
let end_addrs = parse_locs("main_ends").unwrap();
|
||||||
|
|
||||||
let ret = uc.afl_fuzz(
|
let ret = uc.afl_fuzz(
|
||||||
input_file,
|
input_file,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user