Class

GumInterceptor

Description [src]

final class Gum.Interceptor : GObject.Object
{
  /* No available fields */
}

Intercepts execution through inline hooking.

Three complementary mechanisms are offered:

  • Attaching a GumInvocationListener to a function, to be notified right before it is entered and right after it returns, while leaving the original function in place. This is the classic enter/leave hook.
  • Probing a single point in the code with a listener that implements only on_enter, typically one from gum_make_probe_listener(). Because the target is an arbitrary address rather than a function entry, a probe can be placed in the middle of a function to observe execution reaching a specific instruction. A call listener given a NULL on_leave is not equivalent: it still traps the return and counts toward gum_invocation_context_get_depth().
  • Replacing a function outright with your own implementation. Your replacement can still reach the original by calling the function’s own address: the interceptor routes such a call to the original instead of recursing back into the replacement. (The lighter gum_interceptor_replace_fast() instead hands you a dedicated pointer for this.)

A batch of changes can be grouped into a transaction so that they are activated as a unit, which is both faster and atomic from the target’s point of view; see gum_interceptor_begin_transaction().

Attaching a listener

static void on_enter (GumInvocationContext * ic, gpointer user_data);
static void on_leave (GumInvocationContext * ic, gpointer user_data);

void
instrument (void)
{
  g_autoptr(GumInterceptor) interceptor = gum_interceptor_obtain ();
  GumInvocationListener * listener =
      gum_make_call_listener (on_enter, on_leave, NULL, NULL);

  gum_interceptor_begin_transaction (interceptor);
  gum_interceptor_attach (interceptor,
      GSIZE_TO_POINTER (gum_module_find_global_export_by_name ("open")),
      listener, NULL);
  gum_interceptor_end_transaction (interceptor);
}

Replacing a function

static int (* libc_open) (const char * path, int oflag, ...);

static int
replacement_open (const char * path, int oflag, ...)
{
  g_printerr ("open(\"%s\")\n", path);
  return libc_open (path, oflag); // reaches the original
}

void
instrument (void)
{
  g_autoptr(GumInterceptor) interceptor = gum_interceptor_obtain ();

  libc_open = GSIZE_TO_POINTER (
      gum_module_find_global_export_by_name ("open"));

  gum_interceptor_replace (interceptor, libc_open, replacement_open,
      NULL, NULL);
}

Ahead-of-time instrumentation

Inline hooking normally rewrites code at runtime, but some platforms forbid that: where code signing is strictly enforced (e.g. iOS), executable pages cannot be patched on the fly. For these, trampolines can be grafted into a Mach-O binary ahead of time with GumDarwinGrafter — exposed as the gum-graft command-line tool — which reserves a trampoline at each code offset you intend to hook.

At runtime gum_interceptor_attach() and gum_interceptor_replace() then claim the matching grafted trampoline instead of patching code, so interception works without writable code. If a target has no grafted trampoline while code signing requires one, the attach or replace fails with GUM_ATTACH_POLICY_VIOLATION / GUM_REPLACE_POLICY_VIOLATION.

Ancestors

Functions

gum_interceptor_get_current_invocation

Returns the current invocation context.

gum_interceptor_get_current_stack

Returns the invocation stack for the current thread.

gum_interceptor_get_live_replacement_invocation

Returns the invocation context for the given replacement function, if currently active.

gum_interceptor_obtain

Obtains the interceptor singleton.

gum_interceptor_restore

Unwinds the calling thread’s invocation stack back to the depth recorded in state, releasing any entries skipped by a non-local exit.

gum_interceptor_save

Records the calling thread’s current invocation depth into state, to be restored later with gum_interceptor_restore(). Use this around a non-local exit such as a longjmp() that would otherwise skip the bookkeeping the interceptor does as intercepted calls return.

Instance methods

gum_interceptor_attach

Attaches listener so that it is notified right before target is entered and right after it returns. The same listener may be attached to any number of addresses, and multiple listeners may be attached to the same address. The original code is left in place.

gum_interceptor_begin_transaction

Begins a transaction, deferring activation of any attach, replace and revert operations until the matching gum_interceptor_end_transaction(). Batching changes this way is faster and lets a set of modifications be applied as a unit. Transactions nest; only ending the outermost one applies the changes.

gum_interceptor_detach

Detaches listener from every function it is currently attached to, undoing any gum_interceptor_attach() calls made with it. Functions left without any listeners or replacement are restored to their original state.

gum_interceptor_end_transaction

Ends a transaction started with gum_interceptor_begin_transaction(). Ending the outermost transaction activates all changes made since it began.

gum_interceptor_flush

Completes any teardown still pending from earlier detaches and reverts. When a listener is detached or a replacement reverted the hook stops firing immediately, but the memory backing its instrumentation can only be released once no thread is left executing inside it, so that step is deferred. Call this to force a pass and learn whether it finished. Does nothing while a transaction is open.

gum_interceptor_flush_function

Like gum_interceptor_flush(), but reports specifically whether the instrumentation for function_address is no longer in use, so its memory can be reclaimed.

gum_interceptor_flush_listener

Like gum_interceptor_flush(), but reports specifically whether listener is no longer referenced by any in-flight invocation, so it is safe to release.

gum_interceptor_ignore_current_thread

Temporarily stops the calling thread’s calls into hooked code from triggering listeners. The typical use is to bracket work done internally by an injected payload — for example its own worker threads — so that a user’s hooks observe only the target process’s activity, not the payload’s own calls into the functions it has hooked.

gum_interceptor_ignore_other_threads

Restricts interception to the calling thread: invocations on all other threads stop triggering listeners until gum_interceptor_unignore_other_threads() is called.

gum_interceptor_is_locked

Checks whether the interceptor lock is currently held, e.g. to decide whether it is safe to make changes from a signal handler.

gum_interceptor_maybe_unignore_current_thread

Undoes one gum_interceptor_ignore_current_thread(), but only if the calling thread is currently being ignored.

gum_interceptor_replace

Replaces function_address with replacement_function, so that any call to it ends up in the replacement instead. The replacement can still reach the original by calling function_address itself — the interceptor routes that call to the original rather than recursing — or through original_function if a pointer is more convenient.

gum_interceptor_replace_fast

Like gum_interceptor_replace(), but trades flexibility for speed by patching function_address to branch straight to replacement_function with no trampoline in between. A trampoline is only involved if you ask for original_function, which you must use to reach the original — unlike gum_interceptor_replace(), calling function_address again would just re-enter the replacement. A target replaced this way cannot also be attached to; use gum_interceptor_replace() if you need that.

gum_interceptor_revert

Reverts a previous gum_interceptor_replace() of target, restoring the original function. Has no effect if the function was not replaced.

gum_interceptor_set_default_options

Sets the instrumentation options applied when a subsequent attach or replace is given no options of its own.

gum_interceptor_unignore_current_thread

Undoes one gum_interceptor_ignore_current_thread() on the calling thread.

gum_interceptor_unignore_other_threads

Lifts a previous gum_interceptor_ignore_other_threads(), resuming interception on all threads. Must be called from the same thread that ignored the others.

gum_interceptor_with_lock_held

Calls func while holding the interceptor lock.

Methods inherited from GObject (43)

Please see GObject for a full list of methods.

Signals

Signals inherited from GObject (1)
GObject::notify

The notify signal is emitted on an object when one of its properties has its value set through g_object_set_property(), g_object_set(), et al.

Class structure

struct GumInterceptorClass {
  GObjectClass parent_class;
  
}

No description available.

Class members
parent_class: GObjectClass

No description available.