funchook icon indicating copy to clipboard operation
funchook copied to clipboard

One hook for multiple targets - feature request

Open marcin-szmagara opened this issue 3 years ago • 2 comments

Given a list of function addresses at runtime I need to log whenever any of them is called. I believe the best way to do this would be to hook the functions with a logger hook. After some discussion it looks like this ideally would be enabled by a hooking library.

However, with current API of this library, it is impossible to have one hook function for multiple targets, as the hook function does not have the information about the hooked function (in particular its address).

I would like to propose a feature, that would make it possible not only to write this:

void hook(int arg1, int arg2)
{
  ...
  original_function(arg1, arg2);
}

but also this:

void multihook(fun_ptr_t ptr, int arg1, int arg2)
{
  ...
  ptr(arg1, arg2)
}

The address of the original function could be passed in any other way, not necessarily as the first argument.

Could this be implemented as part of this library? If so, what would be the best way to approach it?

marcin-szmagara avatar Sep 23 '22 10:09 marcin-szmagara

Adding a new argument is impossible without knowledge about number of original function's arguments and their types (integer or floating point number). Instead of it, thread-local storage is available for that purpose.

Funchook hooks functions by replacing first few bytes at the beginning of the original functions. (See http://jbremer.org/x86-api-hooking-demystified/#ah-basic) On x86_64, the code size of jump instruction is 5 when the distance from source to destination is between 2 gigabytes. Otherwise it is 14 to jump to any address.

Funchook uses 5-byte code when the distance from the original function to the hook function is less than 2 gigabytes. Otherwise, it allocates memory near the original function and uses 5-byte code to jump from the original to the newly allocated memory and 14-byte code to jump from the memory to the hook function. The code in the memory is called as "transit" in funchook.

I think that the feature can be implemented.

  1. Use "transit" even when the distance is less than 2 gigabytes.
  2. Change "transit" as follows.
    1. Push registers (RDI, RSI, RDX, RCX, R8, R9, R10, AL on linux x86_64) on the stack.
    2. Call the following function with the address of funchook_entry_t, which is got by lea number(%rip), %rdi.
      // linux
      static pthread_key_t funchook_entry_tls_key; // This is initialized somewhere.
      void set_trampoline_function_address(void *addr) {
         pthread_setspecific(funchook_entry_tls_key, addr);
      }
      
    3. Pop registers from the stack.
    4. Jump to a hook function.
  3. Add the following function to get a trampoline function.
    void* funchook_get_trampoline() {
       funchook_entry_t *entry = (funchook_entry_t *)pthread_getspecific(funchook_entry_tls_key);
       return entry != NULL ? (void*)entry->trampoline ? NULL;
    }
    

kubo avatar Sep 24 '22 06:09 kubo

Many thanks, works great for me. I think this can be closed with 2.0.0 release.

marcin-szmagara avatar Jan 01 '23 21:01 marcin-szmagara