在android8源码追踪dlopen调用过程时,遇到问题。

如图,需要找__loader_dlopen。在bionic目录全局找符号 ,只在ANDROID_LIBDL_STRTAB找到

ANDROID_LIBDL_STRTAB 又只在 g_libdl_symtab 使用

static ElfW(Sym) g_libdl_symtab[] = {
  // Total length of libdl_info.strtab, including trailing 0.
  // This is actually the STH_UNDEF entry. Technically, it's
  // supposed to have st_name == 0, but instead, it points to an index
  // in the strtab with a \0 to make iterating through the symtab easier.
  ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, nullptr, 0),
  ELFW(SYM_INITIALIZER)(  0, &__dlopen, 1),
  ELFW(SYM_INITIALIZER)( 16, &, 1),
  ELFW(SYM_INITIALIZER)( 33, &__dlsym, 1),
  ELFW(SYM_INITIALIZER)( 48, &__dlerror, 1),
  ELFW(SYM_INITIALIZER)( 65, &__dladdr, 1),
  ELFW(SYM_INITIALIZER)( 81, &__android_update_LD_LIBRARY_PATH, 1),
  ELFW(SYM_INITIALIZER)(121, &__android_get_LD_LIBRARY_PATH, 1),
  ELFW(SYM_INITIALIZER)(158, &dl_iterate_phdr, 1),
  ELFW(SYM_INITIALIZER)(183, &__android_dlopen_ext, 1),
  ELFW(SYM_INITIALIZER)(211, &__android_set_application_target_sdk_version, 1),
  ELFW(SYM_INITIALIZER)(263, &__android_get_application_target_sdk_version, 1),
  ELFW(SYM_INITIALIZER)(315, &__android_init_anonymous_namespace, 1),
  ELFW(SYM_INITIALIZER)(357, &__android_create_namespace, 1),
  ELFW(SYM_INITIALIZER)(391, &__dlvsym, 1),
  ELFW(SYM_INITIALIZER)(407, &__android_dlwarning, 1),
  ELFW(SYM_INITIALIZER)(434, &__cfi_fail, 1),
  ELFW(SYM_INITIALIZER)(452, &__android_link_namespaces, 1),
  ELFW(SYM_INITIALIZER)(485, &__android_get_exported_namespace, 1),
#if defined(__arm__)
  ELFW(SYM_INITIALIZER)(525, &__dl_unwind_find_exidx, 1),
#endif
};

用到的宏定义:

#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
    { name_offset, \
      reinterpret_cast<Elf32_Addr>(value), \
      /* st_size */ 0, \
      ((shndx) == 0) ? 0 : (STB_GLOBAL << 4), \
      /* st_other */ 0, \
      shndx, \
    }

#define ELFW(what) ELF32_ ## what

将宏展开

假设真把这个东西当作符号表,那么 __loader_dlopen 函数实现对应的函数就是__dlopen 。但是ELF文件符号表还能这么玩吗?? 结合注释和 g_libdl_symtab 的使用。

// Fake out a hash table with a single bucket.
//
// A search of the hash table will look through g_libdl_symtab starting with index 1, then
// use g_libdl_chains to find the next index to look at. g_libdl_chains should be set up to
// walk through every element in g_libdl_symtab, and then end with 0 (sentinel value).
//
// That is, g_libdl_chains should look like { 0, 2, 3, ... N, 0 } where N is the number
// of actual symbols, or nelems(g_libdl_symtab)-1 (since the first element of g_libdl_symtab is not
// a real symbol). (See soinfo_elf_lookup().)
//
// Note that adding any new symbols here requires stubbing them out in libdl.


soinfo* get_libdl_info(const char* linker_path, const link_map& linker_map) {
  if (__libdl_info == nullptr) {
    __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, linker_path, nullptr, 0, 0);
    __libdl_info->flags_ |= FLAG_LINKED;
    __libdl_info->strtab_ = ANDROID_LIBDL_STRTAB;
    __libdl_info->symtab_ = g_libdl_symtab;
    __libdl_info->nbucket_ = sizeof(g_libdl_buckets)/sizeof(unsigned);
    __libdl_info->nchain_ = sizeof(g_libdl_chains)/sizeof(unsigned);
    __libdl_info->bucket_ = g_libdl_buckets;
    __libdl_info->chain_ = g_libdl_chains;
    __libdl_info->ref_count_ = 1;
    __libdl_info->strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
    __libdl_info->local_group_root_ = __libdl_info;
    __libdl_info->soname_ = "ld-android.so";
    __libdl_info->target_sdk_version_ = __ANDROID_API__;
    __libdl_info->generate_handle();
    __libdl_info->link_map_head.l_addr = linker_map.l_addr;
    __libdl_info->link_map_head.l_name = linker_map.l_name;
    __libdl_info->link_map_head.l_ld = linker_map.l_ld;
#if defined(__work_around_b_24465209__)
    strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
#endif
  }

  return __libdl_info;
}

似乎是伪造了 soinfo_elf_lookup 查找符号用的soinfo。

希望看到的大佬能够解释一下。

对照android7版本代码

https://android.googlesource.com/platform/bionic/+/android-7.0.0_r1/linker/dlfcn.cpp

也可以看出dlopen 就是调用 __dlopen 函数。

以上为代码分析。

在做实际验证的时候,发现调用的是

__dl___dlopen(char const*, int, void const*)函数。

在bionic/linker/Android.bp 文件下 , 这类大型的工程,结构会出乎意料的复杂。。。。。。


pareto

未来什么方向不管,先做自己喜欢做的事情。

2 条评论

thouger · 2023年3月2日 上午10:55

是安卓8.1吗,我是安卓8.0的源码,但是全局搜索没有找到__dl___dlopen这个函数

    pareto · 2023年3月7日 下午7:42

    是的 ,__dl___dlopen 拼接过字符串

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注