diff --git a/gum/gumswiftapiresolver.c b/gum/gumswiftapiresolver.c index 522f2b594..bf77f698c 100644 --- a/gum/gumswiftapiresolver.c +++ b/gum/gumswiftapiresolver.c @@ -21,20 +21,49 @@ #include "gumprocess.h" #include +#include /* temporary */ + +#define GUM_DESCRIPTOR_FLAGS_KIND(flags) \ + (flags & 0x1f) +#define GUM_DESCRIPTOR_FLAGS_KIND_FLAGS(flags) \ + (flags >> 16) +#define GUM_DESCRIPTOR_FLAGS_IS_GENERIC(flags) \ + ((flags & GUM_DESCRIPTOR_IS_GENERIC) != 0) +#define GUM_DESCRIPTOR_FLAGS_IS_UNIQUE(flags) \ + ((flags & GUM_DESCRIPTOR_IS_UNIQUE) != 0) + +#define GUM_TYPE_FLAGS_METADATA_INITIALIZATION_MASK(flags) \ + (flags & 3) +#define GUM_TYPE_FLAGS_CLASS_HAS_VTABLE(flags) \ + ((flags & GUM_CLASS_HAS_VTABLE) != 0) +#define GUM_TYPE_FLAGS_CLASS_HAS_OVERRIDE_TABLE(flags) \ + ((flags & GUM_CLASS_HAS_OVERRIDE_TABLE) != 0) + +#define GUM_GENERIC_DESCRIPTOR_FLAGS_HAS_TYPE_PACKS(flags) \ + ((flags & GUM_GENERIC_DESCRIPTOR_HAS_TYPE_PACKS) != 0) + +#define GUM_ALIGN(ptr, type) \ + GUM_ALIGN_POINTER (type, ptr, G_ALIGNOF (type)) typedef struct _GumModuleMetadata GumModuleMetadata; typedef struct _GumFunctionMetadata GumFunctionMetadata; typedef size_t (* GumSwiftDemangle) (const char * name, char * output, size_t length); -typedef struct _GumTargetContextDescriptor GumTargetContextDescriptor; -typedef struct _GumTargetTypeContextDescriptor GumTargetTypeContextDescriptor; -typedef struct _GumTargetGenericContextDescriptorHeader - GumTargetGenericContextDescriptorHeader; -typedef struct _GumTargetTypeGenericContextDescriptorHeader - GumTargetTypeGenericContextDescriptorHeader; -typedef struct _GumTargetClassDescriptor GumTargetClassDescriptor; -typedef struct _GumTargetVTableDescriptorHeader GumTargetVTableDescriptorHeader; -typedef struct _GumTargetOverrideTableHeader GumTargetOverrideTableHeader; +typedef struct _GumContextDescriptor GumContextDescriptor; +typedef struct _GumTypeContextDescriptor GumTypeContextDescriptor; +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; struct _GumSwiftApiResolver { @@ -71,27 +100,40 @@ enum _GumContextDescriptorKind GUM_CONTEXT_DESCRIPTOR_STRUCT, }; +enum _GumContextDescriptorFlags +{ + GUM_DESCRIPTOR_IS_GENERIC = (1 << 7), + GUM_DESCRIPTOR_IS_UNIQUE = (1 << 6), +}; + enum _GumTypeContextDescriptorFlags { - GUM_CLASS_HAS_VTABLE = (1 << 15), - GUM_CLASS_HAS_OVERRIDE_TABLE = (1 << 14), + GUM_CLASS_HAS_VTABLE = (1 << 15), + GUM_CLASS_HAS_OVERRIDE_TABLE = (1 << 14), }; -struct _GumTargetContextDescriptor +enum _GumTypeMetadataInitializationKind +{ + GUM_METADATA_INITIALIZATION_NONE, + GUM_METADATA_INITIALIZATION_SINGLETON, + GUM_METADATA_INITIALIZATION_FOREIGN, +}; + +struct _GumContextDescriptor { guint32 flags; gint32 parent_delta; }; -struct _GumTargetTypeContextDescriptor +struct _GumTypeContextDescriptor { - GumTargetContextDescriptor target_ctx; + GumContextDescriptor target_ctx; gint32 name_delta; gint32 access_function_ptr_delta; gint32 fields_delta; }; -struct _GumTargetGenericContextDescriptorHeader +struct _GumGenericContextDescriptorHeader { guint16 num_params; guint16 num_requirements; @@ -99,16 +141,32 @@ struct _GumTargetGenericContextDescriptorHeader guint16 flags; }; -struct _GumTargetTypeGenericContextDescriptorHeader +enum _GumGenericContextDescriptorFlags +{ + GUM_GENERIC_DESCRIPTOR_HAS_TYPE_PACKS = (1 << 0), +}; + +struct _GumGenericParamDescriptor +{ + guint8 value; +}; + +struct _GumGenericRequirementDescriptor +{ + guint32 flags; + guint32 param_delta; +}; + +struct _GumTypeGenericContextDescriptorHeader { gint32 instantiation_cache_delta; gint32 default_instantiation_pattern_delta; - GumTargetGenericContextDescriptorHeader base; + GumGenericContextDescriptorHeader base; }; -struct _GumTargetClassDescriptor +struct _GumClassDescriptor { - GumTargetTypeContextDescriptor target_type; + GumTypeContextDescriptor target_type; gint32 superclass_type_delta; guint32 metadata_negative_size_in_words_or_resilient_metadata_bounds; guint32 metadata_positive_size_in_words_or_extra_class_flags; @@ -118,17 +176,42 @@ struct _GumTargetClassDescriptor guint32 padding; }; -struct _GumTargetVTableDescriptorHeader +struct _GumSingletonMetadataInitialization +{ + gint32 initialization_cache_delta; + gint32 incomplete_metadata_or_resilient_pattern_delta; + gint32 completion_function_delta; +}; + +struct _GumForeignMetadataInitialization +{ + gint32 completion_function_delta; +}; + +struct _GumVTableDescriptorHeader { guint32 vtable_offset; guint32 vtable_size; }; -struct _GumTargetOverrideTableHeader +struct _GumMethodDescriptor +{ + guint32 flags; + gint32 impl_delta; +}; + +struct _GumOverrideTableHeader { guint32 num_entries; }; +struct _GumMethodOverrideDescriptor +{ + gint32 class_delta; + gint32 method_delta; + gint32 impl_delta; +}; + static void gum_swift_api_resolver_iface_init (gpointer g_iface, gpointer iface_data); static void gum_swift_api_resolver_finalize (GObject * object); @@ -382,11 +465,11 @@ 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); - g_printerr ("sizeof (GumTargetContextDescriptor) == %zu\n", sizeof (GumTargetContextDescriptor)); - g_printerr ("sizeof (GumTargetTypeContextDescriptor) == %zu\n", sizeof (GumTargetTypeContextDescriptor)); - g_printerr ("sizeof (GumTargetClassDescriptor) == %zu\n", sizeof (GumTargetClassDescriptor)); - g_printerr ("offsetof (GumTargetClassDescriptor, target_type) == %zu\n", G_STRUCT_OFFSET (GumTargetClassDescriptor, target_type)); - g_printerr ("offsetof (GumTargetClassDescriptor, superclass_type_delta) == %zu\n", G_STRUCT_OFFSET (GumTargetClassDescriptor, superclass_type_delta)); + g_printerr ("sizeof (GumContextDescriptor) == %zu\n", sizeof (GumContextDescriptor)); + g_printerr ("sizeof (GumTypeContextDescriptor) == %zu\n", sizeof (GumTypeContextDescriptor)); + g_printerr ("sizeof (GumClassDescriptor) == %zu\n", sizeof (GumClassDescriptor)); + g_printerr ("offsetof (GumClassDescriptor, target_type) == %zu\n", G_STRUCT_OFFSET (GumClassDescriptor, target_type)); + g_printerr ("offsetof (GumClassDescriptor, superclass_type_delta) == %zu\n", G_STRUCT_OFFSET (GumClassDescriptor, superclass_type_delta)); g_printerr ("collecting exports of %s\n", self->path); the_base = gum_module_find_base_address (self->path); gum_module_enumerate_sections (self->path, @@ -420,46 +503,133 @@ gum_module_metadata_collect_section (const GumSectionDetails * details, for (i = 0; i != n; i++) { - const GumTargetTypeContextDescriptor * type = - (const GumTargetTypeContextDescriptor *) ( + const GumTypeContextDescriptor * type = + (const GumTypeContextDescriptor *) ( (const guint8 *) &type_deltas[i] + type_deltas[i]); + guint32 descriptor_flags = type->target_ctx.flags; const gchar * name; - guint8 kind; name = (const gchar *) &type->name_delta + type->name_delta; g_printerr ("\n=== %s\n", name); g_printerr ("\tflags=0x%08x\n", type->target_ctx.flags); - kind = type->target_ctx.flags & 0x1f; - switch (kind) + switch (GUM_DESCRIPTOR_FLAGS_KIND (descriptor_flags)) { case GUM_CONTEXT_DESCRIPTOR_CLASS: { - GumTargetClassDescriptor * cd = (GumTargetClassDescriptor *) type; + const GumClassDescriptor * cd; guint16 type_flags; - gboolean has_vtable, has_override_table; + gconstpointer trailer; + + cd = (const GumClassDescriptor *) type; + trailer = cd + 1; + + if (GUM_DESCRIPTOR_FLAGS_IS_GENERIC (descriptor_flags)) + { + const GumTypeGenericContextDescriptorHeader * h; + const GumGenericParamDescriptor * params; + const GumGenericRequirementDescriptor * reqs; + + h = GUM_ALIGN (trailer, GumTypeGenericContextDescriptorHeader); + trailer = h + 1; + + params = GUM_ALIGN (trailer, GumGenericParamDescriptor); + trailer = params + h->num_params; - type_flags = type->target_ctx.flags >> 16; + 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 */ + } + } + + 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; + } + } g_printerr ("\tclass offset=0x%x\n", (int) (GUM_ADDRESS (cd) - the_base)); - has_vtable = (type_flags & GUM_CLASS_HAS_VTABLE) != 0; - g_printerr ("\thas_vtable=%s\n", has_vtable ? "TRUE" : "FALSE"); - if (has_vtable) + if (GUM_TYPE_FLAGS_CLASS_HAS_VTABLE (type_flags)) { - GumTargetVTableDescriptorHeader * vth = - (GumTargetVTableDescriptorHeader *) (cd + 1); + const GumVTableDescriptorHeader * vth; + const GumMethodDescriptor * methods; + guint32 i; + + vth = GUM_ALIGN (trailer, GumVTableDescriptorHeader); + methods = GUM_ALIGN ((const GumMethodDescriptor *) (vth + 1), + GumMethodDescriptor); + g_printerr ("\tvtable offset: 0x%x\n", vth->vtable_offset); g_printerr ("\tvtable size: 0x%x\n", vth->vtable_size); + + for (i = 0; i != vth->vtable_size; i++) + { + const GumMethodDescriptor * method = &methods[i]; + + g_printerr ("\t\tmethods[%u]: 0x%08x, %p\n", + i, + method->flags, + (guint8 *) &method->impl_delta + method->impl_delta); + } + + trailer = methods + vth->vtable_size; } - has_override_table = (type_flags & GUM_CLASS_HAS_OVERRIDE_TABLE) != 0; - g_printerr ("\thas_override_table=%s\n", has_override_table ? "TRUE" : "FALSE"); - if (has_override_table) + if (GUM_TYPE_FLAGS_CLASS_HAS_OVERRIDE_TABLE (type_flags)) { - GumTargetOverrideTableHeader * oth = - (GumTargetOverrideTableHeader *) (cd + 1); - g_printerr ("\toverride entries: 0x%x\n", oth->num_entries); + const GumOverrideTableHeader * oth; + const GumMethodOverrideDescriptor * methods; + guint32 i; + + oth = GUM_ALIGN (trailer, GumOverrideTableHeader); + methods = GUM_ALIGN ((const GumMethodOverrideDescriptor *) (oth + 1), + GumMethodOverrideDescriptor); + + g_printerr ("\toverride_table size: 0x%x\n", oth->num_entries); + + for (i = 0; i != oth->num_entries; i++) + { + const GumMethodOverrideDescriptor * method = &methods[i]; + + g_printerr ("\t\tmethods[%u]: %p\n", + i, + (guint8 *) &method->impl_delta + method->impl_delta); + } + + trailer = methods + oth->num_entries; + } + +#if 0 + static int count = 0; + count++; + if (count == 3) + { + g_printerr ("Waiting for debugger in PID %u...\n", getpid ()); + while (!gum_process_is_debugger_attached ()) + { + g_usleep (G_USEC_PER_SEC); + } } +#endif break; }