Skip to content

Commit

Permalink
[WIP] Wire up some more
Browse files Browse the repository at this point in the history
Co-authored-by: Håvard Sørbø <[email protected]>
  • Loading branch information
oleavr and hsorbo committed Sep 14, 2023
1 parent 3ed1612 commit 5a9bb3b
Showing 1 changed file with 215 additions and 45 deletions.
260 changes: 215 additions & 45 deletions gum/gumswiftapiresolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,49 @@
#include "gumprocess.h"

#include <string.h>
#include <unistd.h> /* 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
{
Expand Down Expand Up @@ -71,44 +100,73 @@ 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;
guint16 num_key_arguments;
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;
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 5a9bb3b

Please sign in to comment.