From 33d8d0a9c93c7c972de03b90f9e6b3ee0dba5b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Tue, 19 Sep 2023 15:39:36 +0200 Subject: [PATCH] [WIP] Wire up some more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Håvard Sørbø --- gum/gumswiftapiresolver.c | 268 ++++++++++++++++++++++---------------- 1 file changed, 155 insertions(+), 113 deletions(-) diff --git a/gum/gumswiftapiresolver.c b/gum/gumswiftapiresolver.c index 813b218f6..55e8ec88a 100644 --- a/gum/gumswiftapiresolver.c +++ b/gum/gumswiftapiresolver.c @@ -283,6 +283,8 @@ static void gum_module_metadata_collect_method (GumModuleMetadata * self, const GumTypeContextDescriptor * holder); static gboolean gum_module_metadata_collect_export ( const GumExportDetails * details, gpointer user_data); +static void gum_module_metadata_maybe_ingest_thunk (GumModuleMetadata * self, + const gchar * name, GumAddress address); static gchar * gum_extract_class_name (const gchar * full_name); static const gchar * gum_find_character_backwards (const gchar * starting_point, char needle, const gchar * start); @@ -616,22 +618,10 @@ gum_module_metadata_collect_class (GumModuleMetadata * self, methods = GUM_ALIGN ((const GumMethodDescriptor *) (vth + 1), GumMethodDescriptor); -#if 0 - g_printerr ("\n=== %s\n", - (const char *) gum_resolve_relative_direct_ptr (&type->name)); -#endif - for (i = 0; i != vth->vtable_size; i++) { const GumMethodDescriptor * method = &methods[i]; -#if 0 - g_printerr ("\tvtable[%u]: flags=0x%08x impl=%p\n", - i, - method->flags, - gum_resolve_relative_direct_ptr (&method->impl)); -#endif - gum_module_metadata_collect_method (self, method, i, type); } @@ -726,7 +716,6 @@ gum_module_metadata_collect_method (GumModuleMetadata * self, break; } - //g_printerr ("\t\tTODO\n"); break; } } @@ -741,13 +730,7 @@ gum_module_metadata_collect_method (GumModuleMetadata * self, if (vtable != NULL) { if (vtable_index < vtable->len) - { func.name = g_strdup (g_ptr_array_index (vtable, vtable_index)); -#if 0 - if (func.name != NULL) - g_printerr ("\t\t\n", func.name); -#endif - } } } @@ -779,136 +762,195 @@ gum_module_metadata_collect_export (const GumExportDetails * details, GumFunctionMetadata func; if (details->type != GUM_EXPORT_FUNCTION) - return TRUE; + goto skip; len = self->resolver->demangle (details->name, name, sizeof (name)); if (len == 0) - return TRUE; + goto skip; func.name = g_strdup (name); func.address = details->address; g_array_append_val (self->functions, func); - if (g_str_has_prefix (func.name, "dispatch thunk of ")) - { - csh capstone; - const uint8_t * code; - size_t size; - uint64_t address; - cs_insn * insn; - gint vtable_index; - gboolean end_of_block; + gum_module_metadata_maybe_ingest_thunk (self, func.name, func.address); + +skip: + return TRUE; +} + +static void +gum_module_metadata_maybe_ingest_thunk (GumModuleMetadata * self, + const gchar * name, + GumAddress address) +{ + csh capstone; + const uint8_t * code; + size_t size; + cs_insn * insn; + gint vtable_index, vtable_offsets[18]; + gboolean end_of_thunk; + guint i; - gum_cs_arch_register_native (); - cs_open (GUM_DEFAULT_CS_ARCH, GUM_DEFAULT_CS_MODE, &capstone); - cs_option (capstone, CS_OPT_DETAIL, CS_OPT_ON); + if (!g_str_has_prefix (name, "dispatch thunk of ")) + return; - code = GSIZE_TO_POINTER (details->address); - size = 256; - address = details->address; + gum_cs_arch_register_native (); + cs_open (GUM_DEFAULT_CS_ARCH, GUM_DEFAULT_CS_MODE, &capstone); + cs_option (capstone, CS_OPT_DETAIL, CS_OPT_ON); - insn = cs_malloc (capstone); + code = GSIZE_TO_POINTER (address); + size = 256; - gboolean should_log = FALSE; //strstr (func.name, "CoreDevice.RemoteDevice") != NULL; + insn = cs_malloc (capstone); - if (should_log) - { - g_printerr ("\n=== %s (%s+0x%" G_GINT64_MODIFIER "x)\n", - func.name + strlen ("dispatch thunk of "), - self->name, - details->address - self->base_address); - } + vtable_index = -1; + for (i = 0; i != G_N_ELEMENTS (vtable_offsets); i++) + vtable_offsets[i] = -1; + end_of_thunk = FALSE; - vtable_index = -1; - end_of_block = FALSE; - while (vtable_index == -1 && !end_of_block && - cs_disasm_iter (capstone, &code, &size, &address, insn)) - { - /* g_printerr ("%s %s\n", insn->mnemonic, insn->op_str); */ + while (vtable_index == -1 && !end_of_thunk && + cs_disasm_iter (capstone, &code, &size, &address, insn)) + { + const cs_arm64_op * ops = insn->detail->arm64.operands; + +#define GUM_REG_IS_TRACKED(reg) (reg >= ARM64_REG_X0 && reg <= ARM64_REG_X17) +#define GUM_REG_INDEX(reg) (reg - ARM64_REG_X0) - switch (insn->id) + switch (insn->id) + { + case ARM64_INS_LDR: { - case ARM64_INS_LDR: - { - arm64_op_mem * src = &insn->detail->arm64.operands[1].mem; + arm64_reg dst = ops[0].reg; + const arm64_op_mem * src = &ops[1].mem; - /* - * ldr x3, [x16, #0xd0]! - * ... - * braa x3, x16 - */ - if (src->base == ARM64_REG_X16) - vtable_index = src->disp / sizeof (gpointer); + if (GUM_REG_IS_TRACKED (dst)) + { + gint offset; - break; + if (!(src->base == ARM64_REG_X20 && src->disp == 0)) + { + /* + * ldr x3, [x16, #0xd0]! + * ... + * braa x3, x16 + */ + vtable_offsets[GUM_REG_INDEX (dst)] = src->disp; + } } - case ARM64_INS_MOV: + + break; + } + case ARM64_INS_MOV: + { + arm64_reg dst = ops[0].reg; + const cs_arm64_op * src = &ops[1]; + + /* + * mov x17, #0x3b0 + * add x16, x16, x17 + * ldr x7, [x16] + * ... + * braa x7, x16 + */ + if (src->type == ARM64_OP_IMM && GUM_REG_IS_TRACKED (dst)) + vtable_offsets[GUM_REG_INDEX (dst)] = src->imm; + + break; + } + case ARM64_INS_ADD: + { + arm64_reg dst = ops[0].reg; + arm64_reg left = ops[1].reg; + const cs_arm64_op * right = &ops[2]; + gint offset; + + if (left == dst) { - cs_arm64_op * dst = &insn->detail->arm64.operands[0]; - cs_arm64_op * src = &insn->detail->arm64.operands[1]; - - /* - * mov x17, #0x3b0 - * add x16, x16, x17 - * ldr x7, [x16] - * ... - * braa x7, x16 - */ - if (dst->reg == ARM64_REG_X17 && src->type == ARM64_OP_IMM) + if (right->type == ARM64_OP_REG && + GUM_REG_IS_TRACKED (right->reg) && + (offset = vtable_offsets[GUM_REG_INDEX (right->reg)]) != -1) { - vtable_index = src->imm / sizeof (gpointer); + vtable_index = offset / sizeof (gpointer); } - break; + if (right->type == ARM64_OP_IMM) + { + vtable_index = right->imm / sizeof (gpointer); + } } - case ARM64_INS_BR: - case ARM64_INS_BRAA: - case ARM64_INS_BRAAZ: - case ARM64_INS_RET: - case ARM64_INS_RETAA: - case ARM64_INS_RETAB: - end_of_block = TRUE; - break; + + break; } - } + case ARM64_INS_BR: + case ARM64_INS_BRAA: + case ARM64_INS_BRAAZ: + case ARM64_INS_BRAB: + case ARM64_INS_BRABZ: + case ARM64_INS_BLR: + case ARM64_INS_BLRAA: + case ARM64_INS_BLRAAZ: + case ARM64_INS_BLRAB: + case ARM64_INS_BLRABZ: + { + arm64_reg target = ops[0].reg; + gint offset; - cs_free (insn, 1); + switch (insn->id) + { + case ARM64_INS_BR: + case ARM64_INS_BRAA: + case ARM64_INS_BRAAZ: + case ARM64_INS_BRAB: + case ARM64_INS_BRABZ: + end_of_thunk = TRUE; + break; + default: + break; + } - cs_close (&capstone); + if (GUM_REG_IS_TRACKED (target) && + (offset = vtable_offsets[GUM_REG_INDEX (target)]) != -1) + { + vtable_index = offset / sizeof (gpointer); + } - if (vtable_index != -1) - { - const gchar * full_name; - gchar * class_name; - GPtrArray * vtable; + break; + } + case ARM64_INS_RET: + case ARM64_INS_RETAA: + case ARM64_INS_RETAB: + end_of_thunk = TRUE; + break; + } + } - full_name = func.name + strlen ("dispatch thunk of "); - class_name = gum_extract_class_name (full_name); + cs_free (insn, 1); - vtable = g_hash_table_lookup (self->vtables, class_name); - if (vtable == NULL) - { - vtable = g_ptr_array_new_full (64, g_free); - g_hash_table_insert (self->vtables, g_steal_pointer (&class_name), vtable); - } + cs_close (&capstone); - if (vtable_index >= vtable->len) - g_ptr_array_set_size (vtable, vtable_index + 1); - g_free (g_ptr_array_index (vtable, vtable_index)); - g_ptr_array_index (vtable, vtable_index) = g_strdup (full_name); + if (vtable_index != -1) + { + const gchar * full_name; + gchar * class_name; + GPtrArray * vtable; - //g_printerr (" => SUCCESS, class_name=\"%s\", vtable_index=%d\n", class_name, vtable_index); + full_name = name + strlen ("dispatch thunk of "); + class_name = gum_extract_class_name (full_name); - g_free (class_name); - } - else + vtable = g_hash_table_lookup (self->vtables, class_name); + if (vtable == NULL) { - if (should_log) - g_printerr (" => FAILURE, vtable_index not determined\n"); + vtable = g_ptr_array_new_full (64, g_free); + g_hash_table_insert (self->vtables, g_steal_pointer (&class_name), vtable); } - } - return TRUE; + if (vtable_index >= vtable->len) + g_ptr_array_set_size (vtable, vtable_index + 1); + g_free (g_ptr_array_index (vtable, vtable_index)); + g_ptr_array_index (vtable, vtable_index) = g_strdup (full_name); + + g_free (class_name); + } } static gchar *