Skip to content

Commit

Permalink
Refactor to avoid the NOP trick
Browse files Browse the repository at this point in the history
We don't actually need to keep the thread suspended until we have
created the dispatch source.

Co-authored-by: Håvard Sørbø <[email protected]>
  • Loading branch information
oleavr and hsorbo committed Jun 4, 2024
1 parent 9bfeffe commit 80c141f
Showing 1 changed file with 58 additions and 35 deletions.
93 changes: 58 additions & 35 deletions src/darwin/frida-helper-backend-glue.m
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,8 @@ static void frida_agent_context_emit_mach_stub_code (FridaAgentContext * self, g
static void frida_agent_context_emit_pthread_stub_code (FridaAgentContext * self, guint8 * code, GumDarwinModuleResolver * resolver,
GumDarwinMapper * mapper);

static gboolean frida_convert_thread_state_for_task (mach_port_t task, thread_state_flavor_t flavor, gconstpointer in_state,
mach_msg_type_number_t in_state_count, gpointer out_state, mach_msg_type_number_t * out_state_count, GError ** error);
static mach_port_t frida_obtain_thread_port_for_thread_id (mach_port_t task, uint64_t thread_id);
static kern_return_t frida_get_thread_state (mach_port_t thread, thread_state_flavor_t flavor, gpointer state,
mach_msg_type_number_t * count);
Expand Down Expand Up @@ -2583,30 +2585,24 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier
frida_inject_instance_start_thread (FridaInjectInstance * self, GError ** error)
{
gboolean success = FALSE;
thread_state_t thread_state;
mach_msg_type_number_t thread_state_count;
kern_return_t kr;
const gchar * failed_operation;
FridaHelperContext * ctx = self->backend->context;
dispatch_source_t source;

thread_act_array_t threads;
mach_msg_type_number_t thread_count;
kr = task_threads(self->task, &threads, &thread_count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "task_threads");

thread_state_t remote_state;
mach_msg_type_number_t count = self->thread_state_count;
remote_state = g_alloca (count * sizeof (integer_t));
thread_state = g_alloca (self->thread_state_count * sizeof (natural_t));
thread_state_count = self->thread_state_count;

kr = frida_convert_thread_state (*threads, FRIDA_CONVERT_THREAD_STATE_OUT, self->thread_state_flavor, self->thread_state_data, self->thread_state_count, remote_state, &count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_convert_thread_state");

for (int i = 0; i < thread_count; ++i) {
mach_port_deallocate(mach_task_self(), threads[i]);
if (!frida_convert_thread_state_for_task (self->task, self->thread_state_flavor, self->thread_state_data, self->thread_state_count,
thread_state, &thread_state_count, error))
{
return FALSE;
}
vm_deallocate(mach_task_self(), (vm_address_t)threads, sizeof(*threads) * thread_count);

kr = thread_create_running(self->task, self->thread_state_flavor, remote_state, self->thread_state_count, &self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_create_running");
kr = thread_create_running (self->task, self->thread_state_flavor, thread_state, thread_state_count, &self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_create");

source = dispatch_source_create (DISPATCH_SOURCE_TYPE_MACH_SEND, self->thread, DISPATCH_MACH_SEND_DEAD, ctx->dispatch_queue);
self->thread_monitor_source = source;
Expand All @@ -2615,22 +2611,6 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier
dispatch_source_set_event_handler_f (source, frida_inject_instance_on_mach_thread_dead);
dispatch_resume (source);

kr = thread_suspend(self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_suspend");

guint page_size = getpagesize();

uint32_t nop = 0xd503201f;
kr = mach_vm_protect (self->task, self->payload_address, page_size, FALSE, VM_PROT_READ | VM_PROT_WRITE);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "mach_vm_protect");
kr = mach_vm_write (self->task, self->payload_address, (vm_offset_t) &nop, sizeof (nop));
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "mach_vm_write(nop)");
kr = mach_vm_protect (self->task, self->payload_address, page_size, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "mach_vm_protect");

kr = thread_resume(self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_resume");

success = TRUE;

goto beach;
Expand Down Expand Up @@ -4882,9 +4862,6 @@ static void frida_agent_context_emit_arm64_pthread_stub_code (FridaAgentContext

ctx.aw.ptrauth_support = resolver->ptrauth_support;

gum_arm64_writer_put_label(&ctx.aw, "loop");
gum_arm64_writer_put_b_label(&ctx.aw, "loop");

gum_arm64_writer_put_push_reg_reg (&ctx.aw, ARM64_REG_FP, ARM64_REG_LR);
gum_arm64_writer_put_mov_reg_reg (&ctx.aw, ARM64_REG_FP, ARM64_REG_SP);
gum_arm64_writer_put_push_reg_reg (&ctx.aw, ARM64_REG_X19, ARM64_REG_X20);
Expand Down Expand Up @@ -5102,6 +5079,52 @@ static void frida_agent_context_emit_arm64_pthread_stub_code (FridaAgentContext

#endif

static gboolean
frida_convert_thread_state_for_task (mach_port_t task, thread_state_flavor_t flavor, gconstpointer in_state,
mach_msg_type_number_t in_state_count, gpointer out_state, mach_msg_type_number_t * out_state_count,
GError ** error)
{
gboolean success = FALSE;
kern_return_t kr;
const gchar * failed_operation;
thread_act_array_t threads = NULL;
mach_msg_type_number_t thread_count = 0;

kr = task_threads (task, &threads, &thread_count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "task_threads");

kr = frida_convert_thread_state (threads[0], FRIDA_CONVERT_THREAD_STATE_OUT, flavor, in_state, in_state_count,
out_state, out_state_count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_convert_thread_state");

success = TRUE;

goto beach;

mach_failure:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error while converting thread state for task (%s returned '%s')",
failed_operation, mach_error_string (kr));
goto beach;
}
beach:
{
mach_msg_type_number_t i;

if (threads != NULL)
{
for (i = 0; i != thread_count; i++)
mach_port_deallocate (mach_task_self (), threads[i]);
vm_deallocate (mach_task_self (), (vm_address_t) threads, thread_count * sizeof (thread_t));
}

return success;
}
}

static mach_port_t
frida_obtain_thread_port_for_thread_id (mach_port_t task, uint64_t thread_id)
{
Expand Down

0 comments on commit 80c141f

Please sign in to comment.