Make FridaInProcessExecutor compatible with TargetBytesConverter, decouple input type from FridaRuntime trait (#2741)

* decouple input type from FridaRuntime trait

* fmt

* fmt2

* remove HasTargetBytes requirement from FridaInProcessExecutor

* fmt

* restore comment

* fix clippy comment error
This commit is contained in:
jejuisland87654 2024-12-03 23:44:19 +01:00 committed by GitHub
parent ffbb7a0f42
commit 1809c31a46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 84 additions and 83 deletions

View File

@ -27,7 +27,7 @@ use frida_gum::{
}; };
use frida_gum_sys::Insn; use frida_gum_sys::Insn;
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl_bolts::{cli::FuzzerOptions, AsSlice}; use libafl_bolts::cli::FuzzerOptions;
use libc::wchar_t; use libc::wchar_t;
use rangemap::RangeMap; use rangemap::RangeMap;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@ -190,33 +190,22 @@ impl FridaRuntime for AsanRuntime {
self.deregister_hooks(gum); self.deregister_hooks(gum);
} }
fn pre_exec<I: libafl::inputs::Input + libafl::inputs::HasTargetBytes>( fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), libafl::Error> {
&mut self, self.unpoison(input_bytes.as_ptr() as usize, input_bytes.len());
input: &I,
) -> Result<(), libafl::Error> {
let target_bytes = input.target_bytes();
let slice = target_bytes.as_slice();
self.unpoison(slice.as_ptr() as usize, slice.len());
self.enable_hooks(); self.enable_hooks();
Ok(()) Ok(())
} }
fn post_exec<I: libafl::inputs::Input + libafl::inputs::HasTargetBytes>( fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), libafl::Error> {
&mut self,
input: &I,
) -> Result<(), libafl::Error> {
self.disable_hooks(); self.disable_hooks();
if self.check_for_leaks_enabled { if self.check_for_leaks_enabled {
self.check_for_leaks(); self.check_for_leaks();
} }
let target_bytes = input.target_bytes();
let slice = target_bytes.as_slice();
// # Safety // # Safety
// The ptr and length are correct. // The ptr and length are correct.
unsafe { unsafe {
self.poison(slice.as_ptr() as usize, slice.len()); self.poison(input_bytes.as_ptr() as usize, input_bytes.len());
} }
self.reset_allocations(); self.reset_allocations();

View File

@ -29,10 +29,7 @@ use iced_x86::{
BlockEncoder, Code, DecoderOptions, Instruction, InstructionBlock, MemoryOperand, MemorySize, BlockEncoder, Code, DecoderOptions, Instruction, InstructionBlock, MemoryOperand, MemorySize,
OpKind, Register, OpKind, Register,
}; };
use libafl::{ use libafl::Error;
inputs::{HasTargetBytes, Input},
Error,
};
use libafl_targets::{cmps::__libafl_targets_cmplog_instructions, CMPLOG_MAP_W}; use libafl_targets::{cmps::__libafl_targets_cmplog_instructions, CMPLOG_MAP_W};
use rangemap::RangeMap; use rangemap::RangeMap;
@ -132,11 +129,11 @@ impl FridaRuntime for CmpLogRuntime {
fn deinit(&mut self, _gum: &frida_gum::Gum) {} fn deinit(&mut self, _gum: &frida_gum::Gum) {}
fn pre_exec<I: Input + HasTargetBytes>(&mut self, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _input_bytes: &[u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn post_exec<I: Input + HasTargetBytes>(&mut self, _input: &I) -> Result<(), Error> { fn post_exec(&mut self, _input_bytes: &[u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }

View File

@ -44,17 +44,11 @@ impl FridaRuntime for CoverageRuntime {
fn deinit(&mut self, _gum: &frida_gum::Gum) {} fn deinit(&mut self, _gum: &frida_gum::Gum) {}
fn pre_exec<I: libafl::inputs::Input + libafl::inputs::HasTargetBytes>( fn pre_exec(&mut self, _input_bytes: &[u8]) -> Result<(), libafl::Error> {
&mut self,
_input: &I,
) -> Result<(), libafl::Error> {
Ok(()) Ok(())
} }
fn post_exec<I: libafl::inputs::Input + libafl::inputs::HasTargetBytes>( fn post_exec(&mut self, _input_bytes: &[u8]) -> Result<(), libafl::Error> {
&mut self,
_input: &I,
) -> Result<(), libafl::Error> {
Ok(()) Ok(())
} }
} }

View File

@ -7,11 +7,7 @@ use std::{
use ahash::RandomState; use ahash::RandomState;
use frida_gum::ModuleMap; use frida_gum::ModuleMap;
use libafl::{ use libafl::Error;
inputs::{HasTargetBytes, Input},
Error,
};
use libafl_bolts::AsSlice;
use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter}; use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter};
use rangemap::RangeMap; use rangemap::RangeMap;
@ -43,20 +39,20 @@ impl FridaRuntime for DrCovRuntime {
fn deinit(&mut self, _gum: &frida_gum::Gum) {} fn deinit(&mut self, _gum: &frida_gum::Gum) {}
/// Called before execution, does nothing /// Called before execution, does nothing
fn pre_exec<I: Input + HasTargetBytes>(&mut self, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _input_bytes: &[u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Called after execution, writes the trace to a unique `DrCov` file for this trace /// Called after execution, writes the trace to a unique `DrCov` file for this trace
/// into `./coverage/<input_hash>_<coverage_hash>.drcov`. Empty coverages will be skipped. /// into `./coverage/<input_hash>_<coverage_hash>.drcov`. Empty coverages will be skipped.
fn post_exec<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error> { fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> {
// We don't need empty coverage files // We don't need empty coverage files
if self.drcov_basic_blocks.is_empty() { if self.drcov_basic_blocks.is_empty() {
return Ok(()); return Ok(());
} }
let mut input_hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); let mut input_hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
input_hasher.write(input.target_bytes().as_slice()); input_hasher.write(input_bytes);
let input_hash = input_hasher.finish(); let input_hash = input_hasher.finish();
let mut coverage_hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); let mut coverage_hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();

View File

@ -15,12 +15,12 @@ use libafl::{
}; };
use libafl::{ use libafl::{
executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
inputs::HasTargetBytes, inputs::{HasTargetBytes, NopTargetBytesConverter, TargetBytesConverter},
observers::ObserversTuple, observers::ObserversTuple,
state::{HasExecutions, State, UsesState}, state::{HasExecutions, State, UsesState},
Error, Error,
}; };
use libafl_bolts::tuples::RefIndexable; use libafl_bolts::{tuples::RefIndexable, AsSlice};
#[cfg(not(test))] #[cfg(not(test))]
use crate::asan::errors::AsanErrors; use crate::asan::errors::AsanErrors;
@ -29,30 +29,31 @@ use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple};
use crate::windows_hooks::initialize; use crate::windows_hooks::initialize;
/// The [`FridaInProcessExecutor`] is an [`Executor`] that executes the target in the same process, usinig [`frida`](https://frida.re/) for binary-only instrumentation. /// The [`FridaInProcessExecutor`] is an [`Executor`] that executes the target in the same process, usinig [`frida`](https://frida.re/) for binary-only instrumentation.
pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S::Input: HasTargetBytes, TC: TargetBytesConverter<Input = S::Input>,
S: State, S: State,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
'b: 'a, 'b: 'a,
{ {
base: InProcessExecutor<'a, H, OT, S>, base: InProcessExecutor<'a, H, OT, S>,
// thread_id for the Stalker /// `thread_id` for the Stalker
thread_id: Option<u32>, thread_id: Option<u32>,
/// Frida's dynamic rewriting engine /// Frida's dynamic rewriting engine
stalker: Stalker, stalker: Stalker,
/// User provided callback for instrumentation /// User provided callback for instrumentation
helper: &'c mut FridaInstrumentationHelper<'b, RT>, helper: &'c mut FridaInstrumentationHelper<'b, RT>,
target_bytes_converter: TC,
followed: bool, followed: bool,
_phantom: PhantomData<&'b u8>, _phantom: PhantomData<&'b u8>,
} }
impl<H, OT, RT, S> Debug for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> impl<H, OT, RT, S, TC> Debug for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S: State, S: State,
S::Input: HasTargetBytes, TC: TargetBytesConverter<Input = S::Input>,
OT: ObserversTuple<S::Input, S> + Debug, OT: ObserversTuple<S::Input, S> + Debug,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -64,12 +65,13 @@ where
} }
} }
impl<EM, H, OT, RT, S, Z> Executor<EM, Z> for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> impl<EM, H, OT, RT, S, TC, Z> Executor<EM, Z>
for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC>
where where
EM: UsesState<State = S>, EM: UsesState<State = S>,
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S: State + HasExecutions, S: State + HasExecutions,
S::Input: HasTargetBytes, TC: TargetBytesConverter<Input = S::Input>,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
RT: FridaRuntimeTuple, RT: FridaRuntimeTuple,
Z: UsesState<State = S>, Z: UsesState<State = S>,
@ -83,7 +85,8 @@ where
mgr: &mut EM, mgr: &mut EM,
input: &Self::Input, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.helper.pre_exec(input)?; let target_bytes = self.target_bytes_converter.to_target_bytes(input);
self.helper.pre_exec(target_bytes.as_slice())?;
if self.helper.stalker_enabled() { if self.helper.stalker_enabled() {
if self.followed { if self.followed {
self.stalker.activate(NativePointer(core::ptr::null_mut())); self.stalker.activate(NativePointer(core::ptr::null_mut()));
@ -115,25 +118,25 @@ where
abort(); abort();
} }
} }
self.helper.post_exec(input)?; self.helper.post_exec(target_bytes.as_slice())?;
res res
} }
} }
impl<H, OT, RT, S> UsesState for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> impl<H, OT, RT, S, TC> UsesState for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: State, S: State,
S::Input: HasTargetBytes, TC: TargetBytesConverter<Input = S::Input>,
{ {
type State = S; type State = S;
} }
impl<H, OT, RT, S> HasObservers for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> impl<H, OT, RT, S, TC> HasObservers for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S::Input: HasTargetBytes, TC: TargetBytesConverter<Input = S::Input>,
S: State, S: State,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
{ {
@ -149,7 +152,8 @@ where
} }
} }
impl<'a, 'b, 'c, H, OT, S, RT> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> impl<'a, 'b, 'c, H, OT, RT, S>
FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, NopTargetBytesConverter<S::Input>>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S: State, S: State,
@ -163,7 +167,13 @@ where
base: InProcessExecutor<'a, H, OT, S>, base: InProcessExecutor<'a, H, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>, helper: &'c mut FridaInstrumentationHelper<'b, RT>,
) -> Self { ) -> Self {
Self::_on_thread(gum, base, helper, None) FridaInProcessExecutor::with_target_bytes_converter(
gum,
base,
helper,
None,
NopTargetBytesConverter::new(),
)
} }
/// Creates a new [`FridaInProcessExecutor`] tracking the given `thread_id`. /// Creates a new [`FridaInProcessExecutor`] tracking the given `thread_id`.
@ -173,23 +183,40 @@ where
helper: &'c mut FridaInstrumentationHelper<'b, RT>, helper: &'c mut FridaInstrumentationHelper<'b, RT>,
thread_id: u32, thread_id: u32,
) -> Self { ) -> Self {
Self::_on_thread(gum, base, helper, Some(thread_id)) FridaInProcessExecutor::with_target_bytes_converter(
gum,
base,
helper,
Some(thread_id),
NopTargetBytesConverter::new(),
)
} }
}
/// Creates a new [`FridaInProcessExecutor`] tracking the given `thread_id`, of `thread_id` is provided. impl<'a, 'b, 'c, H, OT, RT, S, TC> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC>
fn _on_thread( where
H: FnMut(&S::Input) -> ExitKind,
S: State,
TC: TargetBytesConverter<Input = S::Input>,
OT: ObserversTuple<S::Input, S>,
RT: FridaRuntimeTuple,
{
/// Creates a new [`FridaInProcessExecutor`].
pub fn with_target_bytes_converter(
gum: &'a Gum, gum: &'a Gum,
base: InProcessExecutor<'a, H, OT, S>, base: InProcessExecutor<'a, H, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>, helper: &'c mut FridaInstrumentationHelper<'b, RT>,
thread_id: Option<u32>, thread_id: Option<u32>,
target_bytes_converter: TC,
) -> Self { ) -> Self {
let mut stalker = Stalker::new(gum); let mut stalker = Stalker::new(gum);
// Include the current module (the fuzzer) in stalked ranges. We clone the ranges so that // Include the current module (the fuzzer) in stalked ranges. We clone the ranges so that
// we don't add it to the INSTRUMENTED ranges. // we don't add it to the INSTRUMENTED ranges.
let mut ranges = helper.ranges().clone(); let mut ranges = helper.ranges().clone();
for module in frida_gum::Module::obtain(gum).enumerate_modules() { for module in frida_gum::Module::obtain(gum).enumerate_modules() {
if module.base_address < Self::new as usize if module.base_address < Self::with_target_bytes_converter as usize
&& (Self::new as usize as u64) < module.base_address as u64 + module.size as u64 && (Self::with_target_bytes_converter as usize as u64)
< module.base_address as u64 + module.size as u64
{ {
ranges.insert( ranges.insert(
module.base_address as u64..(module.base_address as u64 + module.size as u64), module.base_address as u64..(module.base_address as u64 + module.size as u64),
@ -220,6 +247,7 @@ where
thread_id, thread_id,
stalker, stalker,
helper, helper,
target_bytes_converter,
followed: false, followed: false,
_phantom: PhantomData, _phantom: PhantomData,
} }
@ -227,12 +255,12 @@ where
} }
#[cfg(windows)] #[cfg(windows)]
impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHooks<S> impl<'a, 'b, 'c, H, OT, RT, S, TC> HasInProcessHooks<S>
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC>
where where
H: FnMut(&S::Input) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
S: State + HasSolutions + HasCorpus + HasExecutions, S: State + HasSolutions + HasCorpus + HasExecutions,
S::Input: HasTargetBytes, TC: TargetBytesConverter<Input = S::Input>,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
RT: FridaRuntimeTuple, RT: FridaRuntimeTuple,
<S as HasSolutions>::Solutions: Corpus<Input = S::Input>, //delete me <S as HasSolutions>::Solutions: Corpus<Input = S::Input>, //delete me

View File

@ -13,10 +13,7 @@ use frida_gum::{
Backend, Gum, ModuleDetails, ModuleMap, Script, Backend, Gum, ModuleDetails, ModuleMap, Script,
}; };
use frida_gum_sys::gchar; use frida_gum_sys::gchar;
use libafl::{ use libafl::Error;
inputs::{HasTargetBytes, Input},
Error,
};
use libafl_bolts::{ use libafl_bolts::{
cli::{FridaScriptBackend, FuzzerOptions}, cli::{FridaScriptBackend, FuzzerOptions},
tuples::MatchFirstType, tuples::MatchFirstType,
@ -49,10 +46,10 @@ pub trait FridaRuntime: 'static + Debug {
fn deinit(&mut self, gum: &Gum); fn deinit(&mut self, gum: &Gum);
/// Method called before execution /// Method called before execution
fn pre_exec<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error>; fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error>;
/// Method called after execution /// Method called after execution
fn post_exec<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error>; fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error>;
} }
/// The tuple for Frida Runtime /// The tuple for Frida Runtime
@ -69,10 +66,10 @@ pub trait FridaRuntimeTuple: MatchFirstType + Debug {
fn deinit_all(&mut self, gum: &Gum); fn deinit_all(&mut self, gum: &Gum);
/// Method called before execution /// Method called before execution
fn pre_exec_all<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error>; fn pre_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error>;
/// Method called after execution /// Method called after execution
fn post_exec_all<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error>; fn post_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error>;
} }
impl FridaRuntimeTuple for () { impl FridaRuntimeTuple for () {
@ -85,10 +82,10 @@ impl FridaRuntimeTuple for () {
} }
fn deinit_all(&mut self, _gum: &Gum) {} fn deinit_all(&mut self, _gum: &Gum) {}
fn pre_exec_all<I: Input + HasTargetBytes>(&mut self, _input: &I) -> Result<(), Error> { fn pre_exec_all(&mut self, _input_bytes: &[u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn post_exec_all<I: Input + HasTargetBytes>(&mut self, _input: &I) -> Result<(), Error> { fn post_exec_all(&mut self, _input_bytes: &[u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
@ -113,14 +110,14 @@ where
self.1.deinit_all(gum); self.1.deinit_all(gum);
} }
fn pre_exec_all<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error> { fn pre_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error> {
self.0.pre_exec(input)?; self.0.pre_exec(input_bytes)?;
self.1.pre_exec_all(input) self.1.pre_exec_all(input_bytes)
} }
fn post_exec_all<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error> { fn post_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error> {
self.0.post_exec(input)?; self.0.post_exec(input_bytes)?;
self.1.post_exec_all(input) self.1.post_exec_all(input_bytes)
} }
} }
@ -709,13 +706,13 @@ where
} }
/// Method called before execution /// Method called before execution
pub fn pre_exec<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error> { pub fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> {
(*self.runtimes).borrow_mut().pre_exec_all(input) (*self.runtimes).borrow_mut().pre_exec_all(input_bytes)
} }
/// Method called after execution /// Method called after execution
pub fn post_exec<I: Input + HasTargetBytes>(&mut self, input: &I) -> Result<(), Error> { pub fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> {
(*self.runtimes).borrow_mut().post_exec_all(input) (*self.runtimes).borrow_mut().post_exec_all(input_bytes)
} }
/// If stalker is enabled /// If stalker is enabled