frida/frida-rust

How to call original function from replacement?

aviramha opened this issue · 13 comments

Hi!
I have to say this library is amazing, both in structure and design and functionality.
I am now trying to figure out how to call the original function from the detour/function that replaced it.
I'd love to contribute my case as an example later on for it to be more accessible.

Thanks!

s1341 commented

You just call it. Frida automagically makes sure you don’t recurse into the hook.

meme commented

NativePointer has its field publicized, so you can transmute it to an extern "C" function pointer and then call it like a Rust function: e.g. let f = std::mem::transmute::<*mut _, extern "C" fn(*mut u8, usize)>(ptr.0);. An example in the docs would be appreciated.

Wow thanks for the first response. I'm not sure which is it then. The first answer seems more right when I look at the code

s1341 commented

It depends if the function you are targeting is exported and if you link directly with your target. If so then you can just declare the function as extern and call it.

If not, you can use the trick @meme suggested.

okay, awesome. I'll try it out soon and when it works I'll add an example as PR ;)

s1341 commented

@aviramha why did you reopen?

#![feature(c_variadic)]
use frida_gum::{
    interceptor::{Interceptor},
    Gum,
    Module, NativePointer
};
use std::ptr::null;
use ctor::ctor;
use libc::{c_void, c_int, c_char};


unsafe extern "C" fn open_detour(
    name: *const c_char, 
    flags: c_int,
) -> c_int {
    println!("here");
    let res = libc::open(name, flags);
    println!("here2");
    res
}

#[ctor]
fn init_aaaa() {
    let gum = unsafe { Gum::obtain() };
    let mut interceptor = Interceptor::obtain(&gum);
    let open = Module::find_export_by_name(None, "open").unwrap();
    match interceptor.replace(open, NativePointer(open_detour as *mut c_void), NativePointer(0 as *mut c_void)) {
        Ok(_) => println!("Success"),
        Err(e) => println!("Error: {}", e)
    }
    println!("INIT");
}

I get a segfault while running this. Loading the dylib with DYLD_INSERT_LIBRARIES on M1 Pro

s1341 commented

your Interceptor is not living long enough, it's being dropped at the end of init_aaa. You need to make it global.

@s1341 I was worried that might happen but I didn't see a Drop impl for it?

meme commented

I believe it is because you are declaring Gum at a local scope, it is being dropped after Interceptor::replace which calls gum_deinit_embedded. See the examples, but you need to use e.g. lazy_static!

I believe it is because you are declaring Gum at a local scope, it is being dropped after Interceptor::replace which calls gum_deinit_embedded. See the examples, but you need to use e.g. lazy_static!

Okay, cool. So Interceptor can be local and dropped and that's okay, right?

meme commented

There is no impl Drop for Interceptor, only Gum (in this example), so when the Interceptor goes out of scope, the replacement is still active.

Added an example #39