From 56c4f4d45c04dab361fd5c294dbf4792a3c1d742 Mon Sep 17 00:00:00 2001 From: Elazar Leibovich Date: Tue, 29 Oct 2024 18:02:32 +0300 Subject: [PATCH] frida-gum: force frida-gum init to use Module (#98) (#172) * frida-gum: force frida-gum init to use Module (#98) In order to use the underlying C API global init should be called. We hence force the creation of Gum to use Module::* functions. We also use OnceLock instead of lazy_static! as discussed in the issue. * CR: s/from_gum/obtain/ * frida-gum: clippy --- examples/gum/debug_symbol/src/main.rs | 13 +++++----- examples/gum/hook_instruction/Cargo.toml | 1 - examples/gum/hook_instruction/src/lib.rs | 13 +++++----- examples/gum/hook_open/src/lib.rs | 9 ++++--- examples/gum/open/Cargo.toml | 1 - examples/gum/open/src/lib.rs | 16 ++++++------- frida-gum/src/module.rs | 30 ++++++++++++++++++------ 7 files changed, 49 insertions(+), 34 deletions(-) diff --git a/examples/gum/debug_symbol/src/main.rs b/examples/gum/debug_symbol/src/main.rs index c0f466b0..9e71a476 100644 --- a/examples/gum/debug_symbol/src/main.rs +++ b/examples/gum/debug_symbol/src/main.rs @@ -1,15 +1,14 @@ use frida_gum::DebugSymbol; use frida_gum::{Gum, Module}; -use lazy_static::lazy_static; - -lazy_static! { - static ref GUM: Gum = unsafe { Gum::obtain() }; -} +use std::iter::Once; +use std::sync::OnceLock; fn main() { - lazy_static::initialize(&GUM); + static CELL: OnceLock = OnceLock::new(); + let gum = CELL.get_or_init(|| Gum::obtain()); - let symbol = Module::find_export_by_name(None, "mmap").unwrap(); + let module = Module::obtain(gum); + let symbol = module.find_export_by_name(None, "mmap").unwrap(); let symbol_details = DebugSymbol::from_address(symbol).unwrap(); println!( "address={:#x?} module_name={:?} symbol_name={:?} file_name={:?} line_number={:?}", diff --git a/examples/gum/hook_instruction/Cargo.toml b/examples/gum/hook_instruction/Cargo.toml index 09b992ef..a104ab92 100644 --- a/examples/gum/hook_instruction/Cargo.toml +++ b/examples/gum/hook_instruction/Cargo.toml @@ -11,5 +11,4 @@ crate-type = ["cdylib"] [dependencies] frida-gum = { path = "../../../frida-gum", features = ["invocation-listener"] } -lazy_static = "1.4" ctor = "0.2" diff --git a/examples/gum/hook_instruction/src/lib.rs b/examples/gum/hook_instruction/src/lib.rs index 0ec1b996..79ad01c4 100644 --- a/examples/gum/hook_instruction/src/lib.rs +++ b/examples/gum/hook_instruction/src/lib.rs @@ -3,11 +3,7 @@ use frida_gum::{ interceptor::{Interceptor, InvocationContext, ProbeListener}, Gum, Module, }; -use lazy_static::lazy_static; - -lazy_static! { - static ref GUM: Gum = unsafe { Gum::obtain() }; -} +use std::sync::OnceLock; #[derive(Default, Debug)] struct OpenProbeListener; @@ -19,8 +15,11 @@ impl ProbeListener for OpenProbeListener { #[ctor] fn init() { - let mut interceptor = Interceptor::obtain(&GUM); - let open = Module::find_export_by_name(None, "open").unwrap(); + static CELL: OnceLock = OnceLock::new(); + let gum = CELL.get_or_init(|| Gum::obtain()); + let mut interceptor = Interceptor::obtain(gum); + let module = Module::obtain(gum); + let open = module.find_export_by_name(None, "open").unwrap(); let mut listener = OpenProbeListener; interceptor.attach_instruction(open, &mut listener).unwrap(); } diff --git a/examples/gum/hook_open/src/lib.rs b/examples/gum/hook_open/src/lib.rs index d4d00cfd..cead4d9c 100644 --- a/examples/gum/hook_open/src/lib.rs +++ b/examples/gum/hook_open/src/lib.rs @@ -4,9 +4,9 @@ use lazy_static::lazy_static; use libc::{c_char, c_int, c_void}; use std::cell::UnsafeCell; use std::sync::Mutex; +use std::sync::OnceLock; lazy_static! { - static ref GUM: Gum = unsafe { Gum::obtain() }; static ref ORIGINAL_OPEN: Mutex>> = Mutex::new(UnsafeCell::new(None)); } @@ -29,8 +29,11 @@ unsafe extern "C" fn open_detour(name: *const c_char, flags: c_int) -> c_int { #[ctor] fn init() { - let mut interceptor = Interceptor::obtain(&GUM); - let open = Module::find_export_by_name(None, "open").unwrap(); + static CELL: OnceLock = OnceLock::new(); + let gum = CELL.get_or_init(|| Gum::obtain()); + let module = Module::obtain(gum); + let mut interceptor = Interceptor::obtain(gum); + let open = module.find_export_by_name(None, "open").unwrap(); unsafe { *ORIGINAL_OPEN.lock().unwrap().get_mut() = Some(std::mem::transmute::< *mut libc::c_void, diff --git a/examples/gum/open/Cargo.toml b/examples/gum/open/Cargo.toml index 2b573987..c31585cd 100644 --- a/examples/gum/open/Cargo.toml +++ b/examples/gum/open/Cargo.toml @@ -11,4 +11,3 @@ crate-type = ["cdylib"] [dependencies] frida-gum = { path = "../../../frida-gum", features = ["invocation-listener"] } -lazy_static = "1.4" diff --git a/examples/gum/open/src/lib.rs b/examples/gum/open/src/lib.rs index 9723aa52..c48fbeb7 100644 --- a/examples/gum/open/src/lib.rs +++ b/examples/gum/open/src/lib.rs @@ -5,12 +5,8 @@ use gum::{ interceptor::{Interceptor, InvocationContext, InvocationListener}, Gum, Module, }; -use lazy_static::lazy_static; use std::os::raw::{c_int, c_void}; - -lazy_static! { - static ref GUM: Gum = unsafe { Gum::obtain() }; -} +use std::sync::OnceLock; struct OpenListener; @@ -28,10 +24,14 @@ impl InvocationListener for OpenListener { extern "C" fn example_agent_main(_user_data: *const c_void, resident: *mut c_int) { unsafe { *resident = 1 }; - let mut interceptor = Interceptor::obtain(&GUM); + static CELL: OnceLock = OnceLock::new(); + let gum = CELL.get_or_init(|| Gum::obtain()); + + let mut interceptor = Interceptor::obtain(gum); let mut listener = OpenListener {}; - let modules = Module::enumerate_modules(); + let module = Module::obtain(gum); + let modules = module.enumerate_modules(); for module in modules { println!( "{}@{:#x}/{:#x}", @@ -39,6 +39,6 @@ extern "C" fn example_agent_main(_user_data: *const c_void, resident: *mut c_int ); } - let open = Module::find_export_by_name(None, "open").unwrap(); + let open = module.find_export_by_name(None, "open").unwrap(); interceptor.attach(open, &mut listener).unwrap(); } diff --git a/frida-gum/src/module.rs b/frida-gum/src/module.rs index b5dfd978..fc8a38a3 100644 --- a/frida-gum/src/module.rs +++ b/frida-gum/src/module.rs @@ -14,7 +14,7 @@ )] use { - crate::{NativePointer, PageProtection, RangeDetails}, + crate::{Gum, NativePointer, PageProtection, RangeDetails}, core::ffi::c_void, cstr_core::CString, frida_gum_sys as gum_sys, @@ -56,12 +56,23 @@ pub struct ModuleDetailsOwned { pub size: usize, } -pub struct Module; +pub struct Module { + // This is to verify that Gum is initialized before using any Module methods which requires + // intialization. + // Note that Gum is expected to be initialized via OnceCell which provides &Gum for every + // instance. + _gum: &'static Gum, +} impl Module { + pub fn obtain(gum: &'static Gum) -> Module { + Module { _gum: gum } + } + /// The absolute address of the export. In the event that no such export /// could be found, returns NULL. pub fn find_export_by_name( + &self, module_name: Option<&str>, symbol_name: &str, ) -> Option { @@ -92,7 +103,11 @@ impl Module { /// The absolute address of the symbol. In the event that no such symbol /// could be found, returns NULL. - pub fn find_symbol_by_name(module_name: &str, symbol_name: &str) -> Option { + pub fn find_symbol_by_name( + &self, + module_name: &str, + symbol_name: &str, + ) -> Option { let symbol_name = CString::new(symbol_name).unwrap(); let module_name = CString::new(module_name).unwrap(); @@ -112,7 +127,7 @@ impl Module { /// Returns the base address of the specified module. In the event that no /// such module could be found, returns NULL. - pub fn find_base_address(module_name: &str) -> NativePointer { + pub fn find_base_address(&self, module_name: &str) -> NativePointer { let module_name = CString::new(module_name).unwrap(); unsafe { @@ -124,6 +139,7 @@ impl Module { /// Enumerates memory ranges satisfying protection given. pub fn enumerate_ranges( + &self, module_name: &str, prot: PageProtection, callout: impl FnMut(RangeDetails) -> bool, @@ -147,7 +163,7 @@ impl Module { } /// Enumerates modules. - pub fn enumerate_modules() -> Vec { + pub fn enumerate_modules(&self) -> Vec { let result: Vec = vec![]; unsafe extern "C" fn callback( @@ -187,7 +203,7 @@ impl Module { } /// Enumerates exports in module. - pub fn enumerate_exports(module_name: &str) -> Vec { + pub fn enumerate_exports(&self, module_name: &str) -> Vec { let result: Vec = vec![]; unsafe extern "C" fn callback( @@ -219,7 +235,7 @@ impl Module { } /// Enumerates symbols in module. - pub fn enumerate_symbols(module_name: &str) -> Vec { + pub fn enumerate_symbols(&self, module_name: &str) -> Vec { let result: Vec = vec![]; unsafe extern "C" fn callback( details: *const GumSymbolDetails,