use core::fmt::{self, Debug, Formatter};
use std::{ffi::c_void, marker::PhantomData};
use frida_gum::{
stalker::{NoneEventSink, Stalker},
Gum, MemoryRange, NativePointer,
};
#[cfg(windows)]
use libafl::{
executors::inprocess::{HasInProcessHandlers, InProcessHandlers},
state::{HasClientPerfMonitor, HasSolutions},
};
use libafl::{
executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
inputs::{HasTargetBytes, UsesInput},
observers::{ObserversTuple, UsesObservers},
state::UsesState,
Error,
};
#[cfg(unix)]
use crate::asan::errors::ASAN_ERRORS;
use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple};
#[cfg(windows)]
use crate::windows_hooks::initialize;
pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S::Input: HasTargetBytes,
S: UsesInput,
OT: ObserversTuple<S>,
'a: 'b,
{
base: InProcessExecutor<'a, H, OT, S>,
stalker: Stalker<'a>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>,
followed: bool,
_phantom: PhantomData<&'b u8>,
}
impl<'a, 'b, 'c, H, OT, RT, S> Debug for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S: UsesInput,
S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("FridaInProcessExecutor")
.field("base", &self.base)
.field("helper", &self.helper)
.field("followed", &self.followed)
.finish_non_exhaustive()
}
}
impl<'a, 'b, 'c, EM, H, OT, RT, S, Z> Executor<EM, Z>
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
EM: UsesState<State = S>,
H: FnMut(&S::Input) -> ExitKind,
S: UsesInput,
S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
RT: FridaRuntimeTuple,
Z: UsesState<State = S>,
{
#[inline]
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
self.helper.pre_exec(input)?;
if self.helper.stalker_enabled() {
if self.followed {
self.stalker.activate(NativePointer(core::ptr::null_mut()));
} else {
self.followed = true;
let transformer = self.helper.transformer();
self.stalker.follow_me::<NoneEventSink>(transformer, None);
}
}
let res = self.base.run_target(fuzzer, state, mgr, input);
if self.helper.stalker_enabled() {
self.stalker.deactivate();
}
#[cfg(unix)]
unsafe {
if ASAN_ERRORS.is_some() && !ASAN_ERRORS.as_ref().unwrap().is_empty() {
println!("Crashing target as it had ASAN errors");
libc::raise(libc::SIGABRT);
}
}
self.helper.post_exec(input)?;
res
}
}
impl<'a, 'b, 'c, H, OT, RT, S> UsesObservers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
S: UsesInput,
S::Input: HasTargetBytes,
{
type Observers = OT;
}
impl<'a, 'b, 'c, H, OT, RT, S> UsesState for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
S: UsesInput,
S::Input: HasTargetBytes,
{
type State = S;
}
impl<'a, 'b, 'c, H, OT, RT, S> HasObservers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S::Input: HasTargetBytes,
S: UsesInput,
OT: ObserversTuple<S>,
{
#[inline]
fn observers(&self) -> &OT {
self.base.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
self.base.observers_mut()
}
}
impl<'a, 'b, 'c, H, OT, S, RT> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S: UsesInput,
S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
RT: FridaRuntimeTuple,
{
pub fn new(
gum: &'a Gum,
base: InProcessExecutor<'a, H, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>,
) -> Self {
let mut stalker = Stalker::new(gum);
let mut ranges = helper.ranges().clone();
for module in frida_gum::Module::enumerate_modules() {
if module.base_address < Self::new as usize
&& (Self::new as usize) < module.base_address + module.size
{
ranges.insert(
module.base_address..(module.base_address + module.size),
(0xffff, "fuzzer".to_string()),
);
break;
}
}
if !helper.options().disable_excludes {
for range in ranges.gaps(&(0..usize::MAX)) {
println!("excluding range: {:x}-{:x}", range.start, range.end);
stalker.exclude(&MemoryRange::new(
NativePointer(range.start as *mut c_void),
range.end - range.start,
));
}
}
#[cfg(windows)]
initialize(&gum);
Self {
base,
stalker,
helper,
followed: false,
_phantom: PhantomData,
}
}
}
#[cfg(windows)]
impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S: UsesInput + HasClientPerfMonitor + HasSolutions,
S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
RT: FridaRuntimeTuple,
{
#[inline]
fn inprocess_handlers(&self) -> &InProcessHandlers {
&self.base.handlers()
}
}