diff --git a/frida-gum/src/lib.rs b/frida-gum/src/lib.rs index 6d30617..9041fd2 100644 --- a/frida-gum/src/lib.rs +++ b/frida-gum/src/lib.rs @@ -81,6 +81,9 @@ pub use module::*; mod module_map; pub use module_map::*; +mod process; +pub use process::*; + mod error; pub use error::Error; diff --git a/frida-gum/src/module.rs b/frida-gum/src/module.rs index 55ad145..37bca9d 100644 --- a/frida-gum/src/module.rs +++ b/frida-gum/src/module.rs @@ -53,6 +53,37 @@ impl fmt::Display for ExportType { } } +impl ModuleDetailsOwned { + pub unsafe fn from_module_details(details: *const GumModuleDetails) -> Self { + let name: String = NativePointer((*details).name as *mut _) + .try_into() + .unwrap_or_default(); + let path: String = NativePointer((*details).path as *mut _) + .try_into() + .unwrap_or_default(); + let range = (*details).range; + let base_address = (*range).base_address as usize; + let size = (*range).size as usize; + + ModuleDetailsOwned { + name, + path, + base_address, + size, + } + } +} + +impl fmt::Display for ModuleDetailsOwned { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + fmt, + "{{\n\tbase: 0x{:x}\n\tname: {}\n\tpath: {}\n\tsize: {}\n}}", + self.base_address, self.name, self.path, self.size + ) + } +} + /// Module symbol details returned by [`Module::enumerate_symbols`]. pub struct SymbolDetails { pub name: String, @@ -91,7 +122,7 @@ pub struct Module<'a> { _gum: &'a Gum, } -impl<'a> Module<'a> { +impl Module<'_> { pub fn obtain(gum: &Gum) -> Module { Module { _gum: gum } } @@ -198,23 +229,7 @@ impl<'a> Module<'a> { user_data: gpointer, ) -> gboolean { let res = &mut *(user_data as *mut Vec); - - let name: String = NativePointer((*details).name as *mut _) - .try_into() - .unwrap_or_default(); - let path: String = NativePointer((*details).path as *mut _) - .try_into() - .unwrap_or_default(); - let range = (*details).range; - let base_address = (*range).base_address as usize; - let size = (*range).size as usize; - let module_details = ModuleDetailsOwned { - name, - path, - base_address, - size, - }; - res.push(module_details); + res.push(ModuleDetailsOwned::from_module_details(details)); 1 } diff --git a/frida-gum/src/process.rs b/frida-gum/src/process.rs new file mode 100644 index 0000000..fff714a --- /dev/null +++ b/frida-gum/src/process.rs @@ -0,0 +1,139 @@ +//! Process helpers. +//! + +#![cfg_attr( + any(target_arch = "x86_64", target_arch = "x86"), + allow(clippy::unnecessary_cast) +)] + +use crate::{FileMapping, NativePointer}; + +use { + crate::{module, Gum, PageProtection, RangeDetails}, + core::ffi::c_void, + frida_gum_sys as gum_sys, + frida_gum_sys::{gboolean, gpointer}, +}; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +#[derive(Clone, FromPrimitive, Debug)] +#[repr(u32)] +pub enum CodeSigningPolicy { + CodeSigningOptional = gum_sys::GumCodeSigningPolicy_GUM_CODE_SIGNING_OPTIONAL as u32, + CodeSigningRequired = gum_sys::GumCodeSigningPolicy_GUM_CODE_SIGNING_REQUIRED as u32, +} + +#[derive(Clone, FromPrimitive, Debug)] +#[repr(u32)] +pub enum Os { + OsWindows = gum_sys::_GumOS_GUM_OS_WINDOWS as u32, + OsMacos = gum_sys::_GumOS_GUM_OS_MACOS as u32, + OsLinux = gum_sys::_GumOS_GUM_OS_LINUX as u32, + OsIos = gum_sys::_GumOS_GUM_OS_IOS as u32, + OsWatchos = gum_sys::_GumOS_GUM_OS_WATCHOS as u32, + OsTvos = gum_sys::_GumOS_GUM_OS_TVOS as u32, + OsAndroid = gum_sys::_GumOS_GUM_OS_ANDROID as u32, + OsFreebsd = gum_sys::_GumOS_GUM_OS_FREEBSD as u32, + OsQnx = gum_sys::_GumOS_GUM_OS_QNX as u32, +} + +pub struct Range<'a> { + /// Base address + pub base: NativePointer, + /// Size in bytes + pub size: usize, + /// Protection flag (e.g., Read, Write, Execute) + pub protection: PageProtection, + /// When available, file mapping details. + pub file: Option>, +} + +pub struct Process<'a> { + // 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: &'a Gum, + /// Property containing the PID as a number + pub id: u32, + /// Properly specifying the current platform. + pub platform: Os, + /// Property which can be `optional` or `required`, where the latter means Frida will avoid modifying + /// existing code in memory and will not try to run unsigned code. + pub code_signing_policy: CodeSigningPolicy, + /// Contains a Module representing the main executable of the process. + pub main_module: module::ModuleDetailsOwned, +} + +impl<'a> Process<'a> { + /// Initialize a new process + pub fn obtain(gum: &'a Gum) -> Process<'a> { + let id = unsafe { gum_sys::gum_process_get_id() }; + let platform = + num::FromPrimitive::from_u32(unsafe { gum_sys::gum_process_get_native_os() }).unwrap(); + let code_signing_policy = num::FromPrimitive::from_u32(unsafe { + gum_sys::gum_process_get_code_signing_policy() as u32 + }) + .unwrap(); + + let main_module = unsafe { + module::ModuleDetailsOwned::from_module_details(gum_sys::gum_process_get_main_module()) + }; + + Process { + _gum: gum, + id, + platform, + code_signing_policy, + main_module, + } + } + + /// Enumerates memory ranges satisfying `protection` given + pub fn enumerate_ranges(&self, protection: PageProtection) -> Vec> { + struct CallbackData<'a> { + ranges: Vec>, + protection: PageProtection, + } + + unsafe extern "C" fn enumerate_ranges_callback( + details: *const gum_sys::GumRangeDetails, + user_data: gpointer, + ) -> gboolean { + let res = &mut *(user_data as *mut CallbackData); + let r_details = RangeDetails::from_raw(details); + + let prot = r_details.protection(); + if res.protection == prot { + let m_range = r_details.memory_range(); + let file_map = r_details.file_mapping(); + + res.ranges.push(Range { + base: m_range.base_address(), + size: m_range.size(), + protection: prot, + file: file_map, + }); + } + + 1 + } + + let callback_data = CallbackData { + ranges: Vec::new(), + protection: protection.clone(), + }; + + unsafe { + gum_sys::gum_process_enumerate_ranges( + protection as u32, + Some(enumerate_ranges_callback), + &callback_data as *const _ as *mut c_void, + ); + } + + callback_data.ranges + } +} diff --git a/frida-gum/src/range_details.rs b/frida-gum/src/range_details.rs index 6b19bc8..092497a 100644 --- a/frida-gum/src/range_details.rs +++ b/frida-gum/src/range_details.rs @@ -25,7 +25,7 @@ use { use alloc::{boxed::Box, string::String}; /// The memory protection of an unassociated page. -#[derive(Clone, FromPrimitive, Debug)] +#[derive(Clone, FromPrimitive, Debug, PartialEq)] #[repr(u32)] pub enum PageProtection { NoAccess = gum_sys::_GumPageProtection_GUM_PAGE_NO_ACCESS as u32, @@ -64,7 +64,7 @@ pub struct FileMapping<'a> { phantom: PhantomData<&'a gum_sys::GumFileMapping>, } -impl<'a> FileMapping<'a> { +impl FileMapping<'_> { pub(crate) fn from_raw(file: *const gum_sys::GumFileMapping) -> Option { if file.is_null() { None diff --git a/frida-gum/src/stalker/transformer.rs b/frida-gum/src/stalker/transformer.rs index 48a29d6..ed8675f 100644 --- a/frida-gum/src/stalker/transformer.rs +++ b/frida-gum/src/stalker/transformer.rs @@ -204,7 +204,7 @@ impl<'a> Transformer<'a> { } } -impl<'a> Drop for Transformer<'a> { +impl Drop for Transformer<'_> { fn drop(&mut self) { unsafe { frida_gum_sys::g_object_unref(self.transformer as *mut c_void) } } diff --git a/frida/src/device.rs b/frida/src/device.rs index e7502a4..8f6933b 100644 --- a/frida/src/device.rs +++ b/frida/src/device.rs @@ -253,7 +253,7 @@ impl<'a> Device<'a> { } } -impl<'a> Drop for Device<'a> { +impl Drop for Device<'_> { fn drop(&mut self) { unsafe { frida_sys::frida_unref(self.device_ptr as _) } } diff --git a/frida/src/device_manager.rs b/frida/src/device_manager.rs index 3261b76..9325399 100644 --- a/frida/src/device_manager.rs +++ b/frida/src/device_manager.rs @@ -82,7 +82,7 @@ impl<'a> DeviceManager<'a> { return Err(Error::DeviceLookupFailed); } - return Ok(Device::from_raw(device_ptr)); + Ok(Device::from_raw(device_ptr)) } /// Returns the remote device with the specified host. @@ -104,7 +104,7 @@ impl<'a> DeviceManager<'a> { return Err(Error::DeviceLookupFailed); } - return Ok(Device::from_raw(device_ptr)); + Ok(Device::from_raw(device_ptr)) } /// Returns the local device. @@ -141,11 +141,11 @@ impl<'a> DeviceManager<'a> { return Err(Error::DeviceLookupFailed); } - return Ok(Device::from_raw(device_ptr)); + Ok(Device::from_raw(device_ptr)) } } -impl<'a> Drop for DeviceManager<'a> { +impl Drop for DeviceManager<'_> { fn drop(&mut self) { unsafe { frida_sys::frida_device_manager_close_sync( diff --git a/frida/src/injector.rs b/frida/src/injector.rs index 1fd7eb2..c37a864 100644 --- a/frida/src/injector.rs +++ b/frida/src/injector.rs @@ -44,7 +44,7 @@ impl<'a> Injector<'a> { } } -impl<'a> Default for Injector<'a> { +impl Default for Injector<'_> { fn default() -> Self { Self::new() } @@ -130,7 +130,7 @@ pub trait Inject { E: AsRef; } -impl<'a> Inject for Injector<'a> { +impl Inject for Injector<'_> { fn inject_library_file_sync( &mut self, pid: u32, @@ -228,7 +228,7 @@ impl<'a> Inject for Injector<'a> { } } -impl<'a> Inject for Device<'a> { +impl Inject for Device<'_> { fn inject_library_file_sync( &mut self, pid: u32, diff --git a/frida/src/process.rs b/frida/src/process.rs index 2b126ce..6333de2 100644 --- a/frida/src/process.rs +++ b/frida/src/process.rs @@ -36,7 +36,7 @@ impl<'a> Process<'a> { } } -impl<'a> Drop for Process<'a> { +impl Drop for Process<'_> { fn drop(&mut self) { unsafe { frida_sys::frida_unref(self.process_ptr as _) } } @@ -59,7 +59,7 @@ pub struct SpawnOptions<'a> { phantom: PhantomData<&'a FridaSpawnOptions>, } -impl<'a> SpawnOptions<'a> { +impl SpawnOptions<'_> { pub(crate) fn from_raw(options_ptr: *mut FridaSpawnOptions) -> Self { Self { options_ptr, @@ -159,13 +159,13 @@ impl<'a> SpawnOptions<'a> { } } -impl<'a> Default for SpawnOptions<'a> { +impl Default for SpawnOptions<'_> { fn default() -> Self { Self::new() } } -impl<'a> Drop for SpawnOptions<'a> { +impl Drop for SpawnOptions<'_> { fn drop(&mut self) { unsafe { frida_sys::frida_unref(self.options_ptr as _) } } diff --git a/frida/src/script.rs b/frida/src/script.rs index 412a9f0..8941d53 100644 --- a/frida/src/script.rs +++ b/frida/src/script.rs @@ -152,7 +152,7 @@ pub struct Exports<'a> { phantom: PhantomData<&'a _FridaScript>, } -impl<'a> Exports<'a> { +impl Exports<'_> { fn inc_id(&mut self) -> usize { let mut counter_borrow = self.rpc_id_counter.borrow_mut(); *counter_borrow += 1; @@ -306,7 +306,7 @@ impl<'a> Script<'a> { } } -impl<'a> Exports<'a> { +impl Exports<'_> { /// Run exported functions from a Frida script. pub fn call(&mut self, function_name: &str, args: Option) -> Result> { let json_req: String = { @@ -356,7 +356,7 @@ impl<'a> Exports<'a> { } } -impl<'a> Drop for Script<'a> { +impl Drop for Script<'_> { fn drop(&mut self) { unsafe { frida_sys::frida_unref(self.script_ptr as _) } } diff --git a/frida/src/session.rs b/frida/src/session.rs index d74bb3c..534be97 100644 --- a/frida/src/session.rs +++ b/frida/src/session.rs @@ -77,7 +77,7 @@ impl<'a> Session<'a> { } } -impl<'a> Drop for Session<'a> { +impl Drop for Session<'_> { fn drop(&mut self) { unsafe { frida_sys::frida_unref(self.session_ptr as _) } }