From 38890d674c83aea8e3e167e6123660f7527b0166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Mon, 18 Sep 2023 13:59:08 +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 | 192 +++++++++++++++++++++++++++++++------- 1 file changed, 159 insertions(+), 33 deletions(-) diff --git a/gum/gumswiftapiresolver.c b/gum/gumswiftapiresolver.c index f41d364e9..813b218f6 100644 --- a/gum/gumswiftapiresolver.c +++ b/gum/gumswiftapiresolver.c @@ -45,6 +45,9 @@ #define GUM_GENERIC_DESCRIPTOR_FLAGS_HAS_TYPE_PACKS(flags) \ ((flags & GUM_GENERIC_DESCRIPTOR_HAS_TYPE_PACKS) != 0) +#define GUM_METHOD_DESCRIPTOR_IS_ASYNC(desc) \ + (((desc)->flags & GUM_METHOD_ASYNC) != 0) + #define GUM_ALIGN(ptr, type) \ GUM_ALIGN_POINTER (type *, ptr, G_ALIGNOF (type)) @@ -96,6 +99,7 @@ struct _GumModuleMetadata GumAddress base_address; GArray * functions; + GHashTable * vtables; GumSwiftApiResolver * resolver; }; @@ -239,6 +243,11 @@ struct _GumMethodDescriptor GumRelativeDirectPtr impl; }; +enum _GumMethodDescriptorFlags +{ + GUM_METHOD_ASYNC = (1 << 6), +}; + struct _GumOverrideTableHeader { guint32 num_entries; @@ -269,11 +278,14 @@ static gboolean gum_module_metadata_collect_section ( const GumSectionDetails * details, gpointer user_data); static void gum_module_metadata_collect_class (GumModuleMetadata * self, const GumTypeContextDescriptor * type); -static void gum_module_metadata_collect_function (GumModuleMetadata * self, - const gchar * label, gconstpointer impl, +static void gum_module_metadata_collect_method (GumModuleMetadata * self, + const GumMethodDescriptor * method, gint vtable_index, const GumTypeContextDescriptor * holder); static gboolean gum_module_metadata_collect_export ( const GumExportDetails * details, gpointer user_data); +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); static void gum_function_metadata_free (GumFunctionMetadata * function); @@ -339,6 +351,8 @@ gum_swift_api_resolver_init (GumSwiftApiResolver * self) module->path = d->path; module->base_address = d->range->base_address; module->functions = NULL; + module->vtables = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); module->resolver = self; g_hash_table_insert (self->module_by_name, g_strdup (module->name), module); @@ -512,6 +526,9 @@ gum_module_metadata_unref (GumModuleMetadata * module) module->ref_count--; if (module->ref_count == 0) { + if (module->vtables != NULL) + g_hash_table_unref (module->vtables); + if (module->functions != NULL) g_array_unref (module->functions); @@ -527,10 +544,10 @@ gum_module_metadata_get_functions (GumModuleMetadata * self) self->functions = g_array_new (FALSE, FALSE, sizeof (GumFunctionMetadata)); g_array_set_clear_func (self->functions, (GDestroyNotify) gum_function_metadata_free); - gum_module_enumerate_sections (self->path, - gum_module_metadata_collect_section, self); gum_module_enumerate_exports (self->path, gum_module_metadata_collect_export, self); + gum_module_enumerate_sections (self->path, + gum_module_metadata_collect_section, self); } return self->functions; @@ -599,22 +616,29 @@ 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]; - gchar * label; - - label = g_strdup_printf ("vtable[%u]", i); - gum_module_metadata_collect_function (self, label, - gum_resolve_relative_direct_ptr (&method->impl), type); +#if 0 + g_printerr ("\tvtable[%u]: flags=0x%08x impl=%p\n", + i, + method->flags, + gum_resolve_relative_direct_ptr (&method->impl)); +#endif - g_free (label); + gum_module_metadata_collect_method (self, method, i, type); } trailer = methods + vth->vtable_size; } +#if 0 if (GUM_TYPE_FLAGS_CLASS_HAS_OVERRIDE_TABLE (type_flags)) { const GumOverrideTableHeader * oth; @@ -628,33 +652,38 @@ gum_module_metadata_collect_class (GumModuleMetadata * self, for (i = 0; i != oth->num_entries; i++) { const GumMethodOverrideDescriptor * method = &methods[i]; - gchar * label; - - label = g_strdup_printf ("overrides[%u]", i); - gum_module_metadata_collect_function (self, label, - gum_resolve_relative_direct_ptr (&method->impl), type); - - g_free (label); + gum_module_metadata_collect_function (self, + gum_resolve_relative_direct_ptr (&method->impl), -1, 0, type); } trailer = methods + oth->num_entries; } +#endif } static void -gum_module_metadata_collect_function (GumModuleMetadata * self, - const gchar * label, - gconstpointer impl, - const GumTypeContextDescriptor * holder) +gum_module_metadata_collect_method (GumModuleMetadata * self, + const GumMethodDescriptor * method, + gint vtable_index, + const GumTypeContextDescriptor * holder) { + gconstpointer impl; GString * scope; GumFunctionMetadata func; const GumContextDescriptor * cur; + GPtrArray * vtable; + impl = gum_resolve_relative_direct_ptr (&method->impl); if (impl == NULL) return; + if (GUM_METHOD_DESCRIPTOR_IS_ASYNC (method)) + { + impl = gum_resolve_relative_direct_ptr ( + (const GumRelativeDirectPtr *) impl); + } + scope = g_string_sized_new (16); for (cur = gum_resolve_relative_indirectable_ptr (&holder->context.parent); @@ -704,12 +733,35 @@ gum_module_metadata_collect_function (GumModuleMetadata * self, g_string_append (scope, gum_resolve_relative_direct_ptr (&holder->name)); - func.name = g_strdup_printf ( - "%s.%s(%s+0x%" G_GINT64_MODIFIER "x)", - scope->str, - label, - self->name, - GUM_ADDRESS (impl) - self->base_address); + func.name = NULL; + + if (vtable_index != -1) + { + vtable = g_hash_table_lookup (self->vtables, scope->str); + 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 + } + } + } + + if (func.name == NULL) + { + func.name = g_strdup_printf ( + "%s.%s[%d](%s+0x%" G_GINT64_MODIFIER "x)", + scope->str, + (vtable_index != -1) ? "vtable" : "overrides", + vtable_index, + self->name, + GUM_ADDRESS (impl) - self->base_address); + } + func.address = GUM_ADDRESS (impl); g_array_append_val (self->functions, func); @@ -721,7 +773,7 @@ static gboolean gum_module_metadata_collect_export (const GumExportDetails * details, gpointer user_data) { - GumModuleMetadata * module = user_data; + GumModuleMetadata * self = user_data; gchar name[512]; size_t len; GumFunctionMetadata func; @@ -729,13 +781,13 @@ gum_module_metadata_collect_export (const GumExportDetails * details, if (details->type != GUM_EXPORT_FUNCTION) return TRUE; - len = module->resolver->demangle (details->name, name, sizeof (name)); + len = self->resolver->demangle (details->name, name, sizeof (name)); if (len == 0) return TRUE; func.name = g_strdup (name); func.address = details->address; - g_array_append_val (module->functions, func); + g_array_append_val (self->functions, func); if (g_str_has_prefix (func.name, "dispatch thunk of ")) { @@ -757,7 +809,15 @@ gum_module_metadata_collect_export (const GumExportDetails * details, insn = cs_malloc (capstone); - g_printerr ("\n=== %s\n", func.name + strlen ("dispatch thunk of ")); + gboolean should_log = FALSE; //strstr (func.name, "CoreDevice.RemoteDevice") != NULL; + + 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; end_of_block = FALSE; @@ -818,17 +878,83 @@ gum_module_metadata_collect_export (const GumExportDetails * details, if (vtable_index != -1) { - g_printerr (" => SUCCESS, vtable_index=%d\n", vtable_index); + const gchar * full_name; + gchar * class_name; + GPtrArray * vtable; + + full_name = func.name + strlen ("dispatch thunk of "); + class_name = gum_extract_class_name (full_name); + + 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); + } + + 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_printerr (" => SUCCESS, class_name=\"%s\", vtable_index=%d\n", class_name, vtable_index); + + g_free (class_name); } else { - g_printerr (" => FAILURE, vtable_index not determined\n"); + if (should_log) + g_printerr (" => FAILURE, vtable_index not determined\n"); } } return TRUE; } +static gchar * +gum_extract_class_name (const gchar * full_name) +{ + const gchar * ch; + + ch = strstr (full_name, " : "); + if (ch != NULL) + { + ch = gum_find_character_backwards (ch, '.', full_name); + if (ch == NULL) + return NULL; + } + else + { + ch = strchr (full_name, '('); + if (ch == NULL) + return NULL; + } + + ch = gum_find_character_backwards (ch, '.', full_name); + if (ch == NULL) + return NULL; + + return g_strndup (full_name, ch - full_name); +} + +static const gchar * +gum_find_character_backwards (const gchar * starting_point, + char needle, + const gchar * start) +{ + const gchar * ch = starting_point; + + do + { + ch--; + if (*ch == needle) + return ch; + } + while (ch != start); + + return NULL; +} + static void gum_function_metadata_free (GumFunctionMetadata * function) {