From 7c84a7903a6c600c8b4b6ccbc2614ad6755fe26b Mon Sep 17 00:00:00 2001 From: s1341 Date: Tue, 28 Jan 2025 11:48:52 +0200 Subject: [PATCH] Frida updates and FASAN fixes (#2838) * Frida updates and FASAN fixes * fmt * Fixes * clippy * fmt * Clippy * Update to frida 0.16.2 * fix windows hooks * Fix * Fmt * windows fix * Bump frida version to 0.16.3 * Get rid of call to LLVMFuzzerInitialize * bump version 0.16.5; use find_global_export_by_name * allow unused_macro_rules * Don't do stdout_file on windows * fmt * Add tmate to debug * fix windows frida_libpng --------- Co-authored-by: Dongjia "toka" Zhang --- .../frida_executable_libpng/Cargo.toml | 2 +- fuzzers/binary_only/frida_libpng/Cargo.toml | 11 +- .../binary_only/frida_libpng/src/fuzzer.rs | 329 +++++---- .../frida_windows_gdiplus/Cargo.toml | 2 +- libafl_frida/Cargo.toml | 6 +- libafl_frida/build.rs | 1 + libafl_frida/src/alloc.rs | 46 +- libafl_frida/src/asan/asan_rt.rs | 286 +++++--- libafl_frida/src/asan/errors.rs | 34 +- libafl_frida/src/asan/hook_funcs.rs | 665 +++++++++++++----- libafl_frida/src/executor.rs | 10 +- libafl_frida/src/helper.rs | 19 +- libafl_frida/src/windows_hooks.rs | 12 +- 13 files changed, 924 insertions(+), 499 deletions(-) diff --git a/fuzzers/binary_only/frida_executable_libpng/Cargo.toml b/fuzzers/binary_only/frida_executable_libpng/Cargo.toml index 85929c067c..2c3ce6ad79 100644 --- a/fuzzers/binary_only/frida_executable_libpng/Cargo.toml +++ b/fuzzers/binary_only/frida_executable_libpng/Cargo.toml @@ -25,7 +25,7 @@ libafl = { path = "../../../libafl", features = [ "frida_cli", ] } #, "llmp_small_maps", "llmp_debug"]} libafl_bolts = { path = "../../../libafl_bolts" } -frida-gum = { version = "0.15.1", features = [ +frida-gum = { version = "0.16.5", features = [ "auto-download", "event-sink", "invocation-listener", diff --git a/fuzzers/binary_only/frida_libpng/Cargo.toml b/fuzzers/binary_only/frida_libpng/Cargo.toml index 21e8dbd808..6c068cf447 100644 --- a/fuzzers/binary_only/frida_libpng/Cargo.toml +++ b/fuzzers/binary_only/frida_libpng/Cargo.toml @@ -16,6 +16,7 @@ lto = true codegen-units = 1 opt-level = 3 debug = true +panic = 'abort' [dependencies] libafl = { path = "../../../libafl", features = [ @@ -26,7 +27,7 @@ libafl = { path = "../../../libafl", features = [ "errors_backtrace", ] } #, "llmp_small_maps", "llmp_debug"]} libafl_bolts = { path = "../../../libafl_bolts" } -frida-gum = { version = "0.15.1", features = [ +frida-gum = { version = "0.16.5", features = [ "auto-download", "event-sink", "invocation-listener", @@ -37,7 +38,9 @@ libafl_targets = { path = "../../../libafl_targets", features = [ "sancov_cmplog", ] } libloading = "0.8.5" -log = { version = "0.4.22", features = ["release_max_level_info"] } -mimalloc = { version = "0.1.43", default-features = false } -color-backtrace = "0.6.1" +log = { version = "0.4.22", features = ["release_max_level_trace"] } +mimalloc = { version = "0.1.43", default-features = true, features = [ + "local_dynamic_tls", +] } +color-backtrace = { version = "0.6.1", features = ["resolve-modules"] } env_logger = "0.11.5" diff --git a/fuzzers/binary_only/frida_libpng/src/fuzzer.rs b/fuzzers/binary_only/frida_libpng/src/fuzzer.rs index 6d7ee9441e..261296ffc8 100644 --- a/fuzzers/binary_only/frida_libpng/src/fuzzer.rs +++ b/fuzzers/binary_only/frida_libpng/src/fuzzer.rs @@ -25,8 +25,6 @@ use libafl::{ state::{HasCorpus, StdState}, Error, HasMetadata, }; -#[cfg(unix)] -use libafl::{feedback_and_fast, feedbacks::ConstFeedback}; use libafl_bolts::{ cli::{parse_args, FuzzerOptions}, rands::StdRand, @@ -56,19 +54,16 @@ pub fn main() { color_backtrace::install(); let options = parse_args(); - unsafe { - match fuzz(&options) { - Ok(()) | Err(Error::ShuttingDown) => println!("\nFinished fuzzing. Good bye."), - Err(e) => panic!("Error during fuzzing: {e:?}"), - } + log::info!("Frida fuzzer starting up."); + match fuzz(&options) { + Ok(()) | Err(Error::ShuttingDown) => println!("\nFinished fuzzing. Good bye."), + Err(e) => panic!("Error during fuzzing: {e:?}"), } } /// The actual fuzzer #[expect(clippy::too_many_lines)] -unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { - log::info!("Frida fuzzer starting up."); - +fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // 'While the stats are state, they are usually used in the broker - which is likely never restarted let monitor = MultiMonitor::new(|s| println!("{s}")); @@ -81,193 +76,185 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { }; let mut run_client = |state: Option<_>, - mgr: LlmpRestartingEventManager<_, _, _, _, _>, + mut mgr: LlmpRestartingEventManager<_, _, _, _, _>, client_description: ClientDescription| { // The restarting state will spawn the same process again as child, then restarted it each time it crashes. // println!("{:?}", mgr.mgr_id()); - let lib = libloading::Library::new(options.clone().harness.unwrap()).unwrap(); + let lib = unsafe { libloading::Library::new(options.clone().harness.unwrap()).unwrap() }; let target_func: libloading::Symbol< unsafe extern "C" fn(data: *const u8, size: usize) -> i32, - > = lib.get(options.harness_function.as_bytes()).unwrap(); + > = unsafe { lib.get(options.harness_function.as_bytes()).unwrap() }; let mut frida_harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target.as_slice(); - (target_func)(buf.as_ptr(), buf.len()); + unsafe { (target_func)(buf.as_ptr(), buf.len()) }; ExitKind::Ok }; - // if options.asan && options.asan_cores.contains(client_description.core_id()) { - (|state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _, _, _>, - _client_description| { - let gum = Gum::obtain(); + let gum = Gum::obtain(); - let coverage = CoverageRuntime::new(); - let asan = AsanRuntime::new(options); - let cmplog = CmpLogRuntime::new(); + let coverage = CoverageRuntime::new(); + let asan = AsanRuntime::new(options); + let cmplog = CmpLogRuntime::new(); - let client_description_clone = client_description.clone(); - let options_clone = options.clone(); - let client_description_clone2 = client_description.clone(); - let options_clone2 = options.clone(); - let mut frida_helper = FridaInstrumentationHelper::new( - &gum, - options, - tuple_list!( - IfElseRuntime::new( - move || Ok(is_asan(&options_clone, &client_description_clone)), - tuple_list!(asan), - tuple_list!() - ), - IfElseRuntime::new( - move || Ok(is_cmplog(&options_clone2, &client_description_clone2)), - tuple_list!(cmplog), - tuple_list!() - ), - coverage - ), - ); - - // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr( - "edges", - frida_helper.map_mut_ptr().unwrap(), - MAP_SIZE, - )) - .track_indices(); - - // Create an observation channel to keep track of the execution time - let time_observer = TimeObserver::new("time"); - let asan_observer = AsanErrorsObserver::from_static_asan_errors(); - - // Feedback to rate the interestingness of an input - // This one is composed by two Feedbacks in OR - let mut feedback = feedback_or!( - // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new(&edges_observer), - // Time feedback, this one does not need a feedback state - TimeFeedback::new(&time_observer) - ); - - // Feedbacks to recognize an input as solution - #[cfg(unix)] - let mut objective = feedback_or_fast!( - CrashFeedback::new(), - TimeoutFeedback::new(), - // true enables the AsanErrorFeedback - feedback_and_fast!( - ConstFeedback::from(true), - AsanErrorsFeedback::new(&asan_observer) - ) - ); - #[cfg(windows)] - let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); - - // If not restarting, create a State from scratch - let mut state = state.unwrap_or_else(|| { - StdState::new( - // RNG - StdRand::new(), - // Corpus that will be evolved, we keep it in memory for performance - CachedOnDiskCorpus::no_meta(PathBuf::from("./corpus_discovered"), 64).unwrap(), - // Corpus in which we store solutions (crashes in this example), - // on disk so the user can get them after stopping the fuzzer - OnDiskCorpus::new(options.output.clone()).unwrap(), - &mut feedback, - &mut objective, - ) - .unwrap() - }); - - println!("We're a client, let's fuzz :)"); - - // Create a PNG dictionary if not existing - if state.metadata_map().get::().is_none() { - state.add_metadata(Tokens::from([ - vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header - b"IHDR".to_vec(), - b"IDAT".to_vec(), - b"PLTE".to_vec(), - b"IEND".to_vec(), - ])); - } - - // Setup a basic mutator with a mutational stage - let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - - // A minimization+queue policy to get testcasess from the corpus - let scheduler = - IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); - - // A fuzzer with feedbacks and a corpus scheduler - let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - - #[cfg(unix)] - let observers = tuple_list!(edges_observer, time_observer, asan_observer); - #[cfg(windows)] - let observers = tuple_list!(edges_observer, time_observer); - - // Create the executor for an in-process function with just one observer for edge coverage - let mut executor = FridaInProcessExecutor::new( - &gum, - InProcessExecutor::new( - &mut frida_harness, - observers, - &mut fuzzer, - &mut state, - &mut mgr, - )?, - &mut frida_helper, - ); - // Create an observation channel using cmplog map - let cmplog_observer = CmpLogObserver::new("cmplog", true); - - let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer)); - - let tracing = ShadowTracingStage::new(&mut executor); - - // Setup a randomic Input2State stage - let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!( - I2SRandReplace::new() - ))); - - // In case the corpus is empty (on first run), reset - if state.must_load_initial_inputs() { - state - .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &options.input) - .unwrap_or_else(|_| { - panic!("Failed to load initial corpus at {:?}", &options.input) - }); - println!("We imported {} inputs from disk.", state.corpus().count()); - } - - let mut stages = tuple_list!( - IfElseStage::new( - |_, _, _, _| Ok(is_cmplog(&options, &client_description)), - tuple_list!(tracing, i2s), + let client_description_clone = client_description.clone(); + let options_clone = options.clone(); + let client_description_clone2 = client_description.clone(); + let options_clone2 = options.clone(); + let mut frida_helper = FridaInstrumentationHelper::new( + &gum, + options, + tuple_list!( + IfElseRuntime::new( + move || Ok(is_asan(&options_clone, &client_description_clone)), + tuple_list!(asan), tuple_list!() ), - StdMutationalStage::new(mutator) - ); + IfElseRuntime::new( + move || Ok(is_cmplog(&options_clone2, &client_description_clone2)), + tuple_list!(cmplog), + tuple_list!() + ), + coverage + ), + ); - fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; + // Create an observation channel using the coverage map + let edges_observer = HitcountsMapObserver::new(unsafe { + StdMapObserver::from_mut_ptr("edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE) + }) + .track_indices(); - Ok(()) - })(state, mgr, client_description.clone()) + // Create an observation channel to keep track of the execution time + let time_observer = TimeObserver::new("time"); + let asan_observer = AsanErrorsObserver::from_static_asan_errors(); + + // Feedback to rate the interestingness of an input + // This one is composed by two Feedbacks in OR + let mut feedback = feedback_or!( + // New maximization map feedback linked to the edges observer and the feedback state + MaxMapFeedback::new(&edges_observer), + // Time feedback, this one does not need a feedback state + TimeFeedback::new(&time_observer) + ); + + // Feedbacks to recognize an input as solution + let mut objective = feedback_or_fast!( + CrashFeedback::new(), + AsanErrorsFeedback::new(&asan_observer), + TimeoutFeedback::new(), + ); + + // If not restarting, create a State from scratch + let mut state = state.unwrap_or_else(|| { + StdState::new( + // RNG + StdRand::new(), + // Corpus that will be evolved, we keep it in memory for performance + CachedOnDiskCorpus::no_meta(PathBuf::from("./corpus_discovered"), 64).unwrap(), + // Corpus in which we store solutions (crashes in this example), + // on disk so the user can get them after stopping the fuzzer + OnDiskCorpus::new(options.output.clone()).unwrap(), + &mut feedback, + &mut objective, + ) + .unwrap() + }); + + println!("We're a client, let's fuzz :)"); + + // Create a PNG dictionary if not existing + if state.metadata_map().get::().is_none() { + state.add_metadata(Tokens::from([ + vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header + b"IHDR".to_vec(), + b"IDAT".to_vec(), + b"PLTE".to_vec(), + b"IEND".to_vec(), + ])); + } + + // Setup a basic mutator with a mutational stage + let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); + + // A minimization+queue policy to get testcasess from the corpus + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); + + // A fuzzer with feedbacks and a corpus scheduler + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); + + let observers = tuple_list!(edges_observer, time_observer, asan_observer); + + // Create the executor for an in-process function with just one observer for edge coverage + let executor = FridaInProcessExecutor::new( + &gum, + InProcessExecutor::with_timeout( + &mut frida_harness, + observers, + &mut fuzzer, + &mut state, + &mut mgr, + options.timeout, + )?, + &mut frida_helper, + ); + // Create an observation channel using cmplog map + let cmplog_observer = CmpLogObserver::new("cmplog", true); + + let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer)); + + let tracing = ShadowTracingStage::new(&mut executor); + + // Setup a randomic Input2State stage + let i2s = + StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); + + // In case the corpus is empty (on first run), reset + if state.must_load_initial_inputs() { + state + .load_initial_inputs_multicore( + &mut fuzzer, + &mut executor, + &mut mgr, + &options.input, + &client_description.core_id(), + &options.cores, + ) + .unwrap_or_else(|_| { + panic!("Failed to load initial corpus at {:?}", &options.input) + }); + println!("We imported {} inputs from disk.", state.corpus().count()); + } + + let mut stages = tuple_list!( + IfElseStage::new( + |_, _, _, _| Ok(is_cmplog(&options, &client_description)), + tuple_list!(tracing, i2s), + tuple_list!() + ), + StdMutationalStage::new(mutator) + ); + + fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; + + Ok(()) }; - Launcher::builder() + let builder = Launcher::builder() .configuration(EventConfig::AlwaysUnique) .shmem_provider(shmem_provider) .monitor(monitor) .run_client(&mut run_client) .cores(&options.cores) .broker_port(options.broker_port) - // .stdout_file(Some(&options.stdout)) - .remote_broker_addr(options.remote_broker_addr) - .build() - .launch() + .remote_broker_addr(options.remote_broker_addr); + + #[cfg(not(windows))] + let builder = builder.stdout_file(Some(&options.stdout)); + + builder.build().launch() } diff --git a/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml b/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml index 0923ddac8c..3fbabc9c58 100644 --- a/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml +++ b/fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml @@ -23,7 +23,7 @@ libafl = { path = "../../../libafl", features = [ "errors_backtrace", ] } #, "llmp_small_maps", "llmp_debug"]} libafl_bolts = { path = "../../../libafl_bolts" } -frida-gum = { version = "0.15.1", features = [ +frida-gum = { version = "0.16.5", features = [ "auto-download", "event-sink", "invocation-listener", diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index d980bd284b..f8c4e80c34 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -62,15 +62,16 @@ nix = { workspace = true, default-features = true, features = ["mman"] } libc = { workspace = true } hashbrown = { workspace = true, default-features = true } rangemap = { workspace = true } -frida-gum-sys = { version = "0.15.1", features = [ +frida-gum-sys = { version = "0.16.5", features = [ "event-sink", "invocation-listener", ] } -frida-gum = { version = "0.15.1", features = [ +frida-gum = { version = "0.16.5", features = [ "event-sink", "invocation-listener", "module-names", "script", + "backtrace", ] } dynasmrt = "3.0.1" @@ -98,7 +99,6 @@ serial_test = { workspace = true, default-features = false, features = [ clap = { workspace = true, features = ["derive"] } libloading = "0.8.5" mimalloc = { workspace = true, default-features = false } -dlmalloc = { version = "0.2.6", features = ["global"] } [lints] workspace = true diff --git a/libafl_frida/build.rs b/libafl_frida/build.rs index 7d0656cc4c..ca0a08657f 100644 --- a/libafl_frida/build.rs +++ b/libafl_frida/build.rs @@ -14,6 +14,7 @@ fn main() { let target_family = std::env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); // Force linking against libc++ + #[cfg(not(target_vendor = "apple"))] if target_family == "unix" { println!("cargo:rustc-link-lib=dylib=c++"); } diff --git a/libafl_frida/src/alloc.rs b/libafl_frida/src/alloc.rs index 97114765dd..ece38bea1f 100644 --- a/libafl_frida/src/alloc.rs +++ b/libafl_frida/src/alloc.rs @@ -11,7 +11,6 @@ use std::{collections::BTreeMap, ffi::c_void}; use backtrace::Backtrace; use frida_gum::{PageProtection, RangeDetails}; -use hashbrown::HashMap; use libafl_bolts::cli::FuzzerOptions; #[cfg(target_vendor = "apple")] use mach_sys::{ @@ -59,9 +58,9 @@ pub struct Allocator { /// Whether we've pre allocated a shadow mapping: using_pre_allocated_shadow_mapping: bool, /// All tracked allocations - allocations: HashMap, + allocations: BTreeMap, /// All mappings - mappings: HashMap, + mappings: BTreeMap, /// The shadow memory pages shadow_pages: RangeSet, /// A list of allocations @@ -171,7 +170,6 @@ impl Allocator { #[must_use] #[expect(clippy::missing_safety_doc)] pub unsafe fn alloc(&mut self, size: usize, _alignment: usize) -> *mut c_void { - log::trace!("alloc"); let mut is_malloc_zero = false; let size = if size == 0 { is_malloc_zero = true; @@ -249,7 +247,7 @@ impl Allocator { let address = (metadata.address + self.page_size) as *mut c_void; self.allocations.insert(address as usize, metadata); - log::trace!( + log::info!( "serving address: {:#x}, size: {:#x}", address as usize, size @@ -260,21 +258,25 @@ impl Allocator { /// Releases the allocation at the given address. #[expect(clippy::missing_safety_doc)] pub unsafe fn release(&mut self, ptr: *mut c_void) { - log::trace!("release {:?}", ptr); + log::info!("release {:?}", ptr); let Some(metadata) = self.allocations.get_mut(&(ptr as usize)) else { - if !ptr.is_null() { - AsanErrors::get_mut_blocking() - .report_error(AsanError::UnallocatedFree((ptr as usize, Backtrace::new()))); + if !ptr.is_null() + && AsanErrors::get_mut_blocking() + .report_error(AsanError::UnallocatedFree((ptr as usize, Backtrace::new()))) + { + panic!("ASAN: Crashing target!"); } return; }; - if metadata.freed { - AsanErrors::get_mut_blocking().report_error(AsanError::DoubleFree(( + if metadata.freed + && AsanErrors::get_mut_blocking().report_error(AsanError::DoubleFree(( ptr as usize, metadata.clone(), Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } let shadow_mapping_start = map_to_shadow!(self, ptr as usize); @@ -316,7 +318,7 @@ impl Allocator { /// Resets the allocator contents pub fn reset(&mut self) { let mut tmp_allocations = Vec::new(); - for (address, mut allocation) in self.allocations.drain() { + while let Some((address, mut allocation)) = self.allocations.pop_first() { if !allocation.freed { tmp_allocations.push(allocation); continue; @@ -579,9 +581,17 @@ impl Allocator { /// Checks if any of the allocations has not been freed pub fn check_for_leaks(&self) { for metadata in self.allocations.values() { - if !metadata.freed { - AsanErrors::get_mut_blocking() - .report_error(AsanError::Leak((metadata.address, metadata.clone()))); + if !metadata.freed + && AsanErrors::get_mut_blocking() + .report_error(AsanError::Leak((metadata.address, metadata.clone()))) + { + unsafe { + println!( + "{:x?}", + std::slice::from_raw_parts(metadata.address as *const u8, metadata.size) + ); + }; + panic!("ASAN: Crashing target!"); } } } @@ -818,10 +828,10 @@ impl Default for Allocator { page_size, pre_allocated_shadow_mappings: Vec::new(), using_pre_allocated_shadow_mapping: false, - mappings: HashMap::new(), + mappings: BTreeMap::new(), shadow_offset: 0, shadow_bit: 0, - allocations: HashMap::new(), + allocations: BTreeMap::new(), shadow_pages: RangeSet::new(), allocation_queue: BTreeMap::new(), largest_allocation: 0, diff --git a/libafl_frida/src/asan/asan_rt.rs b/libafl_frida/src/asan/asan_rt.rs index 727b248249..f9bd3f6826 100644 --- a/libafl_frida/src/asan/asan_rt.rs +++ b/libafl_frida/src/asan/asan_rt.rs @@ -23,7 +23,7 @@ use frida_gum::instruction_writer::X86Register; use frida_gum::instruction_writer::{Aarch64Register, IndexMode}; use frida_gum::{ instruction_writer::InstructionWriter, interceptor::Interceptor, stalker::StalkerOutput, Gum, - Module, ModuleDetails, ModuleMap, NativePointer, PageProtection, RangeDetails, + Module, ModuleMap, NativePointer, PageProtection, Process, RangeDetails, }; use frida_gum_sys::Insn; use hashbrown::HashMap; @@ -96,6 +96,25 @@ thread_local! { static ASAN_IN_HOOK: Cell = const { Cell::new(false) }; } +#[inline] +#[cfg(target_arch = "aarch64")] +unsafe fn thread_local_initted() -> bool { + let mut tid: u64; + std::arch::asm!( + "mrs {tid}, TPIDRRO_EL0", + tid = out(reg) tid, + ); + tid &= 0xffff_ffff_ffff_fff8; + let tlsptr = tid as *const u64; + tlsptr.add(0x102).read() != 0u64 +} + +#[inline] +#[cfg(not(target_arch = "aarch64"))] +unsafe fn thread_local_initted() -> bool { + true +} + /// The count of registers that need to be saved by the asan runtime #[cfg(target_arch = "aarch64")] pub const ASAN_SAVE_REGISTER_COUNT: usize = 32; @@ -174,8 +193,8 @@ impl FridaRuntime for AsanRuntime { .extend(self.skip_ranges.iter().map(|skip| match skip { SkipRange::Absolute(range) => range.start, SkipRange::ModuleRelative { name, range } => { - let module_details = ModuleDetails::with_name(name.clone()).unwrap(); - let lib_start = module_details.range().base_address().0 as usize; + let module = Module::load(gum, name); + let lib_start = module.range().base_address().0 as usize; lib_start + range.start } })); @@ -456,37 +475,42 @@ impl AsanRuntime { #[expect(clippy::too_many_lines)] pub fn register_hooks(&mut self, gum: &Gum) { let mut interceptor = Interceptor::obtain(gum); - let module = Module::obtain(gum); + let process = Process::obtain(gum); macro_rules! hook_func { - //No library case ($name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty) => { paste::paste! { - log::trace!("Hooking {}", stringify!($name)); - let target_function = module.find_export_by_name(None, stringify!($name)).expect("Failed to find function"); + let target_function = Module::find_global_export_by_name(stringify!($name)).expect("Failed to find function"); + log::warn!("Hooking {} = {:?}", stringify!($name), target_function.0); static [<$name:snake:upper _PTR>]: std::sync::OnceLock $return_type> = std::sync::OnceLock::new(); let _ = [<$name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap(); - #[allow(non_snake_case)] // depends on the values the macro is invoked with + #[allow(non_snake_case)] unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); //is this necessary? The stalked return address will always be the real return address // let real_address = this.real_address_for_stalked(invocation.return_addr()); - let original = [<$name:snake:upper _PTR>].get().unwrap(); - - if !ASAN_IN_HOOK.get() && this.hooks_enabled { - ASAN_IN_HOOK.set(true); - let ret = this.[](*original, $($param),*); - ASAN_IN_HOOK.set(false); - ret - } else { - let ret = (original)($($param),*); - ret + let original = [<$name:snake:upper _PTR>].get().unwrap(); + if this.hooks_enabled { + if thread_local_initted() { + if !ASAN_IN_HOOK.get() { + ASAN_IN_HOOK.set(true); + let ret = this.[](*original, $($param),*); + ASAN_IN_HOOK.set(false); + ret + } else { + (original)($($param),*) + } + } else { + (original)($($param),*) + } + } else { + (original)($($param),*) + } } - } let self_ptr = core::ptr::from_ref(self) as usize; let _ = interceptor.replace( @@ -501,9 +525,10 @@ impl AsanRuntime { //Library specific macro rule. lib and lib_ident are both needed because we need to generate a unique static variable and only name is insufficient. In addition, the lib name could contain invalid characters (i.e., lib.so is an invalid name) ($lib:literal, $lib_ident:ident, $name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty) => { paste::paste! { - log::trace!("Hooking {}:{}", $lib, stringify!($name)); - let target_function = module.find_export_by_name(Some($lib), stringify!($name)).expect("Failed to find function"); + log::warn!("Hooking {}:{}", $lib, stringify!($name)); + let target_function = process.find_module_by_name($lib).expect("Failed to find module").find_export_by_name(stringify!($name)).expect("Failed to find function"); + log::warn!("Hooking {}:{} = {:?}", $lib, stringify!($name), target_function.0); static [<$lib_ident:snake:upper _ $name:snake:upper _PTR>]: std::sync::OnceLock $return_type> = std::sync::OnceLock::new(); @@ -516,14 +541,21 @@ impl AsanRuntime { //is this necessary? The stalked return address will always be the real return address // let real_address = this.real_address_for_stalked(invocation.return_addr()); let original = [<$lib_ident:snake:upper _ $name:snake:upper _PTR>].get().unwrap(); - if !ASAN_IN_HOOK.get() && this.hooks_enabled { - ASAN_IN_HOOK.set(true); - let ret = this.[](*original, $($param),*); - ASAN_IN_HOOK.set(false); - ret + if this.hooks_enabled { + if thread_local_initted() { + if !ASAN_IN_HOOK.get() { + ASAN_IN_HOOK.set(true); + let ret = this.[](*original, $($param),*); + ASAN_IN_HOOK.set(false); + ret + } else { + (original)($($param),*) + } + } else { + (original)($($param),*) + } } else { - let ret = (original)($($param),*); - ret + (original)($($param),*) } } @@ -539,35 +571,48 @@ impl AsanRuntime { }; } - #[expect(unused_macro_rules)] + #[allow(unused_macro_rules)] macro_rules! hook_func_with_check { - //No library case - ($name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty) => { + ($name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty, $always_enabled:expr) => { paste::paste! { - log::trace!("Hooking {}", stringify!($name)); - let target_function = module.find_export_by_name(None, stringify!($name)).expect("Failed to find function"); + let target_function = Module::find_global_export_by_name(stringify!($name)).expect("Failed to find function"); + log::warn!("Hooking {} = {:?}", stringify!($name), target_function.0); static [<$name:snake:upper _PTR>]: std::sync::OnceLock $return_type> = std::sync::OnceLock::new(); - - let _ = [<$name:snake:upper _PTR>].set(unsafe {std::mem::transmute::<*const c_void, extern "C" fn($($param: $param_type),*) -> $return_type>(target_function.0)}).unwrap_or_else(|e| println!("{:?}", e)); - #[allow(non_snake_case)] // depends on the values the macro is invoked with + #[allow(non_snake_case)] unsafe extern "C" fn []($($param: $param_type),*) -> $return_type { let mut invocation = Interceptor::current_invocation(); let this = &mut *(invocation.replacement_data().unwrap().0 as *mut AsanRuntime); let original = [<$name:snake:upper _PTR>].get().unwrap(); //don't check if hooks are enabled as there are certain cases where we want to run the hook even if we are out of the program //For example, sometimes libafl will allocate certain things during the run and free them after the run. This results in a bug where a buffer will come from libafl-frida alloc and be freed in the normal allocator. - if !ASAN_IN_HOOK.get() && this.[]($($param),*){ - ASAN_IN_HOOK.set(true); - let ret = this.[](*original, $($param),*); - ASAN_IN_HOOK.set(false); - ret + if $always_enabled || this.hooks_enabled { + if thread_local_initted() { + if !ASAN_IN_HOOK.get() { + ASAN_IN_HOOK.set(true); + let ret = if this.[]($($param),*) { + this.[](*original, $($param),*) + } else { + (original)($($param),*) + }; + ASAN_IN_HOOK.set(false); + ret + } else { + (original)($($param),*) + } + } else { + let ret = if $always_enabled && this.[]($($param),*) { + this.[](*original, $($param),*) + } else { + (original)($($param),*) + }; + ret + } } else { - let ret = (original)($($param),*); - ret + (original)($($param),*) } } @@ -582,11 +627,11 @@ impl AsanRuntime { } }; //Library specific macro rule. lib and lib_ident are both needed because we need to generate a unique static variable and only name is insufficient. In addition, the lib name could contain invalid characters (i.e., lib.so is an invalid name) - ($lib:literal, $lib_ident:ident, $name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty) => { + ($lib:literal, $lib_ident:ident, $name:ident, ($($param:ident : $param_type:ty),*), $return_type:ty, $always_enabled:expr) => { paste::paste! { - log::trace!("Hooking {}:{}", $lib, stringify!($name)); - let target_function = module.find_export_by_name(Some($lib), stringify!($name)).expect("Failed to find function"); + let target_function = process.find_module_by_name($lib).expect("Failed to find module").find_export_by_name(stringify!($name)).expect("Failed to find function"); + log::warn!("Hooking {}:{} = {:?}", $lib, stringify!($name), target_function.0); static [<$lib_ident:snake:upper _ $name:snake:upper _PTR>]: std::sync::OnceLock $return_type> = std::sync::OnceLock::new(); @@ -600,14 +645,30 @@ impl AsanRuntime { let original = [<$lib_ident:snake:upper _ $name:snake:upper _PTR>].get().unwrap(); //don't check if hooks are enabled as there are certain cases where we want to run the hook even if we are out of the program //For example, sometimes libafl will allocate certain things during the run and free them after the run. This results in a bug where a buffer will come from libafl-frida alloc and be freed in the normal allocator. - if !ASAN_IN_HOOK.get() && this.[]($($param),*){ - ASAN_IN_HOOK.set(true); - let ret = this.[](*original, $($param),*); - ASAN_IN_HOOK.set(false); - ret + if $always_enabled || this.hooks_enabled { + if thread_local_initted() { + if !ASAN_IN_HOOK.get() { + ASAN_IN_HOOK.set(true); + let ret = if this.[]($($param),*) { + this.[](*original, $($param),*) + } else { + (original)($($param),*) + }; + ASAN_IN_HOOK.set(false); + ret + } else { + (original)($($param),*) + } + } else { + let ret = if $always_enabled && this.[]($($param),*) { + this.[](*original, $($param),*) + } else { + (original)($($param),*) + }; + ret + } } else { - let ret = (original)($($param),*); - ret + (original)($($param),*) } } @@ -629,9 +690,9 @@ impl AsanRuntime { #[cfg(not(windows))] hook_func!(calloc, (nmemb: usize, size: usize), *mut c_void); #[cfg(not(windows))] - hook_func!(realloc, (ptr: *mut c_void, size: usize), *mut c_void); + hook_func_with_check!(realloc, (ptr: *mut c_void, size: usize), *mut c_void, false); #[cfg(not(windows))] - hook_func_with_check!(free, (ptr: *mut c_void), usize); + hook_func_with_check!(free, (ptr: *mut c_void), usize, true); #[cfg(not(any(target_vendor = "apple", windows)))] hook_func!(memalign, (size: usize, alignment: usize), *mut c_void); #[cfg(not(windows))] @@ -642,6 +703,28 @@ impl AsanRuntime { ); #[cfg(not(any(target_vendor = "apple", windows)))] hook_func!(malloc_usable_size, (ptr: *mut c_void), usize); + #[cfg(target_vendor = "apple")] + hook_func!(valloc, (size: usize), *mut c_void); + #[cfg(target_vendor = "apple")] + hook_func_with_check!(reallocf, (ptr: *mut c_void, size: usize), *mut c_void, false); + #[cfg(target_vendor = "apple")] + hook_func_with_check!(malloc_size, (ptr: *mut c_void), usize, false); + #[cfg(target_vendor = "apple")] + hook_func_with_check!(malloc_good_size, (ptr: *mut c_void), usize, false); + #[cfg(target_vendor = "apple")] + hook_func!("libSystem.B.dylib", libSystemB, os_log_type_enabled, (oslog: *mut c_void, r#type: u8), bool); + #[cfg(target_vendor = "apple")] + hook_func!("libSystem.B.dylib", libSystemB, _os_log_impl, (dso: *const c_void, log: *mut c_void, r#type: u8, format: *const c_char, buf: *const u8, size: u32), ()); + #[cfg(target_vendor = "apple")] + hook_func!("libSystem.B.dylib", libSystemB, _os_log_fault_impl, (dso: *const c_void, log: *mut c_void, r#type: u8, format: *const c_char, buf: *const u8, size: u32), ()); + #[cfg(target_vendor = "apple")] + hook_func!("libSystem.B.dylib", libSystemB, _os_log_error_impl, (dso: *const c_void, log: *mut c_void, r#type: u8, format: *const c_char, buf: *const u8, size: u32), ()); + #[cfg(target_vendor = "apple")] + hook_func!("libSystem.B.dylib", libSystemB, _os_log_debug_impl, (dso: *const c_void, log: *mut c_void, r#type: u8, format: *const c_char, buf: *const u8, size: u32), ()); + #[cfg(target_vendor = "apple")] + hook_func!("libc++.1.dylib", libcpp, __cxa_allocate_exception, (size: usize), *const c_void); + #[cfg(target_vendor = "apple")] + hook_func!("libc++.1.dylib", libcpp, __cxa_free_exception, (ptr: *mut c_void), usize); // // #[cfg(windows)] // hook_priv_func!( // "c:\\windows\\system32\\ntdll.dll", @@ -674,7 +757,8 @@ impl AsanRuntime { macro_rules! hook_heap_windows { ($libname:literal, $lib_ident:ident) => { log::info!("Hooking allocator functions in {}", $libname); - for export in module.enumerate_exports($libname) { + if let Some(module) = process.find_module_by_name($libname) { + for export in module.enumerate_exports() { // log::trace!("- {}", export.name); match &export.name[..] { "NtGdiCreateCompatibleDC" => { @@ -693,16 +777,16 @@ impl AsanRuntime { hook_func!($libname, $lib_ident, RtlAllocateHeap, (handle: *mut c_void, flags: u32, bytes: usize), *mut c_void); } "HeapFree" => { - hook_func_with_check!($libname, $lib_ident, HeapFree, (handle: *mut c_void, flags: u32, mem: *mut c_void), bool); + hook_func_with_check!($libname, $lib_ident, HeapFree, (handle: *mut c_void, flags: u32, mem: *mut c_void), bool, true); } "RtlFreeHeap" => { - hook_func_with_check!($libname, $lib_ident, RtlFreeHeap, (handle: *mut c_void, flags: u32, mem: *mut c_void), usize); + hook_func_with_check!($libname, $lib_ident, RtlFreeHeap, (handle: *mut c_void, flags: u32, mem: *mut c_void), usize, true); } "HeapSize" => { - hook_func_with_check!($libname, $lib_ident, HeapSize, (handle: *mut c_void, flags: u32, mem: *mut c_void), usize); + hook_func_with_check!($libname, $lib_ident, HeapSize, (handle: *mut c_void, flags: u32, mem: *mut c_void), usize, false); } "RtlSizeHeap" => { - hook_func_with_check!($libname, $lib_ident, RtlSizeHeap , (handle: *mut c_void, flags: u32, mem: *mut c_void), usize); + hook_func_with_check!($libname, $lib_ident, RtlSizeHeap , (handle: *mut c_void, flags: u32, mem: *mut c_void), usize, false); } "RtlReAllocateHeap" => { hook_func!( @@ -737,22 +821,22 @@ impl AsanRuntime { hook_func!($libname, $lib_ident, LocalReAlloc, (mem: *mut c_void, size: usize, flags: u32), *mut c_void); } "LocalHandle" => { - hook_func_with_check!($libname, $lib_ident, LocalHandle, (mem: *mut c_void), *mut c_void); + hook_func_with_check!($libname, $lib_ident, LocalHandle, (mem: *mut c_void), *mut c_void, false); } "LocalLock" => { - hook_func_with_check!($libname, $lib_ident, LocalLock, (mem: *mut c_void), *mut c_void); + hook_func_with_check!($libname, $lib_ident, LocalLock, (mem: *mut c_void), *mut c_void, false); } "LocalUnlock" => { - hook_func_with_check!($libname, $lib_ident, LocalUnlock, (mem: *mut c_void), bool); + hook_func_with_check!($libname, $lib_ident, LocalUnlock, (mem: *mut c_void), bool, false); } "LocalSize" => { - hook_func_with_check!($libname, $lib_ident, LocalSize, (mem: *mut c_void),usize); + hook_func_with_check!($libname, $lib_ident, LocalSize, (mem: *mut c_void),usize, false); } "LocalFree" => { - hook_func_with_check!($libname, $lib_ident, LocalFree, (mem: *mut c_void), *mut c_void); + hook_func_with_check!($libname, $lib_ident, LocalFree, (mem: *mut c_void), *mut c_void, true); } "LocalFlags" => { - hook_func_with_check!($libname, $lib_ident, LocalFlags, (mem: *mut c_void),u32); + hook_func_with_check!($libname, $lib_ident, LocalFlags, (mem: *mut c_void),u32, false); } "GlobalAlloc" => { hook_func!($libname, $lib_ident, GlobalAlloc, (flags: u32, size: usize), *mut c_void); @@ -761,22 +845,22 @@ impl AsanRuntime { hook_func!($libname, $lib_ident, GlobalReAlloc, (mem: *mut c_void, flags: u32, size: usize), *mut c_void); } "GlobalHandle" => { - hook_func_with_check!($libname, $lib_ident, GlobalHandle, (mem: *mut c_void), *mut c_void); + hook_func_with_check!($libname, $lib_ident, GlobalHandle, (mem: *mut c_void), *mut c_void, false); } "GlobalLock" => { - hook_func_with_check!($libname, $lib_ident, GlobalLock, (mem: *mut c_void), *mut c_void); + hook_func_with_check!($libname, $lib_ident, GlobalLock, (mem: *mut c_void), *mut c_void, false); } "GlobalUnlock" => { - hook_func_with_check!($libname, $lib_ident, GlobalUnlock, (mem: *mut c_void), bool); + hook_func_with_check!($libname, $lib_ident, GlobalUnlock, (mem: *mut c_void), bool, false); } "GlobalSize" => { - hook_func_with_check!($libname, $lib_ident, GlobalSize, (mem: *mut c_void),usize); + hook_func_with_check!($libname, $lib_ident, GlobalSize, (mem: *mut c_void),usize, false); } "GlobalFree" => { - hook_func_with_check!($libname, $lib_ident, GlobalFree, (mem: *mut c_void), *mut c_void); + hook_func_with_check!($libname, $lib_ident, GlobalFree, (mem: *mut c_void), *mut c_void, true); } "GlobalFlags" => { - hook_func_with_check!($libname, $lib_ident, GlobalFlags, (mem: *mut c_void),u32); + hook_func_with_check!($libname, $lib_ident, GlobalFlags, (mem: *mut c_void),u32, false); } "memmove" => { hook_func!( @@ -813,10 +897,10 @@ impl AsanRuntime { hook_func!($libname, $lib_ident, _o_realloc, (ptr: *mut c_void, size: usize), *mut c_void); } "free" => { - hook_func_with_check!($libname, $lib_ident, free, (ptr: *mut c_void), usize); + hook_func_with_check!($libname, $lib_ident, free, (ptr: *mut c_void), usize, true); } "_o_free" | "o_free" => { - hook_func_with_check!($libname, $lib_ident, _o_free, (ptr: *mut c_void), usize); + hook_func_with_check!($libname, $lib_ident, _o_free, (ptr: *mut c_void), usize, true); } "_write" => { hook_func!( @@ -860,7 +944,7 @@ impl AsanRuntime { } _ => (), } - } + }} } } #[cfg(windows)] @@ -900,7 +984,8 @@ impl AsanRuntime { macro_rules! hook_cpp { ($libname:literal, $lib_ident:ident) => { log::info!("Hooking c++ functions in {}", $libname); - for export in module.enumerate_exports($libname) { + if let Some(module) = process.find_module_by_name($libname) { + for export in module.enumerate_exports() { match &export.name[..] { "_Znam" => { hook_func!($libname, $lib_ident, _Znam, (size: usize), *mut c_void); @@ -1034,7 +1119,7 @@ impl AsanRuntime { } _ => {} } - } + }} } } #[cfg(target_os = "linux")] @@ -1057,6 +1142,7 @@ impl AsanRuntime { #[cfg(not(windows))] hook_func!( + mmap, ( addr: *const c_void, @@ -1074,6 +1160,7 @@ impl AsanRuntime { // Hook libc functions which may access allocated memory #[cfg(not(windows))] hook_func!( + write, (fd: i32, buf: *const c_void, count: usize), usize @@ -1081,22 +1168,26 @@ impl AsanRuntime { #[cfg(not(windows))] hook_func!(read, (fd: i32, buf: *mut c_void, count: usize), usize); hook_func!( + fgets, (s: *mut c_void, size: u32, stream: *mut c_void), *mut c_void ); hook_func!( + memcmp, (s1: *const c_void, s2: *const c_void, n: usize), i32 ); hook_func!( + memcpy, (dest: *mut c_void, src: *const c_void, n: usize), *mut c_void ); #[cfg(not(any(target_vendor = "apple", windows)))] hook_func!( + mempcpy, (dest: *mut c_void, src: *const c_void, n: usize), *mut c_void @@ -1109,23 +1200,27 @@ impl AsanRuntime { // *mut c_void // ); hook_func!( + memset, (s: *mut c_void, c: i32, n: usize), *mut c_void ); hook_func!( + memchr, (s: *mut c_void, c: i32, n: usize), *mut c_void ); #[cfg(not(any(target_vendor = "apple", windows)))] hook_func!( + memrchr, (s: *mut c_void, c: i32, n: usize), *mut c_void ); #[cfg(not(windows))] hook_func!( + memmem, ( haystack: *const c_void, @@ -1150,39 +1245,46 @@ impl AsanRuntime { hook_func!(strrchr, (s: *mut c_char, c: i32), *mut c_char); #[cfg(not(windows))] hook_func!( + strcasecmp, (s1: *const c_char, s2: *const c_char), i32 ); #[cfg(not(windows))] hook_func!( + strncasecmp, (s1: *const c_char, s2: *const c_char, n: usize), i32 ); hook_func!( + strcat, (dest: *mut c_char, src: *const c_char), *mut c_char ); hook_func!(strcmp, (s1: *const c_char, s2: *const c_char), i32); hook_func!( + strncmp, (s1: *const c_char, s2: *const c_char, n: usize), i32 ); hook_func!( + strcpy, (dest: *mut c_char, src: *const c_char), *mut c_char ); hook_func!( + strncpy, (dest: *mut c_char, src: *const c_char, n: usize), *mut c_char ); #[cfg(not(windows))] hook_func!( + stpcpy, (dest: *mut c_char, src: *const c_char), *mut c_char @@ -1194,12 +1296,14 @@ impl AsanRuntime { hook_func!(strlen, (s: *const c_char), usize); hook_func!(strnlen, (s: *const c_char, n: usize), usize); hook_func!( + strstr, (haystack: *const c_char, needle: *const c_char), *mut c_char ); #[cfg(not(windows))] hook_func!( + strcasestr, (haystack: *const c_char, needle: *const c_char), *mut c_char @@ -1209,6 +1313,7 @@ impl AsanRuntime { hook_func!(atoll, (nptr: *const c_char), i64); hook_func!(wcslen, (s: *const wchar_t), usize); hook_func!( + wcscpy, (dest: *mut wchar_t, src: *const wchar_t), *mut wchar_t @@ -1216,18 +1321,21 @@ impl AsanRuntime { hook_func!(wcscmp, (s1: *const wchar_t, s2: *const wchar_t), i32); #[cfg(target_vendor = "apple")] hook_func!( + memset_pattern4, (s: *mut c_void, c: *const c_void, n: usize), () ); #[cfg(target_vendor = "apple")] hook_func!( + memset_pattern8, (s: *mut c_void, c: *const c_void, n: usize), () ); #[cfg(target_vendor = "apple")] hook_func!( + memset_pattern16, (s: *mut c_void, c: *const c_void, n: usize), () @@ -1397,16 +1505,19 @@ impl AsanRuntime { backtrace, )) }; - AsanErrors::get_mut_blocking().report_error(error); + #[allow(clippy::manual_assert)] + if AsanErrors::get_mut_blocking().report_error(error) { + panic!("ASAN: Crashing target!"); + } // This is not even a mem instruction?? - } else { - AsanErrors::get_mut_blocking().report_error(AsanError::Unknown(( - self.regs, - actual_pc, - (None, None, 0, fault_address), - backtrace, - ))); + } else if AsanErrors::get_mut_blocking().report_error(AsanError::Unknown(( + self.regs, + actual_pc, + (None, None, 0, fault_address), + backtrace, + ))) { + panic!("ASAN: Crashing target!"); } // log::info!("ASAN Error, attach the debugger!"); @@ -1536,7 +1647,10 @@ impl AsanRuntime { backtrace, )) }; - AsanErrors::get_mut_blocking().report_error(error); + #[allow(clippy::manual_assert)] + if AsanErrors::get_mut_blocking().report_error(error) { + panic!("ASAN: Crashing target!"); + } self.enable_hooks(); } diff --git a/libafl_frida/src/asan/errors.rs b/libafl_frida/src/asan/errors.rs index 1887a649c7..3b655e8c51 100644 --- a/libafl_frida/src/asan/errors.rs +++ b/libafl_frida/src/asan/errors.rs @@ -11,7 +11,7 @@ use backtrace::Backtrace; use color_backtrace::{default_output_stream, BacktracePrinter, Verbosity}; #[cfg(target_arch = "aarch64")] use frida_gum::interceptor::Interceptor; -use frida_gum::ModuleDetails; +use frida_gum::{Gum, Process}; use libafl::{ corpus::Testcase, executors::ExitKind, @@ -24,6 +24,7 @@ use libafl_bolts::{ tuples::{Handle, Handled, MatchNameRef}, Named, SerdeAny, }; +use mmap_rs::MmapOptions; use serde::{Deserialize, Serialize}; use termcolor::{Color, ColorSpec, WriteColor}; #[cfg(target_arch = "aarch64")] @@ -151,9 +152,9 @@ impl AsanErrors { self.continue_on_error = continue_on_error; } - /// Report an error + /// Report an error, returns true if the caller should panic #[expect(clippy::too_many_lines)] - pub(crate) fn report_error(&mut self, error: AsanError) { + pub(crate) fn report_error(&mut self, error: AsanError) -> bool { let mut out_stream = default_output_stream(); let output = out_stream.as_mut(); @@ -180,7 +181,9 @@ impl AsanErrors { | AsanError::WriteAfterFree(error) => { let (basereg, indexreg, _displacement, fault_address) = error.fault; - if let Some(module_details) = ModuleDetails::with_address(error.pc as u64) { + if let Some(module_details) = + Process::obtain(&Gum::obtain()).find_module_by_address(error.pc) + { writeln!( output, " at 0x{:x} ({}@0x{:04x}), faulting address 0x{:x}", @@ -294,7 +297,9 @@ impl AsanErrors { writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap(); 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); + #[allow(clippy::cast_possible_wrap)] + let offset: i64 = + fault_address - (metadata_address + MmapOptions::page_size() as i64); let direction = if offset > 0 { "right" } else { "left" }; writeln!( output, @@ -302,7 +307,7 @@ impl AsanErrors { offset, direction, error.metadata.size, - error.metadata.address + 0x1000 + error.metadata.address + MmapOptions::page_size() ) .unwrap(); @@ -343,7 +348,9 @@ impl AsanErrors { { let invocation = Interceptor::current_invocation(); let cpu_context = invocation.cpu_context(); - if let Some(module_details) = ModuleDetails::with_address(*_pc as u64) { + if let Some(module_details) = + Process::obtain(&Gum::obtain()).find_module_by_address(*_pc) + { writeln!( output, " at 0x{:x} ({}@0x{:04x})", @@ -388,7 +395,7 @@ impl AsanErrors { writeln!( output, "allocation at 0x{:x}, with size 0x{:x}", - metadata.address + 0x1000, + metadata.address + MmapOptions::page_size(), metadata.size ) .unwrap(); @@ -426,7 +433,7 @@ impl AsanErrors { writeln!( output, "allocation at 0x{:x}, with size 0x{:x}", - metadata.address + 0x1000, + metadata.address + MmapOptions::page_size(), metadata.size ) .unwrap(); @@ -447,7 +454,9 @@ impl AsanErrors { | AsanError::StackOobWrite((registers, pc, fault, backtrace)) => { let (basereg, indexreg, _displacement, fault_address) = fault; - if let Some(module_details) = ModuleDetails::with_address(*pc as u64) { + if let Some(module_details) = + Process::obtain(&Gum::obtain()).find_module_by_address(*pc) + { writeln!( output, " at 0x{:x} ({}:0x{:04x}), faulting address 0x{:x}", @@ -556,10 +565,7 @@ impl AsanErrors { self.errors.push(error); - #[expect(clippy::manual_assert)] - if !self.continue_on_error { - panic!("ASAN: Crashing target!"); - } + !self.continue_on_error } } diff --git a/libafl_frida/src/asan/hook_funcs.rs b/libafl_frida/src/asan/hook_funcs.rs index d7e391c5b5..f5ba2d1945 100644 --- a/libafl_frida/src/asan/hook_funcs.rs +++ b/libafl_frida/src/asan/hook_funcs.rs @@ -695,6 +695,16 @@ impl AsanRuntime { 0 } + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_valloc( + &mut self, + _original: extern "C" fn(size: usize) -> *mut c_void, + size: usize, + ) -> *mut c_void { + unsafe { self.allocator_mut().alloc(size, 8) } + } + #[inline] pub fn hook_malloc( &mut self, @@ -855,6 +865,11 @@ impl AsanRuntime { fn memset(s: *mut c_void, c: i32, n: usize) -> *mut c_void; } let ret = unsafe { self.allocator_mut().alloc(size * nmemb, 8) }; + // if size * nmemb == 0x10 { + // log::error!("backtrace: {:0x?}", frida_gum::Backtracer::accurate()); + // let x:usize = 0x12345; + // unsafe { (x as *const usize).read(); } + // } unsafe { memset(ret, 0, size * nmemb); } @@ -879,6 +894,11 @@ impl AsanRuntime { ret } + #[inline] + pub fn hook_check_realloc(&mut self, ptr: *mut c_void, _size: usize) -> bool { + self.allocator_mut().is_managed(ptr) + } + #[inline] #[expect(clippy::cmp_null)] pub fn hook_realloc( @@ -888,6 +908,44 @@ impl AsanRuntime { size: usize, ) -> *mut c_void { unsafe { + if size == 0 { + self.allocator_mut().release(ptr); + #[cfg(not(target_vendor = "apple"))] + return std::ptr::null_mut(); + #[cfg(target_vendor = "apple")] + return self.allocator_mut().alloc(0, 0x8); + } + let ret = self.allocator_mut().alloc(size, 0x8); + if ptr != std::ptr::null_mut() && ret != std::ptr::null_mut() { + let old_size = self.allocator_mut().get_usable_size(ptr); + let copy_size = if size < old_size { size } else { old_size }; + (ptr as *mut u8).copy_to(ret as *mut u8, copy_size); + self.allocator_mut().release(ptr); + } + ret + } + } + + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_check_reallocf(&mut self, ptr: *mut c_void, _size: usize) -> bool { + self.allocator_mut().is_managed(ptr) + } + + #[inline] + #[expect(clippy::cmp_null)] + #[cfg(target_vendor = "apple")] + pub fn hook_reallocf( + &mut self, + _original: extern "C" fn(ptr: *mut c_void, size: usize) -> *mut c_void, + ptr: *mut c_void, + size: usize, + ) -> *mut c_void { + unsafe { + if size == 0 { + self.allocator_mut().release(ptr); + return self.allocator_mut().alloc(0, 0x8); + } let ret = self.allocator_mut().alloc(size, 0x8); if ptr != std::ptr::null_mut() && ret != std::ptr::null_mut() { let old_size = self.allocator_mut().get_usable_size(ptr); @@ -991,7 +1049,158 @@ impl AsanRuntime { ) -> usize { self.allocator_mut().get_usable_size(ptr) } + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_check_malloc_size(&mut self, ptr: *mut c_void) -> bool { + self.allocator_mut().is_managed(ptr) + } + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_malloc_size( + &mut self, + _original: extern "C" fn(ptr: *mut c_void) -> usize, + ptr: *mut c_void, + ) -> usize { + self.allocator_mut().get_usable_size(ptr) + } + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_check_malloc_good_size(&mut self, ptr: *mut c_void) -> bool { + self.allocator_mut().is_managed(ptr) + } + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_malloc_good_size( + &mut self, + _original: extern "C" fn(ptr: *mut c_void) -> usize, + ptr: *mut c_void, + ) -> usize { + self.allocator_mut().get_usable_size(ptr) + } + #[inline] + #[cfg(target_vendor = "apple")] + pub fn hook_os_log_type_enabled( + &mut self, + _original: extern "C" fn(oslog: *mut c_void, r#type: u8) -> bool, + _oslog: *mut c_void, + r#_type: u8, + ) -> bool { + false + } + #[inline] + #[cfg(target_vendor = "apple")] + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn hook__os_log_impl( + &mut self, + _original: extern "C" fn( + dso: *const c_void, + log: *mut c_void, + r#type: u8, + format: *const c_char, + buf: *const u8, + size: u32, + ), + _dso: *const c_void, + _log: *mut c_void, + r#_type: u8, + _format: *const c_char, + _buf: *const u8, + _size: u32, + ) { + } + #[inline] + #[cfg(target_vendor = "apple")] + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn hook__os_log_fault_impl( + &mut self, + _original: extern "C" fn( + dso: *const c_void, + log: *mut c_void, + r#type: u8, + format: *const c_char, + buf: *const u8, + size: u32, + ), + _dso: *const c_void, + _log: *mut c_void, + r#_type: u8, + _format: *const c_char, + _buf: *const u8, + _size: u32, + ) { + } + #[inline] + #[cfg(target_vendor = "apple")] + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn hook__os_log_error_impl( + &mut self, + _original: extern "C" fn( + dso: *const c_void, + log: *mut c_void, + r#type: u8, + format: *const c_char, + buf: *const u8, + size: u32, + ), + _dso: *const c_void, + _log: *mut c_void, + r#_type: u8, + _format: *const c_char, + _buf: *const u8, + _size: u32, + ) { + } + #[inline] + #[cfg(target_vendor = "apple")] + #[allow(clippy::too_many_arguments)] + #[allow(non_snake_case)] + pub fn hook__os_log_debug_impl( + &mut self, + _original: extern "C" fn( + dso: *const c_void, + log: *mut c_void, + r#type: u8, + format: *const c_char, + buf: *const u8, + size: u32, + ), + _dso: *const c_void, + _log: *mut c_void, + r#_type: u8, + _format: *const c_char, + _buf: *const u8, + _size: u32, + ) { + } + #[inline] + #[expect(non_snake_case)] + pub fn hook___cxa_allocate_exception( + &mut self, + _original: extern "C" fn(size: usize) -> *const c_void, + size: usize, + ) -> *const c_void { + unsafe { + self.allocator_mut() + .alloc((size + 0x8f) & 0xfffffffffffffff0, 8) + .add(0x80) + } + } + #[inline] + #[expect(non_snake_case)] + pub fn hook___cxa_free_exception( + &mut self, + _original: extern "C" fn(ptr: *mut c_void) -> usize, + ptr: *mut c_void, + ) -> usize { + unsafe { + self.allocator_mut().release(ptr.sub(0x80)); + } + 0 + } #[inline] #[expect(non_snake_case)] #[cfg(windows)] @@ -1273,14 +1482,16 @@ impl AsanRuntime { buf: *const c_void, count: usize, ) -> usize { - if !self.allocator_mut().check_shadow(buf, count) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(buf, count) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "write".to_string(), self.real_address_for_stalked(self.pc()), buf as usize, count, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(fd, buf, count) } @@ -1304,14 +1515,16 @@ impl AsanRuntime { buf: *mut c_void, count: usize, ) -> usize { - if !self.allocator_mut().check_shadow(buf, count) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(buf, count) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "read".to_string(), self.real_address_for_stalked(self.pc()), buf as usize, count, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(fd, buf, count) } @@ -1324,14 +1537,16 @@ impl AsanRuntime { size: u32, stream: *mut c_void, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(s, size as usize) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s, size as usize) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "fgets".to_string(), self.real_address_for_stalked(self.pc()), s as usize, size as usize, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, size, stream) } @@ -1344,23 +1559,27 @@ impl AsanRuntime { s2: *const c_void, n: usize, ) -> i32 { - if !self.allocator_mut().check_shadow(s1, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s1, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memcmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(s2, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s2, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memcmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2, n) } @@ -1373,23 +1592,27 @@ impl AsanRuntime { src: *const c_void, n: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(dest, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(dest, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memcpy".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(src, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(src, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memcpy".to_string(), self.real_address_for_stalked(self.pc()), src as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src, n) } @@ -1403,23 +1626,27 @@ impl AsanRuntime { src: *const c_void, n: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(dest, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(dest, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "mempcpy".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(src, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(src, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "mempcpy".to_string(), self.real_address_for_stalked(self.pc()), src as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src, n) } @@ -1432,23 +1659,27 @@ impl AsanRuntime { src: *const c_void, n: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(dest, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(dest, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memmove".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(src, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(src, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memmove".to_string(), self.real_address_for_stalked(self.pc()), src as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src, n) @@ -1462,14 +1693,16 @@ impl AsanRuntime { c: i32, n: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(dest, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(dest, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, c, n) } @@ -1482,14 +1715,16 @@ impl AsanRuntime { c: i32, n: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memchr".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, c, n) } @@ -1503,14 +1738,16 @@ impl AsanRuntime { c: i32, n: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memrchr".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, c, n) } @@ -1529,23 +1766,27 @@ impl AsanRuntime { needle: *const c_void, needlelen: usize, ) -> *mut c_void { - if !self.allocator_mut().check_shadow(haystack, haystacklen) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(haystack, haystacklen) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memmem".to_string(), self.real_address_for_stalked(self.pc()), haystack as usize, haystacklen, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(needle, needlelen) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(needle, needlelen) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "memmem".to_string(), self.real_address_for_stalked(self.pc()), needle as usize, needlelen, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(haystack, haystacklen, needle, needlelen) } @@ -1558,14 +1799,16 @@ impl AsanRuntime { s: *mut c_void, n: usize, ) -> usize { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "bzero".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, n) } @@ -1578,14 +1821,16 @@ impl AsanRuntime { s: *mut c_void, n: usize, ) -> usize { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "explicit_bzero".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, n) } @@ -1599,23 +1844,27 @@ impl AsanRuntime { s2: *const c_void, n: usize, ) -> i32 { - if !self.allocator_mut().check_shadow(s1, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s1, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "bcmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(s2, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s2, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "bcmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2, n) } @@ -1634,14 +1883,15 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s as *const c_void, unsafe { strlen(s) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strchr".to_string(), self.real_address_for_stalked(self.pc()), s as usize, unsafe { strlen(s) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, c) } @@ -1659,14 +1909,15 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s as *const c_void, unsafe { strlen(s) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strrchr".to_string(), self.real_address_for_stalked(self.pc()), s as usize, unsafe { strlen(s) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, c) } @@ -1684,26 +1935,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s1 as *const c_void, unsafe { strlen(s1) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcasecmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, unsafe { strlen(s1) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(s2 as *const c_void, unsafe { strlen(s2) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcasecmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, unsafe { strlen(s2) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2) } @@ -1716,23 +1969,27 @@ impl AsanRuntime { s2: *const c_char, n: usize, ) -> i32 { - if !self.allocator_mut().check_shadow(s1 as *const c_void, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s1 as *const c_void, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strncasecmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(s2 as *const c_void, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s2 as *const c_void, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strncasecmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2, n) } @@ -1750,26 +2007,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s1 as *const c_void, unsafe { strlen(s1) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcat".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, unsafe { strlen(s1) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(s2 as *const c_void, unsafe { strlen(s2) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcat".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, unsafe { strlen(s2) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2) } @@ -1787,26 +2046,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s1 as *const c_void, unsafe { strlen(s1) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, unsafe { strlen(s1) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(s2 as *const c_void, unsafe { strlen(s2) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, unsafe { strlen(s2) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2) } @@ -1825,26 +2086,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s1 as *const c_void, unsafe { strnlen(s1, n) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strncmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(s2 as *const c_void, unsafe { strnlen(s2, n) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strncmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2, n) } @@ -1862,26 +2125,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(dest as *const c_void, unsafe { strlen(src) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "strcpy".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, unsafe { strlen(src) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(src as *const c_void, unsafe { strlen(src) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcpy".to_string(), self.real_address_for_stalked(self.pc()), src as usize, unsafe { strlen(src) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src) } @@ -1894,23 +2159,31 @@ impl AsanRuntime { src: *const c_char, n: usize, ) -> *mut c_char { - if !self.allocator_mut().check_shadow(dest as *const c_void, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + extern "system" { + fn strlen(s: *const c_char) -> usize; + } + if !self.allocator_mut().check_shadow(dest as *const c_void, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "strncpy".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(src as *const c_void, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + let mn = std::cmp::min(n, unsafe { strlen(src) } + 1); + if !self.allocator_mut().check_shadow(src as *const c_void, mn) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strncpy".to_string(), self.real_address_for_stalked(self.pc()), src as usize, - n, + mn, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src, n) } @@ -1928,26 +2201,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(dest as *const c_void, unsafe { strlen(src) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "stpcpy".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, unsafe { strlen(src) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(src as *const c_void, unsafe { strlen(src) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "stpcpy".to_string(), self.real_address_for_stalked(self.pc()), src as usize, unsafe { strlen(src) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src) } @@ -1971,15 +2246,17 @@ impl AsanRuntime { fn strlen(s: *const c_char) -> usize; fn strcpy(dest: *mut c_char, src: *const c_char) -> *mut c_char; } - let size = unsafe { strlen(s) }; - if !self.allocator_mut().check_shadow(s as *const c_void, size) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + let size = unsafe { strlen(s) + 1 }; + if !self.allocator_mut().check_shadow(s as *const c_void, size) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strdup".to_string(), self.real_address_for_stalked(self.pc()), s as usize, - unsafe { strlen(s) }, + unsafe { strlen(s) + 1 }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } unsafe { @@ -1996,14 +2273,16 @@ impl AsanRuntime { s: *const c_char, ) -> usize { let size = original(s); - if !self.allocator_mut().check_shadow(s as *const c_void, size) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s as *const c_void, size) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strlen".to_string(), self.real_address_for_stalked(self.pc()), s as usize, size, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } size } @@ -2016,14 +2295,16 @@ impl AsanRuntime { n: usize, ) -> usize { let size = original(s, n); - if !self.allocator_mut().check_shadow(s as *const c_void, size) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + if !self.allocator_mut().check_shadow(s as *const c_void, size) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strnlen".to_string(), self.real_address_for_stalked(self.pc()), s as usize, size, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } size } @@ -2041,26 +2322,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(haystack as *const c_void, unsafe { strlen(haystack) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strstr".to_string(), self.real_address_for_stalked(self.pc()), haystack as usize, unsafe { strlen(haystack) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(needle as *const c_void, unsafe { strlen(needle) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strstr".to_string(), self.real_address_for_stalked(self.pc()), needle as usize, unsafe { strlen(needle) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(haystack, needle) } @@ -2078,26 +2361,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(haystack as *const c_void, unsafe { strlen(haystack) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcasestr".to_string(), self.real_address_for_stalked(self.pc()), haystack as usize, unsafe { strlen(haystack) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(needle as *const c_void, unsafe { strlen(needle) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "strcasestr".to_string(), self.real_address_for_stalked(self.pc()), needle as usize, unsafe { strlen(needle) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(haystack, needle) } @@ -2114,14 +2399,15 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s as *const c_void, unsafe { strlen(s) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "atoi".to_string(), self.real_address_for_stalked(self.pc()), s as usize, unsafe { strlen(s) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s) } @@ -2139,14 +2425,15 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s as *const c_void, unsafe { strlen(s) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "atol".to_string(), self.real_address_for_stalked(self.pc()), s as usize, unsafe { strlen(s) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s) } @@ -2164,14 +2451,15 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s as *const c_void, unsafe { strlen(s) }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "atoll".to_string(), self.real_address_for_stalked(self.pc()), s as usize, unsafe { strlen(s) }, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s) } @@ -2187,14 +2475,15 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s as *const c_void, (size + 1) * 2) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "wcslen".to_string(), self.real_address_for_stalked(self.pc()), s as usize, (size + 1) * 2, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } size } @@ -2213,26 +2502,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(dest as *const c_void, unsafe { (wcslen(src) + 1) * 2 }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "wcscpy".to_string(), self.real_address_for_stalked(self.pc()), dest as usize, (unsafe { wcslen(src) } + 1) * 2, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(src as *const c_void, unsafe { (wcslen(src) + 1) * 2 }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "wcscpy".to_string(), self.real_address_for_stalked(self.pc()), src as usize, (unsafe { wcslen(src) } + 1) * 2, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(dest, src) } @@ -2251,26 +2542,28 @@ impl AsanRuntime { if !self .allocator_mut() .check_shadow(s1 as *const c_void, unsafe { (wcslen(s1) + 1) * 2 }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "wcscmp".to_string(), self.real_address_for_stalked(self.pc()), s1 as usize, (unsafe { wcslen(s1) } + 1) * 2, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } if !self .allocator_mut() .check_shadow(s2 as *const c_void, unsafe { (wcslen(s2) + 1) * 2 }) - { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgRead(( "wcscmp".to_string(), self.real_address_for_stalked(self.pc()), s2 as usize, (unsafe { wcslen(s2) } + 1) * 2, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s1, s2) } @@ -2284,23 +2577,27 @@ impl AsanRuntime { p4: *const c_void, n: usize, ) { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset_pattern4".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(p4, n / 4) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(p4, n / 4) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset_pattern4".to_string(), self.real_address_for_stalked(self.pc()), p4 as usize, n / 4, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, p4, n); } @@ -2314,23 +2611,27 @@ impl AsanRuntime { p8: *const c_void, n: usize, ) { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset_pattern8".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(p8, n / 8) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(p8, n / 8) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset_pattern8".to_string(), self.real_address_for_stalked(self.pc()), p8 as usize, n / 8, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, p8, n); } @@ -2344,23 +2645,27 @@ impl AsanRuntime { p16: *const c_void, n: usize, ) { - if !self.allocator_mut().check_shadow(s, n) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(s, n) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset_pattern16".to_string(), self.real_address_for_stalked(self.pc()), s as usize, n, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } - if !self.allocator_mut().check_shadow(p16, n / 16) { - AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( + if !self.allocator_mut().check_shadow(p16, n / 16) + && AsanErrors::get_mut_blocking().report_error(AsanError::BadFuncArgWrite(( "memset_pattern16".to_string(), self.real_address_for_stalked(self.pc()), p16 as usize, n / 16, Backtrace::new(), - ))); + ))) + { + panic!("ASAN: Crashing target!"); } original(s, p16, n); } diff --git a/libafl_frida/src/executor.rs b/libafl_frida/src/executor.rs index c11d4be52b..bfc9b80a4b 100644 --- a/libafl_frida/src/executor.rs +++ b/libafl_frida/src/executor.rs @@ -177,13 +177,15 @@ where // 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::with_target_bytes_converter as usize + for module in frida_gum::Process::obtain(gum).enumerate_modules() { + let range = module.range(); + if (range.base_address().0 as usize) < 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 + < range.base_address().0 as u64 + range.size() as u64 { ranges.insert( - module.base_address as u64..(module.base_address as u64 + module.size as u64), + range.base_address().0 as u64 + ..(range.base_address().0 as u64 + range.size() as u64), (0xffff, "fuzzer".to_string()), ); break; diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 3a14a4b000..b5a60728af 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -11,7 +11,7 @@ use std::{ use frida_gum::{ instruction_writer::InstructionWriter, stalker::{StalkerIterator, StalkerOutput, Transformer}, - Backend, Gum, ModuleDetails, ModuleMap, Script, + Backend, Gum, Module, ModuleMap, Script, }; use frida_gum_sys::gchar; use libafl::Error; @@ -276,8 +276,8 @@ pub struct FridaInstrumentationHelperBuilder { stalker_enabled: bool, disable_excludes: bool, #[expect(clippy::type_complexity)] - instrument_module_predicate: Option bool>>, - skip_module_predicate: Box bool>, + instrument_module_predicate: Option bool>>, + skip_module_predicate: Box bool>, skip_ranges: Vec, } @@ -353,7 +353,7 @@ impl FridaInstrumentationHelperBuilder { /// .instrument_module_if(|module| module.path().starts_with("/usr/lib")); /// ``` #[must_use] - pub fn instrument_module_if bool + 'static>( + pub fn instrument_module_if bool + 'static>( mut self, mut predicate: F, ) -> Self { @@ -382,10 +382,7 @@ impl FridaInstrumentationHelperBuilder { /// .skip_module_if(|module| module.name() == "libfoo.so"); /// ``` #[must_use] - pub fn skip_module_if bool + 'static>( - mut self, - mut predicate: F, - ) -> Self { + pub fn skip_module_if bool + 'static>(mut self, mut predicate: F) -> Self { let new = move |module: &_| (self.skip_module_predicate)(module) || predicate(module); Self { skip_module_predicate: Box::new(new), @@ -430,7 +427,7 @@ impl FridaInstrumentationHelperBuilder { !skip_module_predicate(&module) } }); - let module_map = Rc::new(ModuleMap::new_with_filter(gum, &mut module_filter)); + let module_map = Rc::new(ModuleMap::new_with_filter(&mut module_filter)); let ranges = RangeMap::new(); // Wrap ranges and runtimes in reference-counted refcells in order to move @@ -461,7 +458,7 @@ impl FridaInstrumentationHelperBuilder { .borrow_mut() .remove(range.start as u64..range.end as u64), SkipRange::ModuleRelative { name, range } => { - let module_details = ModuleDetails::with_name(name).unwrap(); + let module_details = Module::load(gum, &name); let lib_start = module_details.range().base_address().0 as u64; ranges.borrow_mut().remove( (lib_start + range.start as u64)..(lib_start + range.end as u64), @@ -550,7 +547,7 @@ pub unsafe extern "C" fn test_function(message: *const gchar) { } } -fn pathlist_contains_module(list: I, module: &ModuleDetails) -> bool +fn pathlist_contains_module(list: I, module: &Module) -> bool where I: IntoIterator, P: AsRef, diff --git a/libafl_frida/src/windows_hooks.rs b/libafl_frida/src/windows_hooks.rs index f02e2f2f12..772ef469d5 100644 --- a/libafl_frida/src/windows_hooks.rs +++ b/libafl_frida/src/windows_hooks.rs @@ -1,7 +1,7 @@ // Based on the example of setting hooks: Https://github.com/frida/frida-rust/blob/main/examples/gum/hook_open/src/lib.rs use std::ffi::c_void; -use frida_gum::{interceptor::Interceptor, Gum, Module, NativePointer}; +use frida_gum::{interceptor::Interceptor, Gum, NativePointer, Process}; use libafl_bolts::os::windows_exceptions::{ handle_exception, IsProcessorFeaturePresent, UnhandledExceptionFilter, EXCEPTION_POINTERS, PROCESSOR_FEATURE_ID, @@ -21,16 +21,16 @@ unsafe extern "C" fn unhandled_exception_filter_detour( } /// Initialize the hooks pub fn initialize(gum: &Gum) { - let module = Module::obtain(gum); - let is_processor_feature_present = - module.find_export_by_name(Some("kernel32.dll"), "IsProcessorFeaturePresent"); + let module = Process::obtain(gum) + .find_module_by_name("kernel32.dll") + .unwrap(); + let is_processor_feature_present = module.find_export_by_name("IsProcessorFeaturePresent"); let is_processor_feature_present = is_processor_feature_present.unwrap(); assert!( !is_processor_feature_present.is_null(), "IsProcessorFeaturePresent not found" ); - let unhandled_exception_filter = - module.find_export_by_name(Some("kernel32.dll"), "UnhandledExceptionFilter"); + let unhandled_exception_filter = module.find_export_by_name("UnhandledExceptionFilter"); let unhandled_exception_filter = unhandled_exception_filter.unwrap(); assert!( !unhandled_exception_filter.is_null(),