在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 文件下 , 这类大型的工程,结构会出乎意料的复杂。。。。。。
2 条评论
thouger · 2023年3月2日 上午10:55
是安卓8.1吗,我是安卓8.0的源码,但是全局搜索没有找到__dl___dlopen这个函数
pareto · 2023年3月7日 下午7:42
是的 ,__dl___dlopen 拼接过字符串