Skip to content

Commit

Permalink
Refactor some more
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Feb 23, 2024
1 parent 86b7470 commit ae15188
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 255 deletions.
1 change: 1 addition & 0 deletions gum/backend-arm/gumstalker-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,7 @@ _gum_stalker_modify_to_run_on_thread (GumStalker * self,
GumAddress cpu_context_copy, infect_body;

ctx = gum_stalker_create_exec_ctx (self, thread_id, NULL, NULL);

if ((cpu_context->cpsr & GUM_PSR_T_BIT) == 0)
pc = cpu_context->pc;
else
Expand Down
179 changes: 69 additions & 110 deletions gum/backend-arm64/gumstalker-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "gummemory.h"
#include "gummetalhash.h"
#include "gumspinlock.h"
#include "gumstalker-priv.h"
#ifdef HAVE_LINUX
# include "gum-init.h"
# include "guminterceptor.h"
Expand Down Expand Up @@ -88,7 +89,6 @@ typedef struct _GumBackpatchCall GumBackpatchCall;
typedef struct _GumBackpatchJmp GumBackpatchJmp;
typedef struct _GumBackpatchInlineCache GumBackpatchInlineCache;
typedef struct _GumBackpatchExcludedCall GumBackpatchExcludedCall;
typedef struct _GumStalkerRunOnThreadCtx GumStalkerRunOnThreadCtx;

#ifdef HAVE_LINUX
typedef struct _Unwind_Exception _Unwind_Exception;
Expand Down Expand Up @@ -482,13 +482,6 @@ struct _GumBackpatch
};
};

struct _GumStalkerRunOnThreadCtx
{
GumStalker * stalker;
GumStalkerRunOnThreadFunc func;
gpointer user_data;
};

#ifdef HAVE_LINUX

extern _Unwind_Reason_Code __gxx_personality_v0 (int version,
Expand Down Expand Up @@ -771,9 +764,6 @@ static gpointer gum_find_thread_exit_implementation (void);

static gboolean gum_is_bl_imm (guint32 insn) G_GNUC_UNUSED;

static void gum_stalker_do_run_on_thread (GumThreadId thread_id,
GumCpuContext * cpu_context, gpointer user_data);

G_DEFINE_TYPE (GumStalker, gum_stalker, G_TYPE_OBJECT)

static GPrivate gum_stalker_exec_ctx_private;
Expand Down Expand Up @@ -1939,6 +1929,74 @@ gum_call_probe_unref (GumCallProbe * probe)
}
}

void
_gum_stalker_modify_to_run_on_thread (GumStalker * self,
GumThreadId thread_id,
GumCpuContext * cpu_context,
GumStalkerRunOnThreadFunc func,
gpointer data)
{
GumExecCtx * ctx;
GumAddress pc;
GumArm64Writer * cw;
GumAddress cpu_context_copy;

ctx = gum_stalker_create_exec_ctx (self, thread_id, NULL, NULL);

pc = gum_strip_code_address (cpu_context->pc);

gum_spinlock_acquire (&ctx->code_lock);

gum_stalker_thaw (self, ctx->thunks, self->thunks_size);
cw = &ctx->code_writer;
gum_arm64_writer_reset (cw, ctx->infect_thunk);

cpu_context_copy = GUM_ADDRESS (gum_arm64_writer_cur (cw));
gum_arm64_writer_put_bytes (cw, (guint8 *) cpu_context,
sizeof (GumCpuContext));

ctx->infect_body = GUM_ADDRESS (gum_arm64_writer_cur (cw));

#ifdef HAVE_PTRAUTH
ctx->infect_body = GPOINTER_TO_SIZE (ptrauth_sign_unauthenticated (
GSIZE_TO_POINTER (ctx->infect_body),
ptrauth_key_process_independent_code,
ptrauth_string_discriminator ("pc")));
#endif
gum_exec_ctx_write_prolog (ctx, GUM_PROLOG_MINIMAL, cw);

gum_arm64_writer_put_call_address_with_arguments (cw,
GUM_ADDRESS (func), 2,
GUM_ARG_ADDRESS, cpu_context_copy,
GUM_ARG_ADDRESS, GUM_ADDRESS (data));

gum_arm64_writer_put_call_address_with_arguments (cw,
GUM_ADDRESS (gum_exec_ctx_unfollow), 2,
GUM_ARG_ADDRESS, GUM_ADDRESS (ctx),
GUM_ARG_ADDRESS, pc);

gum_exec_ctx_write_epilog (ctx, GUM_PROLOG_MINIMAL, cw);

/*
* Here we spoil x17 since this is a necessity of the AARCH64 architecture
* when performing long branches. However, the documentation states...
*
* "Registers r16 (IP0) and r17 (IP1) may be used by a linker as a scratch
* register between a routine and any subroutine it calls."
*
* This same approach is used elsewhere in Stalker for arm64.
*/
gum_arm64_writer_put_ldr_reg_address (cw, ARM64_REG_X17, pc);
gum_arm64_writer_put_br_reg_no_auth (cw, ARM64_REG_X17);

gum_arm64_writer_flush (cw);
gum_stalker_freeze (self, cw->base, gum_arm64_writer_offset (cw));

gum_spinlock_release (&ctx->code_lock);

cpu_context->pc = ctx->infect_body;
}

static GumExecCtx *
gum_stalker_create_exec_ctx (GumStalker * self,
GumThreadId thread_id,
Expand Down Expand Up @@ -5906,102 +5964,3 @@ gum_is_bl_imm (guint32 insn)
}

#endif

gboolean
gum_stalker_run_on_thread (GumStalker * self,
GumThreadId thread_id,
GumStalkerRunOnThreadFunc func,
gpointer user_data)
{
GumStalkerRunOnThreadCtx ctx;

if (gum_process_get_current_thread_id () == thread_id)
{
func (NULL, user_data);
return TRUE;
}
else
{
ctx.stalker = self;
ctx.func = func;
ctx.user_data = user_data;
return gum_process_modify_thread (thread_id, gum_stalker_do_run_on_thread,
&ctx, GUM_MODIFY_THREAD_FLAGS_NONE);
}
}

static void
gum_stalker_do_run_on_thread (GumThreadId thread_id,
GumCpuContext * cpu_context,
gpointer user_data)
{
GumStalkerRunOnThreadCtx * run_ctx = (GumStalkerRunOnThreadCtx *) user_data;
GumStalker * self = run_ctx->stalker;
GumExecCtx * ctx;
guint8 * pc;
GumArm64Writer * cw;
GumAddress cpu_ctx;

if (gum_process_get_current_thread_id () == thread_id)
{
run_ctx->func (cpu_context, run_ctx->user_data);
}
else
{
ctx = gum_stalker_create_exec_ctx (self, thread_id, NULL, NULL);

pc = GSIZE_TO_POINTER (gum_strip_code_address (cpu_context->pc));

gum_spinlock_acquire (&ctx->code_lock);

gum_stalker_thaw (self, ctx->thunks, self->thunks_size);
cw = &ctx->code_writer;
gum_arm64_writer_reset (cw, ctx->infect_thunk);

/* Copy the cpu context for the target thread. */
cpu_ctx = GUM_ADDRESS (gum_arm64_writer_cur (cw));
gum_arm64_writer_put_bytes (cw, (gpointer) cpu_context,
sizeof (GumCpuContext));

ctx->infect_body = GUM_ADDRESS (gum_arm64_writer_cur (cw));

#ifdef HAVE_PTRAUTH
ctx->infect_body = GPOINTER_TO_SIZE (ptrauth_sign_unauthenticated (
GSIZE_TO_POINTER (ctx->infect_body),
ptrauth_key_process_independent_code,
ptrauth_string_discriminator ("pc")));
#endif
gum_exec_ctx_write_prolog (ctx, GUM_PROLOG_MINIMAL, cw);

gum_arm64_writer_put_call_address_with_arguments (cw,
GUM_ADDRESS (run_ctx->func), 2,
GUM_ARG_ADDRESS, GUM_ADDRESS (cpu_ctx),
GUM_ARG_ADDRESS, GUM_ADDRESS (run_ctx->user_data));

gum_arm64_writer_put_call_address_with_arguments (cw,
GUM_ADDRESS (gum_exec_ctx_unfollow), 2,
GUM_ARG_ADDRESS, GUM_ADDRESS (ctx),
GUM_ARG_ADDRESS, GUM_ADDRESS (pc));

gum_exec_ctx_write_epilog (ctx, GUM_PROLOG_MINIMAL, cw);

/*
* Here we spoil x17 since this is a necessity of the AARCH64 architecture
* when performing long branches. However, the documentation states...
*
* "Registers r16 (IP0) and r17 (IP1) may be used by a linker as a scratch
* register between a routine and any subroutine it calls."
*
* This same approach is used elsewhere in Stalker for aarch64.
*/
gum_arm64_writer_put_ldr_reg_address (cw, ARM64_REG_X17, GUM_ADDRESS (pc));
gum_arm64_writer_put_br_reg_no_auth (cw, ARM64_REG_X17);

gum_arm64_writer_flush (cw);
gum_stalker_freeze (self, cw->base, gum_arm64_writer_offset (cw));

gum_spinlock_release (&ctx->code_lock);

cpu_context->pc = ctx->infect_body;
}
}
36 changes: 17 additions & 19 deletions gum/gumstalker.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ static void gum_callback_stalker_transformer_transform_block (
static void gum_stalker_observer_default_init (
GumStalkerObserverInterface * iface);

static void gum_stalker_do_run_on_thread_sync (
const GumCpuContext * cpu_context, gpointer user_data);

G_DEFINE_INTERFACE (GumStalkerTransformer, gum_stalker_transformer,
G_TYPE_OBJECT)

Expand Down Expand Up @@ -209,13 +206,12 @@ gum_stalker_run_on_thread (GumStalker * self,
gpointer data,
GDestroyNotify data_destroy)
{
gboolean done = FALSE;
gboolean accepted = TRUE;
gboolean finished = TRUE;

if (gum_process_get_current_thread_id () == thread_id)
if (thread_id == gum_process_get_current_thread_id ())
{
func (NULL, data);

done = TRUE;
}
else
{
Expand All @@ -227,16 +223,18 @@ gum_stalker_run_on_thread (GumStalker * self,
rc->data = data;
rc->data_destroy = data_destroy;

if (!gum_process_modify_thread (thread_id, gum_modify_to_run_on_thread, rc,
GUM_MODIFY_THREAD_FLAGS_NONE))
{
accepted = gum_process_modify_thread (thread_id,
gum_modify_to_run_on_thread, rc, GUM_MODIFY_THREAD_FLAGS_NONE);
if (accepted)
finished = FALSE;
else
g_slice_free (GumRunOnThreadCtx, rc);
done = TRUE;
}
}

if (done && data_destroy != NULL)
if (finished && data_destroy != NULL)
data_destroy (data);

return accepted;
}

static void
Expand Down Expand Up @@ -269,13 +267,11 @@ gum_stalker_run_on_thread_sync (GumStalker * self,
GumStalkerRunOnThreadFunc func,
gpointer data)
{
gboolean success = FALSE;
gboolean success = TRUE;

if (gum_process_get_current_thread_id () == thread_id)
if (thread_id == gum_process_get_current_thread_id ())
{
func (NULL, data);

success = TRUE;
}
else
{
Expand All @@ -294,8 +290,10 @@ gum_stalker_run_on_thread_sync (GumStalker * self,
{
while (!rc.done)
g_cond_wait (&rc.cond, &rc.mutex);

success = TRUE;
}
else
{
success = FALSE;
}

g_mutex_unlock (&rc.mutex);
Expand Down
Loading

0 comments on commit ae15188

Please sign in to comment.