diff --git a/gum/gumswiftapiresolver.c b/gum/gumswiftapiresolver.c index c3aa22dda..83ee972ce 100644 --- a/gum/gumswiftapiresolver.c +++ b/gum/gumswiftapiresolver.c @@ -31,6 +31,9 @@ #define GUM_DESCRIPTOR_FLAGS_IS_UNIQUE(flags) \ ((flags & GUM_DESCRIPTOR_IS_UNIQUE) != 0) +#define GUM_ANONYMOUS_DESCRIPTOR_FLAGS_HAS_MANGLED_NAME(flags) \ + ((flags & GUM_ANONYMOUS_DESCRIPTOR_HAS_MANGLED_NAME) != 0) + #define GUM_TYPE_FLAGS_METADATA_INITIALIZATION_MASK(flags) \ (flags & 3) #define GUM_TYPE_FLAGS_CLASS_HAS_VTABLE(flags) \ @@ -48,23 +51,28 @@ typedef struct _GumModuleMetadata GumModuleMetadata; typedef struct _GumFunctionMetadata GumFunctionMetadata; typedef size_t (* GumSwiftDemangle) (const char * name, char * output, size_t length); +typedef guint GumContextDescriptorKind; typedef struct _GumContextDescriptor GumContextDescriptor; +typedef struct _GumModuleContextDescriptor GumModuleContextDescriptor; +typedef struct _GumExtensionContextDescriptor GumExtensionContextDescriptor; typedef struct _GumTypeContextDescriptor GumTypeContextDescriptor; +typedef struct _GumClassDescriptor GumClassDescriptor; typedef struct _GumGenericContextDescriptorHeader GumGenericContextDescriptorHeader; typedef struct _GumGenericParamDescriptor GumGenericParamDescriptor; typedef struct _GumGenericRequirementDescriptor GumGenericRequirementDescriptor; typedef struct _GumTypeGenericContextDescriptorHeader GumTypeGenericContextDescriptorHeader; -typedef struct _GumClassDescriptor GumClassDescriptor; typedef struct _GumSingletonMetadataInitialization GumSingletonMetadataInitialization; typedef struct _GumForeignMetadataInitialization GumForeignMetadataInitialization; typedef struct _GumVTableDescriptorHeader GumVTableDescriptorHeader; typedef struct _GumMethodDescriptor GumMethodDescriptor; typedef struct _GumOverrideTableHeader GumOverrideTableHeader; typedef struct _GumMethodOverrideDescriptor GumMethodOverrideDescriptor; +typedef struct _GumMangledContextName GumMangledContextName; typedef gint32 GumRelativeDirectPtr; +typedef gint32 GumRelativeIndirectablePtr; struct _GumSwiftApiResolver { @@ -98,8 +106,19 @@ struct _GumFunctionMetadata enum _GumContextDescriptorKind { - GUM_CONTEXT_DESCRIPTOR_CLASS = 16, - GUM_CONTEXT_DESCRIPTOR_STRUCT, + GUM_CONTEXT_DESCRIPTOR_MODULE, + GUM_CONTEXT_DESCRIPTOR_EXTENSION, + GUM_CONTEXT_DESCRIPTOR_ANONYMOUS, + GUM_CONTEXT_DESCRIPTOR_PROTOCOL, + GUM_CONTEXT_DESCRIPTOR_OPAQUE_TYPE, + + GUM_CONTEXT_DESCRIPTOR_TYPE_FIRST = 16, + + GUM_CONTEXT_DESCRIPTOR_CLASS = GUM_CONTEXT_DESCRIPTOR_TYPE_FIRST, + GUM_CONTEXT_DESCRIPTOR_STRUCT = GUM_CONTEXT_DESCRIPTOR_TYPE_FIRST + 1, + GUM_CONTEXT_DESCRIPTOR_ENUM = GUM_CONTEXT_DESCRIPTOR_TYPE_FIRST + 2, + + GUM_CONTEXT_DESCRIPTOR_TYPE_LAST = 31, }; enum _GumContextDescriptorFlags @@ -108,6 +127,11 @@ enum _GumContextDescriptorFlags GUM_DESCRIPTOR_IS_UNIQUE = (1 << 6), }; +enum _GumAnonymousContextDescriptorFlags +{ + GUM_ANONYMOUS_DESCRIPTOR_HAS_MANGLED_NAME = (1 << 0), +}; + enum _GumTypeContextDescriptorFlags { GUM_CLASS_HAS_VTABLE = (1 << 15), @@ -124,17 +148,40 @@ enum _GumTypeMetadataInitializationKind struct _GumContextDescriptor { guint32 flags; - GumRelativeDirectPtr parent; + GumRelativeIndirectablePtr parent; +}; + +struct _GumModuleContextDescriptor +{ + GumContextDescriptor context; + GumRelativeDirectPtr name; +}; + +struct _GumExtensionContextDescriptor +{ + GumContextDescriptor context; + GumRelativeDirectPtr extended_context; }; struct _GumTypeContextDescriptor { - GumContextDescriptor target_ctx; + GumContextDescriptor context; GumRelativeDirectPtr name; GumRelativeDirectPtr access_function_ptr; GumRelativeDirectPtr fields; }; +struct _GumClassDescriptor +{ + GumTypeContextDescriptor type_context; + GumRelativeDirectPtr superclass_type; + guint32 metadata_negative_size_in_words_or_resilient_metadata_bounds; + guint32 metadata_positive_size_in_words_or_extra_class_flags; + guint32 num_immediate_members; + guint32 num_fields; + guint32 field_offset_vector_offset; +}; + struct _GumGenericContextDescriptorHeader { guint16 num_params; @@ -167,17 +214,6 @@ struct _GumTypeGenericContextDescriptorHeader GumGenericContextDescriptorHeader base; }; -struct _GumClassDescriptor -{ - GumTypeContextDescriptor target_type; - GumRelativeDirectPtr superclass_type; - guint32 metadata_negative_size_in_words_or_resilient_metadata_bounds; - guint32 metadata_positive_size_in_words_or_extra_class_flags; - guint32 num_immediate_members; - guint32 num_fields; - guint32 field_offset_vector_offset; -}; - struct _GumSingletonMetadataInitialization { GumRelativeDirectPtr initialization_cache; @@ -214,6 +250,11 @@ struct _GumMethodOverrideDescriptor GumRelativeDirectPtr impl; }; +struct _GumMangledContextName +{ + GumRelativeDirectPtr name; +}; + static void gum_swift_api_resolver_iface_init (gpointer g_iface, gpointer iface_data); static void gum_swift_api_resolver_finalize (GObject * object); @@ -225,13 +266,27 @@ static void gum_module_metadata_unref (GumModuleMetadata * module); static GArray * gum_module_metadata_get_functions (GumModuleMetadata * self); static gboolean gum_module_metadata_collect_section ( const GumSectionDetails * details, gpointer user_data); +static void gum_module_metadata_collect_function (GumModuleMetadata * self, + const gchar * label, gconstpointer impl, + const GumTypeContextDescriptor * holder); static gboolean gum_module_metadata_collect_export ( const GumExportDetails * details, gpointer user_data); static void gum_function_metadata_free (GumFunctionMetadata * function); +static void gum_skip_generic_trailers (gconstpointer * trailer_ptr, + const GumContextDescriptor * t); +static void gum_skip_generic_type_trailers (gconstpointer * trailer_ptr, + const GumTypeContextDescriptor * t); +static void gum_skip_generic_parts (gconstpointer * trailer_ptr, + const GumGenericContextDescriptorHeader * h); +static void gum_skip_metadata_initialization_trailers ( + gconstpointer * trailer_ptr, const GumTypeContextDescriptor * t); + static gconstpointer gum_resolve_relative_direct_ptr ( const GumRelativeDirectPtr * delta); +static gconstpointer gum_resolve_relative_indirectable_ptr ( + const GumRelativeIndirectablePtr * delta); G_DEFINE_TYPE_EXTENDED (GumSwiftApiResolver, gum_swift_api_resolver, @@ -497,75 +552,26 @@ gum_module_metadata_collect_section (const GumSectionDetails * details, { const GumTypeContextDescriptor * type; guint32 descriptor_flags; - const gchar * name; type = gum_resolve_relative_direct_ptr (&types[i]); - descriptor_flags = type->target_ctx.flags; - - name = gum_resolve_relative_direct_ptr (&type->name); + descriptor_flags = type->context.flags; switch (GUM_DESCRIPTOR_FLAGS_KIND (descriptor_flags)) { case GUM_CONTEXT_DESCRIPTOR_CLASS: { const GumClassDescriptor * cd; - guint16 type_flags; gconstpointer trailer; + guint16 type_flags; cd = (const GumClassDescriptor *) type; trailer = cd + 1; - if (GUM_DESCRIPTOR_FLAGS_IS_GENERIC (descriptor_flags)) - { - const GumTypeGenericContextDescriptorHeader * th; - const GumGenericContextDescriptorHeader * h; - - th = GUM_ALIGN (trailer, GumTypeGenericContextDescriptorHeader); - trailer = th + 1; - - h = &th->base; - - if (h->num_params != 0) - { - const GumGenericParamDescriptor * params = - GUM_ALIGN (trailer, GumGenericParamDescriptor); - trailer = params + h->num_params; - } - - if (h->num_requirements != 0) - { - const GumGenericRequirementDescriptor * reqs = - GUM_ALIGN (trailer, GumGenericRequirementDescriptor); - trailer = reqs + h->num_requirements; - } + gum_skip_generic_type_trailers (&trailer, type); - if (GUM_GENERIC_DESCRIPTOR_FLAGS_HAS_TYPE_PACKS (h->flags)) - { - g_error ("Not yet implemented"); /* TODO */ - } - } + gum_skip_metadata_initialization_trailers (&trailer, type); - type_flags = GUM_DESCRIPTOR_FLAGS_KIND_FLAGS (descriptor_flags); - - switch (GUM_TYPE_FLAGS_METADATA_INITIALIZATION_MASK (type_flags)) - { - case GUM_METADATA_INITIALIZATION_NONE: - break; - case GUM_METADATA_INITIALIZATION_SINGLETON: - { - const GumSingletonMetadataInitialization * smi = - GUM_ALIGN (trailer, GumSingletonMetadataInitialization); - trailer = smi + 1; - break; - } - case GUM_METADATA_INITIALIZATION_FOREIGN: - { - const GumForeignMetadataInitialization * fmi = - GUM_ALIGN (trailer, GumForeignMetadataInitialization); - trailer = fmi + 1; - break; - } - } + type_flags = GUM_DESCRIPTOR_FLAGS_KIND_FLAGS (type->context.flags); if (GUM_TYPE_FLAGS_CLASS_HAS_VTABLE (type_flags)) { @@ -580,19 +586,14 @@ gum_module_metadata_collect_section (const GumSectionDetails * details, for (i = 0; i != vth->vtable_size; i++) { const GumMethodDescriptor * method = &methods[i]; - gconstpointer impl; - GumFunctionMetadata func; - - impl = gum_resolve_relative_direct_ptr (&method->impl); - - func.name = g_strdup_printf ( - "%s.vtable[%u](%s+0x%" G_GINT64_MODIFIER "x)", - name, - i, - module->name, - GUM_ADDRESS (impl) - module->base_address); - func.address = GUM_ADDRESS (impl); - g_array_append_val (module->functions, func); + gchar * label; + + label = g_strdup_printf ("vtable[%u]", i); + + gum_module_metadata_collect_function (module, label, + gum_resolve_relative_direct_ptr (&method->impl), type); + + g_free (label); } trailer = methods + vth->vtable_size; @@ -611,19 +612,14 @@ gum_module_metadata_collect_section (const GumSectionDetails * details, for (i = 0; i != oth->num_entries; i++) { const GumMethodOverrideDescriptor * method = &methods[i]; - gconstpointer impl; - GumFunctionMetadata func; - - impl = gum_resolve_relative_direct_ptr (&method->impl); - - func.name = g_strdup_printf ( - "%s.overrides[%u](%s+0x%" G_GINT64_MODIFIER "x)", - name, - i, - module->name, - GUM_ADDRESS (impl) - module->base_address); - func.address = GUM_ADDRESS (impl); - g_array_append_val (module->functions, func); + gchar * label; + + label = g_strdup_printf ("overrides[%u]", i); + + gum_module_metadata_collect_function (module, label, + gum_resolve_relative_direct_ptr (&method->impl), type); + + g_free (label); } trailer = methods + oth->num_entries; @@ -644,6 +640,84 @@ gum_module_metadata_collect_section (const GumSectionDetails * details, return TRUE; } +static void +gum_module_metadata_collect_function (GumModuleMetadata * self, + const gchar * label, + gconstpointer impl, + const GumTypeContextDescriptor * holder) +{ + GString * scope; + GumFunctionMetadata func; + const GumContextDescriptor * cur; + + scope = g_string_sized_new (16); + + g_printerr ("\n>>> walking from \"%s\"\n", (char *) gum_resolve_relative_direct_ptr (&holder->name)); + for (cur = gum_resolve_relative_indirectable_ptr (&holder->context.parent); + cur != NULL; + cur = gum_resolve_relative_indirectable_ptr (&cur->parent)) + { + GumContextDescriptorKind kind = GUM_DESCRIPTOR_FLAGS_KIND (cur->flags); + + g_printerr ("\tcur=%p kind=%u\n", cur, GUM_DESCRIPTOR_FLAGS_KIND (cur->flags)); + + switch (kind) + { + case GUM_CONTEXT_DESCRIPTOR_MODULE: + { + const GumModuleContextDescriptor * m = + (const GumModuleContextDescriptor *) cur; + g_string_prepend_c (scope, '.'); + g_string_prepend (scope, gum_resolve_relative_direct_ptr (&m->name)); + break; + } +#if 0 + case GUM_CONTEXT_DESCRIPTOR_EXTENSION: + { + const GumExtensionContextDescriptor * e = + (const GumExtensionContextDescriptor *) cur; + g_string_prepend_c (scope, '.'); + g_string_prepend (scope, + gum_resolve_relative_direct_ptr (&e->extended_context)); + break; + } +#endif + case GUM_CONTEXT_DESCRIPTOR_ANONYMOUS: + break; + default: + if (kind >= GUM_CONTEXT_DESCRIPTOR_TYPE_FIRST && + kind <= GUM_CONTEXT_DESCRIPTOR_TYPE_LAST) + { + const GumTypeContextDescriptor * t = + (const GumTypeContextDescriptor *) cur; + g_string_prepend_c (scope, '.'); + g_string_prepend (scope, gum_resolve_relative_direct_ptr (&t->name)); + break; + } + + g_printerr ("\t\tTODO\n"); + break; + } + } + g_printerr ("<<<\n"); + + g_string_append (scope, gum_resolve_relative_direct_ptr (&holder->name)); + + g_printerr (" => \"%s\"\n", scope->str); + + 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.address = GUM_ADDRESS (impl); + + g_array_append_val (self->functions, func); + + g_string_free (scope, TRUE); +} + static gboolean gum_module_metadata_collect_export (const GumExportDetails * details, gpointer user_data) @@ -673,10 +747,125 @@ gum_function_metadata_free (GumFunctionMetadata * function) g_free (function->name); } +static void +gum_skip_generic_trailers (gconstpointer * trailer_ptr, + const GumContextDescriptor * t) +{ + gconstpointer trailer = *trailer_ptr; + + if (GUM_DESCRIPTOR_FLAGS_IS_GENERIC (t->flags)) + { + const GumGenericContextDescriptorHeader * th; + + th = GUM_ALIGN (trailer, GumGenericContextDescriptorHeader); + trailer = th + 1; + + gum_skip_generic_parts (&trailer, th); + } + + *trailer_ptr = trailer; +} + +static void +gum_skip_generic_type_trailers (gconstpointer * trailer_ptr, + const GumTypeContextDescriptor * t) +{ + gconstpointer trailer = *trailer_ptr; + + if (GUM_DESCRIPTOR_FLAGS_IS_GENERIC (t->context.flags)) + { + const GumTypeGenericContextDescriptorHeader * th; + + th = GUM_ALIGN (trailer, GumTypeGenericContextDescriptorHeader); + trailer = th + 1; + + gum_skip_generic_parts (&trailer, &th->base); + } + + *trailer_ptr = trailer; +} + +static void +gum_skip_generic_parts (gconstpointer * trailer_ptr, + const GumGenericContextDescriptorHeader * h) +{ + gconstpointer trailer = *trailer_ptr; + + if (h->num_params != 0) + { + const GumGenericParamDescriptor * params = + GUM_ALIGN (trailer, GumGenericParamDescriptor); + trailer = params + h->num_params; + } + + if (h->num_requirements != 0) + { + const GumGenericRequirementDescriptor * reqs = + GUM_ALIGN (trailer, GumGenericRequirementDescriptor); + trailer = reqs + h->num_requirements; + } + + if (GUM_GENERIC_DESCRIPTOR_FLAGS_HAS_TYPE_PACKS (h->flags)) + { + g_error ("Not yet implemented"); /* TODO */ + } + + *trailer_ptr = trailer; +} + +static void +gum_skip_metadata_initialization_trailers (gconstpointer * trailer_ptr, + const GumTypeContextDescriptor * t) +{ + gconstpointer trailer = *trailer_ptr; + + switch (GUM_TYPE_FLAGS_METADATA_INITIALIZATION_MASK ( + GUM_DESCRIPTOR_FLAGS_KIND_FLAGS (t->context.flags))) + { + case GUM_METADATA_INITIALIZATION_NONE: + break; + case GUM_METADATA_INITIALIZATION_SINGLETON: + { + const GumSingletonMetadataInitialization * smi = + GUM_ALIGN (trailer, GumSingletonMetadataInitialization); + trailer = smi + 1; + break; + } + case GUM_METADATA_INITIALIZATION_FOREIGN: + { + const GumForeignMetadataInitialization * fmi = + GUM_ALIGN (trailer, GumForeignMetadataInitialization); + trailer = fmi + 1; + break; + } + } + + *trailer_ptr = trailer; +} + static gconstpointer gum_resolve_relative_direct_ptr (const GumRelativeDirectPtr * delta) { - return (const guint8 *) delta + *delta; + GumRelativeDirectPtr val = *delta; + + if (val == 0) + return NULL; + + return (const guint8 *) delta + val; +} + +static gconstpointer +gum_resolve_relative_indirectable_ptr (const GumRelativeIndirectablePtr * delta) +{ + GumRelativeIndirectablePtr val = *delta; + gconstpointer * target; + + if ((val & 1) == 0) + return gum_resolve_relative_direct_ptr (delta); + + target = (gconstpointer *) ((const guint8 *) delta + (val & ~1)); + + return *target; } #endif