void gum_darwin_enumerate_exports (mach_port_t task, const gchar * module_name, GumFoundExportFunc func, gpointer user_data) { GumEnumerateExportsContext ctx; ctx.task = task; ctx.modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); ctx.module_name = module_name; ctx.func = func; ctx.user_data = user_data; gum_darwin_enumerate_modules (task, gum_store_module_address, &ctx); gum_do_enumerate_exports (&ctx, module_name); g_hash_table_unref (ctx.modules); }
static gboolean gum_do_enumerate_exports (GumEnumerateExportsContext * ctx, const gchar * module_name) { gboolean carry_on = TRUE; GVariant * address_value; GumAddress address; guint8 * chunk = NULL; gsize chunk_size; struct mach_header * header; gint64 slide; GumAddress linkedit; GSList * text_section_ids = NULL; struct symtab_command * sc; gsize symbol_size; guint8 * symbols = NULL; GumAddress strings_address; gchar * strings; guint8 * cur_sym; guint symbol_index; address_value = g_hash_table_lookup (ctx->modules, module_name); if (address_value == NULL) goto beach; address = g_variant_get_uint64 (address_value); if (address == 0) goto beach; chunk = gum_darwin_read (ctx->task, address, MAX_MACH_HEADER_SIZE, &chunk_size); if (chunk == NULL) goto beach; header = (struct mach_header *) chunk; if (!gum_darwin_find_slide (address, chunk, chunk_size, &slide)) goto beach; if (!gum_darwin_find_linkedit (chunk, chunk_size, &linkedit)) goto beach; linkedit += slide; text_section_ids = gum_darwin_find_text_section_ids (chunk, chunk_size); if (!gum_darwin_find_symtab_command (chunk, chunk_size, &sc)) goto beach; if (header->magic == MH_MAGIC) symbol_size = sizeof (struct nlist); else symbol_size = sizeof (struct nlist_64); symbols = gum_darwin_read (ctx->task, linkedit + sc->symoff, sc->nsyms * symbol_size, NULL); if (symbols == NULL) goto beach; strings_address = linkedit + sc->stroff; strings = g_hash_table_lookup (ctx->strings, GSIZE_TO_POINTER (strings_address)); if (strings == NULL) { strings = (gchar *) gum_darwin_read (ctx->task, strings_address, sc->strsize, NULL); if (strings == NULL) goto beach; g_hash_table_insert (ctx->strings, GSIZE_TO_POINTER (strings_address), strings); } cur_sym = symbols; for (symbol_index = 0; symbol_index != sc->nsyms; symbol_index++) { GumExportDetails details; details.name = NULL; if (header->magic == MH_MAGIC) { struct nlist * sym = (struct nlist *) cur_sym; if (!SYMBOL_IS_UNDEFINED_DEBUG_OR_LOCAL (sym)) { details.type = g_slist_find (text_section_ids, GSIZE_TO_POINTER (sym->n_sect)) != NULL ? GUM_EXPORT_FUNCTION : GUM_EXPORT_VARIABLE; details.name = gum_symbol_name_from_darwin (strings + sym->n_un.n_strx); details.address = sym->n_value + slide; if ((sym->n_desc & N_ARM_THUMB_DEF) != 0) details.address++; } } else { struct nlist_64 * sym = (struct nlist_64 *) cur_sym; if (!SYMBOL_IS_UNDEFINED_DEBUG_OR_LOCAL (sym)) { details.type = g_slist_find (text_section_ids, GSIZE_TO_POINTER (sym->n_sect)) != NULL ? GUM_EXPORT_FUNCTION : GUM_EXPORT_VARIABLE; details.name = gum_symbol_name_from_darwin (strings + sym->n_un.n_strx); details.address = sym->n_value + slide; if ((sym->n_desc & N_ARM_THUMB_DEF) != 0) details.address++; } } if (details.name != NULL) { if (!ctx->func (&details, ctx->user_data)) { carry_on = FALSE; break; } } cur_sym += symbol_size; } if (carry_on) { guint8 * cur_cmd; guint cmd_index; if (header->magic == MH_MAGIC) cur_cmd = chunk + sizeof (struct mach_header); else cur_cmd = chunk + sizeof (struct mach_header_64); for (cmd_index = 0; cmd_index != header->ncmds; cmd_index++) { struct load_command * lc = (struct load_command *) cur_cmd; if (lc->cmd == LC_REEXPORT_DYLIB) { struct dylib_command * dc = (struct dylib_command *) lc; const char * name = (const char *) (((guint8 *) dc) + dc->dylib.name.offset); if (!gum_do_enumerate_exports (ctx, name)) { carry_on = FALSE; break; } } cur_cmd += lc->cmdsize; } } beach: g_free (symbols); g_slist_free (text_section_ids); g_free (chunk); return carry_on; }