diff --git a/fuzzers/frida_gdiplus/Cargo.toml b/fuzzers/frida_gdiplus/Cargo.toml index 1227a3eb3f..e5e06f249c 100644 --- a/fuzzers/frida_gdiplus/Cargo.toml +++ b/fuzzers/frida_gdiplus/Cargo.toml @@ -29,7 +29,6 @@ capstone = "0.11.0" frida-gum = { version = "0.8.1", features = [ "auto-download", "event-sink", "invocation-listener"] } libafl_frida = { path = "../../libafl_frida", features = ["cmplog"] } libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] } -lazy_static = "1.4.0" libc = "0.2" libloading = "0.7" num-traits = "0.2" diff --git a/libafl/src/bolts/os/windows_exceptions.rs b/libafl/src/bolts/os/windows_exceptions.rs index ee255d39da..170ef1a541 100644 --- a/libafl/src/bolts/os/windows_exceptions.rs +++ b/libafl/src/bolts/os/windows_exceptions.rs @@ -13,7 +13,10 @@ use std::os::raw::{c_long, c_void}; use num_enum::TryFromPrimitive; pub use windows::Win32::{ Foundation::NTSTATUS, - System::Diagnostics::Debug::{AddVectoredExceptionHandler, EXCEPTION_POINTERS}, + System::{ + Diagnostics::Debug::{AddVectoredExceptionHandler, EXCEPTION_POINTERS}, + Threading::{IsProcessorFeaturePresent, PROCESSOR_FEATURE_ID}, + }, }; use crate::Error; @@ -315,8 +318,12 @@ unsafe fn internal_handle_exception( } } -/// Internal function that is being called whenever an exception arrives (stdcall). -unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_POINTERS) -> c_long { +/// Function that is being called whenever an exception arrives (stdcall). +/// # Safety +/// This function is unsafe because it is called by the OS +pub unsafe extern "system" fn handle_exception( + exception_pointers: *mut EXCEPTION_POINTERS, +) -> c_long { let code = exception_pointers .as_mut() .unwrap() diff --git a/libafl_frida/src/executor.rs b/libafl_frida/src/executor.rs index 1eceda602e..d9e4fa4b67 100644 --- a/libafl_frida/src/executor.rs +++ b/libafl_frida/src/executor.rs @@ -17,6 +17,8 @@ use libafl::{ #[cfg(unix)] use crate::asan::errors::ASAN_ERRORS; use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple}; +#[cfg(windows)] +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, I, OT, RT, S> @@ -146,6 +148,9 @@ where )); } + #[cfg(windows)] + initialize(&gum); + Self { base, stalker, diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 68410c57dc..5a1b838aa7 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -69,6 +69,10 @@ pub mod alloc; #[cfg(unix)] pub mod asan; +#[cfg(windows)] +/// Windows specific hooks to catch __fastfail like exceptions with Frida, see https://github.com/AFLplusplus/LibAFL/issues/395 for more details +pub mod windows_hooks; + pub mod coverage_rt; #[cfg(feature = "cmplog")] diff --git a/libafl_frida/src/windows_hooks.rs b/libafl_frida/src/windows_hooks.rs new file mode 100644 index 0000000000..06bae64a6e --- /dev/null +++ b/libafl_frida/src/windows_hooks.rs @@ -0,0 +1,55 @@ +// Based on the example of setting hooks: Https://github.com/frida/frida-rust/blob/main/examples/gum/hook_open/src/lib.rs +use frida_gum::{interceptor::Interceptor, Gum, Module, NativePointer}; +use libafl::bolts::os::windows_exceptions::{ + handle_exception, IsProcessorFeaturePresent, EXCEPTION_POINTERS, PROCESSOR_FEATURE_ID, +}; + +/// Initialize the hooks +pub fn initialize(gum: &Gum) { + let is_processor_feature_present = + Module::find_export_by_name(Some("kernel32.dll"), "IsProcessorFeaturePresent"); + let is_processor_feature_present = is_processor_feature_present.unwrap(); + if is_processor_feature_present.is_null() { + panic!("IsProcessorFeaturePresent not found"); + } + let unhandled_exception_filter = + Module::find_export_by_name(Some("kernel32.dll"), "UnhandledExceptionFilter"); + let unhandled_exception_filter = unhandled_exception_filter.unwrap(); + if unhandled_exception_filter.is_null() { + panic!("UnhandledExceptionFilter not found"); + } + + let mut interceptor = Interceptor::obtain(&gum); + use std::ffi::c_void; + + interceptor + .replace( + is_processor_feature_present, + NativePointer(is_processor_feature_present_detour as *mut c_void), + NativePointer(std::ptr::null_mut()), + ) + .unwrap(); + + interceptor + .replace( + unhandled_exception_filter, + NativePointer(unhandled_exception_filter_detour as *mut c_void), + NativePointer(std::ptr::null_mut()), + ) + .unwrap(); + + unsafe extern "C" fn is_processor_feature_present_detour(feature: u32) -> bool { + let result = match feature { + 0x17 => false, + _ => IsProcessorFeaturePresent(PROCESSOR_FEATURE_ID(feature)).as_bool(), + }; + result + } + + unsafe extern "C" fn unhandled_exception_filter_detour( + exception_pointers: *mut EXCEPTION_POINTERS, + ) -> i32 { + handle_exception(exception_pointers); + unreachable!("handle_exception should not return"); + } +}