Example #1
0
guint8 *
gum_kernel_read (GumAddress address,
                 gsize len,
                 gsize * n_bytes_read)
{
  mach_port_t task;

  task = gum_kernel_get_task ();
  if (task == MACH_PORT_NULL)
    return NULL;

  return gum_darwin_read (task, address, len, n_bytes_read);
}
Example #2
0
static gboolean
gum_emit_modules_in_range (const GumMemoryRange * range,
                           GumEnumerateModulesSlowContext * ctx)
{
  GumAddress address = range->base_address;
  gsize remaining = range->size;
  gboolean carry_on = TRUE;

  do
  {
    struct mach_header * header;
    gboolean is_dylib;
    guint8 * chunk;
    gsize chunk_size;
    guint8 * first_command, * p;
    guint cmd_index;
    GumMemoryRange dylib_range;

    header = (struct mach_header *) gum_darwin_read (ctx->task,
        address, sizeof (struct mach_header), NULL);
    if (header == NULL)
      return TRUE;
    is_dylib = (header->magic == MH_MAGIC || header->magic == MH_MAGIC_64) &&
        header->filetype == MH_DYLIB;
    g_free (header);

    if (!is_dylib)
    {
      address += ctx->alignment;
      remaining -= ctx->alignment;
      continue;
    }

    chunk = gum_darwin_read (ctx->task,
        address, MIN (MAX_MACH_HEADER_SIZE, remaining), &chunk_size);
    if (chunk == NULL)
      return TRUE;

    header = (struct mach_header *) chunk;
    if (header->magic == MH_MAGIC)
      first_command = chunk + sizeof (struct mach_header);
    else
      first_command = chunk + sizeof (struct mach_header_64);

    dylib_range.base_address = address;
    dylib_range.size = ctx->alignment;

    p = first_command;
    for (cmd_index = 0; cmd_index != header->ncmds; cmd_index++)
    {
      const struct load_command * lc = (struct load_command *) p;

      if (lc->cmd == GUM_LC_SEGMENT)
      {
        gum_segment_command_t * sc = (gum_segment_command_t *) lc;
        if (strcmp (sc->segname, "__TEXT") == 0)
        {
          dylib_range.size = sc->vmsize;
          break;
        }
      }

      p += lc->cmdsize;
    }

    p = first_command;
    for (cmd_index = 0; cmd_index != header->ncmds; cmd_index++)
    {
      const struct load_command * lc = (struct load_command *) p;

      if (lc->cmd == LC_ID_DYLIB)
      {
        const struct dylib * dl = &((struct dylib_command *) lc)->dylib;
        const gchar * raw_path;
        guint raw_path_len;
        gchar * path, * name;
        GumModuleDetails details;

        raw_path = (gchar *) p + dl->name.offset;
        raw_path_len = lc->cmdsize - sizeof (struct dylib_command);
        path = g_malloc (raw_path_len + 1);
        memcpy (path, raw_path, raw_path_len);
        path[raw_path_len] = '\0';
        name = g_path_get_basename (path);

        details.name = name;
        details.range = &dylib_range;
        details.path = path;

        carry_on = ctx->func (&details, ctx->user_data);

        g_free (name);
        g_free (path);

        break;
      }

      p += lc->cmdsize;
    }

    g_free (chunk);

    address += dylib_range.size;
    remaining -= dylib_range.size;

    if (!carry_on)
      break;
  }
  while (remaining != 0);

  return carry_on;
}
Example #3
0
void
gum_darwin_enumerate_modules (mach_port_t task,
                              GumFoundModuleFunc func,
                              gpointer user_data)
{
  struct task_dyld_info info;
  mach_msg_type_number_t count;
  kern_return_t kr;
  gsize info_array_count, info_array_size, i;
  GumAddress info_array_address;
  gpointer info_array = NULL;
  gpointer header_data = NULL;
  gchar * file_path = NULL;
  gboolean carry_on = TRUE;

#if defined (HAVE_ARM) || defined (HAVE_ARM64)
  DyldInfo info_raw;
  count = DYLD_INFO_COUNT;
  kr = task_info (task, TASK_DYLD_INFO, (task_info_t) &info_raw, &count);
  if (kr != KERN_SUCCESS)
    goto beach;
  switch (count)
  {
    case DYLD_INFO_LEGACY_COUNT:
      info.all_image_info_addr = info_raw.info_legacy.all_image_info_addr;
      info.all_image_info_size = 0;
      info.all_image_info_format = TASK_DYLD_ALL_IMAGE_INFO_32;
      break;
    case DYLD_INFO_32_COUNT:
      info.all_image_info_addr = info_raw.info_32.all_image_info_addr;
      info.all_image_info_size = info_raw.info_32.all_image_info_size;
      info.all_image_info_format = info_raw.info_32.all_image_info_format;
      break;
    case DYLD_INFO_64_COUNT:
      info.all_image_info_addr = info_raw.info_64.all_image_info_addr;
      info.all_image_info_size = info_raw.info_64.all_image_info_size;
      info.all_image_info_format = info_raw.info_64.all_image_info_format;
      break;
    default:
      g_assert_not_reached ();
  }
#else
  count = TASK_DYLD_INFO_COUNT;
  kr = task_info (task, TASK_DYLD_INFO, (task_info_t) &info, &count);
  if (kr != KERN_SUCCESS)
    goto beach;
#endif

  if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64)
  {
    DyldAllImageInfos64 * all_info;

    all_info = (DyldAllImageInfos64 *) gum_darwin_read (task,
        info.all_image_info_addr,
        sizeof (DyldAllImageInfos64),
        NULL);
    if (all_info == NULL)
      goto beach;
    info_array_count = all_info->info_array_count;
    info_array_size = info_array_count * DYLD_IMAGE_INFO_64_SIZE;
    info_array_address = all_info->info_array;
    g_free (all_info);
  }
  else
  {
    DyldAllImageInfos32 * all_info;

    all_info = (DyldAllImageInfos32 *) gum_darwin_read (task,
        info.all_image_info_addr,
        sizeof (DyldAllImageInfos32),
        NULL);
    if (all_info == NULL)
      goto beach;
    info_array_count = all_info->info_array_count;
    info_array_size = info_array_count * DYLD_IMAGE_INFO_32_SIZE;
    info_array_address = all_info->info_array;
    g_free (all_info);
  }

  if (info_array_address == 0)
    goto fallback;

  info_array =
      gum_darwin_read (task, info_array_address, info_array_size, NULL);

  for (i = 0; i != info_array_count && carry_on; i++)
  {
    GumAddress load_address, file_path_address;
    struct mach_header * header;
    guint8 * first_command, * p;
    guint cmd_index;
    GumMemoryRange dylib_range;
    gchar * name;
    GumModuleDetails details;

    if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64)
    {
      DyldImageInfo64 * info = info_array + (i * DYLD_IMAGE_INFO_64_SIZE);
      load_address = info->image_load_address;
      file_path_address = info->image_file_path;
    }
    else
    {
      DyldImageInfo32 * info = info_array + (i * DYLD_IMAGE_INFO_32_SIZE);
      load_address = info->image_load_address;
      file_path_address = info->image_file_path;
    }

    header_data = gum_darwin_read (task,
        load_address,
        MAX_MACH_HEADER_SIZE,
        NULL);
    file_path = (gchar *) gum_darwin_read (task,
        file_path_address,
        2 * MAXPATHLEN,
        NULL);
    if (header_data == NULL || file_path == NULL)
      goto beach;

    header = (struct mach_header *) header_data;
    if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64)
      first_command = header_data + sizeof (struct mach_header_64);
    else
      first_command = header_data + sizeof (struct mach_header);

    dylib_range.base_address = load_address;
    dylib_range.size = 4096;

    p = first_command;
    for (cmd_index = 0; cmd_index != header->ncmds; cmd_index++)
    {
      const struct load_command * lc = (struct load_command *) p;

      if (lc->cmd == GUM_LC_SEGMENT)
      {
        gum_segment_command_t * sc = (gum_segment_command_t *) lc;
        if (strcmp (sc->segname, "__TEXT") == 0)
        {
          dylib_range.size = sc->vmsize;
          break;
        }
      }

      p += lc->cmdsize;
    }

    name = g_path_get_basename (file_path);

    details.name = name;
    details.range = &dylib_range;
    details.path = file_path;

    carry_on = func (&details, user_data);

    g_free (name);

    g_free (file_path);
    file_path = NULL;
    g_free (header_data);
    header_data = NULL;
  }

  goto beach;

fallback:
  gum_darwin_enumerate_modules_slow (task, func, user_data);

beach:
  g_free (file_path);
  g_free (header_data);
  g_free (info_array);

  return;
}
Example #4
0
static gboolean
gum_probe_range_for_entrypoint (const GumRangeDetails * details,
                                gpointer user_data)
{
  const GumMemoryRange * range = details->range;
  GumFindEntrypointContext * ctx = user_data;
  gboolean carry_on = TRUE;
  guint8 * chunk, * page, * p;
  gsize chunk_size;

  chunk = gum_darwin_read (ctx->task, range->base_address, range->size,
      &chunk_size);
  if (chunk == NULL)
    return TRUE;

  g_assert (chunk_size % ctx->alignment == 0);

  for (page = chunk; page != chunk + chunk_size; page += ctx->alignment)
  {
    struct mach_header * header;
    gint64 slide;
    guint cmd_index;
    GumAddress text_base = 0, text_offset = 0;

    header = (struct mach_header *) page;
    if (header->magic != MH_MAGIC && header->magic != MH_MAGIC_64)
      continue;

    if (header->filetype != MH_EXECUTE)
      continue;

    if (!gum_darwin_find_slide (range->base_address + (page - chunk), page,
          chunk_size - (page - chunk), &slide))
    {
      continue;
    }

    carry_on = FALSE;

    if (header->magic == MH_MAGIC)
      p = page + sizeof (struct mach_header);
    else
      p = page + sizeof (struct mach_header_64);
    for (cmd_index = 0; cmd_index != header->ncmds; cmd_index++)
    {
      const struct load_command * lc = (struct load_command *) p;

      switch (lc->cmd)
      {
        case LC_SEGMENT:
        {
          struct segment_command * sc = (struct segment_command *) lc;
          if (strcmp (sc->segname, "__TEXT") == 0)
            text_base = sc->vmaddr + slide;
          break;
        }
        case LC_SEGMENT_64:
        {
          struct segment_command_64 * sc = (struct segment_command_64 *) lc;
          if (strcmp (sc->segname, "__TEXT") == 0)
            text_base = sc->vmaddr + slide;
          break;
        }
#ifdef HAVE_I386
        case LC_UNIXTHREAD:
        {
          guint8 * thread = p + sizeof (struct thread_command);
          while (thread != p + lc->cmdsize)
          {
            thread_state_flavor_t * flavor = (thread_state_flavor_t *) thread;
            mach_msg_type_number_t * count = (mach_msg_type_number_t *)
                (flavor + 1);
            if (header->magic == MH_MAGIC && *flavor == x86_THREAD_STATE32)
            {
              x86_thread_state32_t * ts = (x86_thread_state32_t *) (count + 1);
              ctx->result = ts->__eip + slide;
            }
            else if (header->magic == MH_MAGIC_64 &&
                *flavor == x86_THREAD_STATE64)
            {
              x86_thread_state64_t * ts = (x86_thread_state64_t *) (count + 1);
              ctx->result = ts->__rip + slide;
            }
            thread = ((guint8 *) (count + 1)) + (*count * sizeof (int));
          }
          break;
        }
#endif
        case LC_MAIN:
        {
          struct entry_point_command * ec = (struct entry_point_command *) p;
          text_offset = ec->entryoff;
          break;
        }
      }
      p += lc->cmdsize;
    }

    if (ctx->result == 0)
      ctx->result = text_base + text_offset;

    if (!carry_on)
      break;
  }

  g_free (chunk);
  return carry_on;
}
Example #5
0
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;
}