From 1809c31a46a235321482aaea639cfc657983e444 Mon Sep 17 00:00:00 2001 From: jejuisland87654 Date: Tue, 3 Dec 2024 23:44:19 +0100 Subject: [PATCH] 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 --- libafl_frida/src/asan/asan_rt.rs | 21 ++------- libafl_frida/src/cmplog_rt.rs | 9 ++-- libafl_frida/src/coverage_rt.rs | 10 +--- libafl_frida/src/drcov_rt.rs | 12 ++--- libafl_frida/src/executor.rs | 78 ++++++++++++++++++++++---------- libafl_frida/src/helper.rs | 37 +++++++-------- 6 files changed, 84 insertions(+), 83 deletions(-) diff --git a/libafl_frida/src/asan/asan_rt.rs b/libafl_frida/src/asan/asan_rt.rs index 94ac0e0bf6..5256475a25 100644 --- a/libafl_frida/src/asan/asan_rt.rs +++ b/libafl_frida/src/asan/asan_rt.rs @@ -27,7 +27,7 @@ use frida_gum::{ }; use frida_gum_sys::Insn; use hashbrown::HashMap; -use libafl_bolts::{cli::FuzzerOptions, AsSlice}; +use libafl_bolts::cli::FuzzerOptions; use libc::wchar_t; use rangemap::RangeMap; #[cfg(target_arch = "aarch64")] @@ -190,33 +190,22 @@ impl FridaRuntime for AsanRuntime { self.deregister_hooks(gum); } - fn pre_exec( - &mut self, - 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()); + fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), libafl::Error> { + self.unpoison(input_bytes.as_ptr() as usize, input_bytes.len()); self.enable_hooks(); Ok(()) } - fn post_exec( - &mut self, - input: &I, - ) -> Result<(), libafl::Error> { + fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), libafl::Error> { self.disable_hooks(); if self.check_for_leaks_enabled { self.check_for_leaks(); } - let target_bytes = input.target_bytes(); - let slice = target_bytes.as_slice(); // # Safety // The ptr and length are correct. unsafe { - self.poison(slice.as_ptr() as usize, slice.len()); + self.poison(input_bytes.as_ptr() as usize, input_bytes.len()); } self.reset_allocations(); diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index b80a7a4f56..7e9e8fa724 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -29,10 +29,7 @@ use iced_x86::{ BlockEncoder, Code, DecoderOptions, Instruction, InstructionBlock, MemoryOperand, MemorySize, OpKind, Register, }; -use libafl::{ - inputs::{HasTargetBytes, Input}, - Error, -}; +use libafl::Error; use libafl_targets::{cmps::__libafl_targets_cmplog_instructions, CMPLOG_MAP_W}; use rangemap::RangeMap; @@ -132,11 +129,11 @@ impl FridaRuntime for CmpLogRuntime { fn deinit(&mut self, _gum: &frida_gum::Gum) {} - fn pre_exec(&mut self, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _input_bytes: &[u8]) -> Result<(), Error> { Ok(()) } - fn post_exec(&mut self, _input: &I) -> Result<(), Error> { + fn post_exec(&mut self, _input_bytes: &[u8]) -> Result<(), Error> { Ok(()) } } diff --git a/libafl_frida/src/coverage_rt.rs b/libafl_frida/src/coverage_rt.rs index 4f1e17a031..3a6226b6de 100644 --- a/libafl_frida/src/coverage_rt.rs +++ b/libafl_frida/src/coverage_rt.rs @@ -44,17 +44,11 @@ impl FridaRuntime for CoverageRuntime { fn deinit(&mut self, _gum: &frida_gum::Gum) {} - fn pre_exec( - &mut self, - _input: &I, - ) -> Result<(), libafl::Error> { + fn pre_exec(&mut self, _input_bytes: &[u8]) -> Result<(), libafl::Error> { Ok(()) } - fn post_exec( - &mut self, - _input: &I, - ) -> Result<(), libafl::Error> { + fn post_exec(&mut self, _input_bytes: &[u8]) -> Result<(), libafl::Error> { Ok(()) } } diff --git a/libafl_frida/src/drcov_rt.rs b/libafl_frida/src/drcov_rt.rs index 5da459b314..ba89652723 100644 --- a/libafl_frida/src/drcov_rt.rs +++ b/libafl_frida/src/drcov_rt.rs @@ -7,11 +7,7 @@ use std::{ use ahash::RandomState; use frida_gum::ModuleMap; -use libafl::{ - inputs::{HasTargetBytes, Input}, - Error, -}; -use libafl_bolts::AsSlice; +use libafl::Error; use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter}; use rangemap::RangeMap; @@ -43,20 +39,20 @@ impl FridaRuntime for DrCovRuntime { fn deinit(&mut self, _gum: &frida_gum::Gum) {} /// Called before execution, does nothing - fn pre_exec(&mut self, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _input_bytes: &[u8]) -> Result<(), Error> { Ok(()) } /// Called after execution, writes the trace to a unique `DrCov` file for this trace /// into `./coverage/_.drcov`. Empty coverages will be skipped. - fn post_exec(&mut self, input: &I) -> Result<(), Error> { + fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> { // We don't need empty coverage files if self.drcov_basic_blocks.is_empty() { return Ok(()); } 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 mut coverage_hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); diff --git a/libafl_frida/src/executor.rs b/libafl_frida/src/executor.rs index 0a113e83a0..a7feffc839 100644 --- a/libafl_frida/src/executor.rs +++ b/libafl_frida/src/executor.rs @@ -15,12 +15,12 @@ use libafl::{ }; use libafl::{ executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, - inputs::HasTargetBytes, + inputs::{HasTargetBytes, NopTargetBytesConverter, TargetBytesConverter}, observers::ObserversTuple, state::{HasExecutions, State, UsesState}, Error, }; -use libafl_bolts::tuples::RefIndexable; +use libafl_bolts::{tuples::RefIndexable, AsSlice}; #[cfg(not(test))] use crate::asan::errors::AsanErrors; @@ -29,30 +29,31 @@ use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple}; 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. -pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> +pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC> where H: FnMut(&S::Input) -> ExitKind, - S::Input: HasTargetBytes, + TC: TargetBytesConverter, S: State, OT: ObserversTuple, 'b: 'a, { base: InProcessExecutor<'a, H, OT, S>, - // thread_id for the Stalker + /// `thread_id` for the Stalker thread_id: Option, /// Frida's dynamic rewriting engine stalker: Stalker, /// User provided callback for instrumentation helper: &'c mut FridaInstrumentationHelper<'b, RT>, + target_bytes_converter: TC, followed: bool, _phantom: PhantomData<&'b u8>, } -impl Debug for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> +impl Debug for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC> where H: FnMut(&S::Input) -> ExitKind, S: State, - S::Input: HasTargetBytes, + TC: TargetBytesConverter, OT: ObserversTuple + Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -64,12 +65,13 @@ where } } -impl Executor for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> +impl Executor + for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC> where EM: UsesState, H: FnMut(&S::Input) -> ExitKind, S: State + HasExecutions, - S::Input: HasTargetBytes, + TC: TargetBytesConverter, OT: ObserversTuple, RT: FridaRuntimeTuple, Z: UsesState, @@ -83,7 +85,8 @@ where mgr: &mut EM, input: &Self::Input, ) -> Result { - 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.followed { self.stalker.activate(NativePointer(core::ptr::null_mut())); @@ -115,25 +118,25 @@ where abort(); } } - self.helper.post_exec(input)?; + self.helper.post_exec(target_bytes.as_slice())?; res } } -impl UsesState for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> +impl UsesState for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC> where H: FnMut(&S::Input) -> ExitKind, OT: ObserversTuple, S: State, - S::Input: HasTargetBytes, + TC: TargetBytesConverter, { type State = S; } -impl HasObservers for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S> +impl HasObservers for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC> where H: FnMut(&S::Input) -> ExitKind, - S::Input: HasTargetBytes, + TC: TargetBytesConverter, S: State, OT: ObserversTuple, { @@ -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> where H: FnMut(&S::Input) -> ExitKind, S: State, @@ -163,7 +167,13 @@ where base: InProcessExecutor<'a, H, OT, S>, helper: &'c mut FridaInstrumentationHelper<'b, RT>, ) -> 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`. @@ -173,23 +183,40 @@ where helper: &'c mut FridaInstrumentationHelper<'b, RT>, thread_id: u32, ) -> 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. - fn _on_thread( +impl<'a, 'b, 'c, H, OT, RT, S, TC> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC> +where + H: FnMut(&S::Input) -> ExitKind, + S: State, + TC: TargetBytesConverter, + OT: ObserversTuple, + RT: FridaRuntimeTuple, +{ + /// Creates a new [`FridaInProcessExecutor`]. + pub fn with_target_bytes_converter( gum: &'a Gum, base: InProcessExecutor<'a, H, OT, S>, helper: &'c mut FridaInstrumentationHelper<'b, RT>, thread_id: Option, + target_bytes_converter: TC, ) -> Self { let mut stalker = Stalker::new(gum); // Include the current module (the fuzzer) in stalked ranges. We clone the ranges so that // we don't add it to the INSTRUMENTED ranges. let mut ranges = helper.ranges().clone(); for module in frida_gum::Module::obtain(gum).enumerate_modules() { - if module.base_address < Self::new as usize - && (Self::new as usize as u64) < module.base_address as u64 + module.size as u64 + if module.base_address < Self::with_target_bytes_converter as usize + && (Self::with_target_bytes_converter as usize as u64) + < module.base_address as u64 + module.size as u64 { ranges.insert( module.base_address as u64..(module.base_address as u64 + module.size as u64), @@ -220,6 +247,7 @@ where thread_id, stalker, helper, + target_bytes_converter, followed: false, _phantom: PhantomData, } @@ -227,12 +255,12 @@ where } #[cfg(windows)] -impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHooks - for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> +impl<'a, 'b, 'c, H, OT, RT, S, TC> HasInProcessHooks + for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC> where H: FnMut(&S::Input) -> ExitKind, S: State + HasSolutions + HasCorpus + HasExecutions, - S::Input: HasTargetBytes, + TC: TargetBytesConverter, OT: ObserversTuple, RT: FridaRuntimeTuple, ::Solutions: Corpus, //delete me diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index f0e6ae64d1..5c03edb6c0 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -13,10 +13,7 @@ use frida_gum::{ Backend, Gum, ModuleDetails, ModuleMap, Script, }; use frida_gum_sys::gchar; -use libafl::{ - inputs::{HasTargetBytes, Input}, - Error, -}; +use libafl::Error; use libafl_bolts::{ cli::{FridaScriptBackend, FuzzerOptions}, tuples::MatchFirstType, @@ -49,10 +46,10 @@ pub trait FridaRuntime: 'static + Debug { fn deinit(&mut self, gum: &Gum); /// Method called before execution - fn pre_exec(&mut self, input: &I) -> Result<(), Error>; + fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error>; /// Method called after execution - fn post_exec(&mut self, input: &I) -> Result<(), Error>; + fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error>; } /// The tuple for Frida Runtime @@ -69,10 +66,10 @@ pub trait FridaRuntimeTuple: MatchFirstType + Debug { fn deinit_all(&mut self, gum: &Gum); /// Method called before execution - fn pre_exec_all(&mut self, input: &I) -> Result<(), Error>; + fn pre_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error>; /// Method called after execution - fn post_exec_all(&mut self, input: &I) -> Result<(), Error>; + fn post_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error>; } impl FridaRuntimeTuple for () { @@ -85,10 +82,10 @@ impl FridaRuntimeTuple for () { } fn deinit_all(&mut self, _gum: &Gum) {} - fn pre_exec_all(&mut self, _input: &I) -> Result<(), Error> { + fn pre_exec_all(&mut self, _input_bytes: &[u8]) -> Result<(), Error> { Ok(()) } - fn post_exec_all(&mut self, _input: &I) -> Result<(), Error> { + fn post_exec_all(&mut self, _input_bytes: &[u8]) -> Result<(), Error> { Ok(()) } } @@ -113,14 +110,14 @@ where self.1.deinit_all(gum); } - fn pre_exec_all(&mut self, input: &I) -> Result<(), Error> { - self.0.pre_exec(input)?; - self.1.pre_exec_all(input) + fn pre_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + self.0.pre_exec(input_bytes)?; + self.1.pre_exec_all(input_bytes) } - fn post_exec_all(&mut self, input: &I) -> Result<(), Error> { - self.0.post_exec(input)?; - self.1.post_exec_all(input) + fn post_exec_all(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + self.0.post_exec(input_bytes)?; + self.1.post_exec_all(input_bytes) } } @@ -709,13 +706,13 @@ where } /// Method called before execution - pub fn pre_exec(&mut self, input: &I) -> Result<(), Error> { - (*self.runtimes).borrow_mut().pre_exec_all(input) + pub fn pre_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + (*self.runtimes).borrow_mut().pre_exec_all(input_bytes) } /// Method called after execution - pub fn post_exec(&mut self, input: &I) -> Result<(), Error> { - (*self.runtimes).borrow_mut().post_exec_all(input) + pub fn post_exec(&mut self, input_bytes: &[u8]) -> Result<(), Error> { + (*self.runtimes).borrow_mut().post_exec_all(input_bytes) } /// If stalker is enabled