Android 7.0 dlopen 函数分析

1. 说明

Android 7.0 后使用 dlopen 函数无法获取 soinfo 对应,因此也无法使用 dlsym 函数去调用第三方的 so 内的函数。这里给出 dlopen() 函数的源码分析。

不同点可参考:https://blog.csdn.net/u011247544/article/details/75262360

2. 源码分析

1. dlopen 函数

函数调用会首先走到 dlfcn.cpp 类内的 dlopen 函数(/bionic/linker/dlfcn.cpp)

85void* dlopen(const char* filename, int flags) {
86  void* caller_addr = __builtin_return_address(0);
87  return dlopen_ext(filename, flags, nullptr, caller_addr);
88}

69static void* dlopen_ext(const char* filename, int flags,
70                        const android_dlextinfo* extinfo, void* caller_addr) {
71  ScopedPthreadMutexLocker locker(&g_dl_mutex);
72  void* result = do_dlopen(filename, flags, extinfo, caller_addr);        // 调到 linker.cpp 类内
73  if (result == nullptr) {
74    __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
75    return nullptr;
76  }
77  return result;
78}

2. do_dlopen() 函数

这个函数实现在 linker.cpp 类内。do_dlopen 函数会调用 find_library 函数返回 soinfo 对象,并最终调用 si->to_handle() 函数返回 handle_。(/bionic/linker/linker.cpp)

2333void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
2334                  void* caller_addr) {
2335  soinfo* const caller = find_containing_library(caller_addr);
2336
2337  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
2338    DL_ERR("invalid flags to dlopen: %x", flags);
2339    return nullptr;
2340  }
2341
2342  android_namespace_t* ns = get_caller_namespace(caller);
2343
2344  if (extinfo != nullptr) {
2345    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
2346      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
2347      return nullptr;
2348    }
2349
2350    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
2351        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
2352      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
2353          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
2354      return nullptr;
2355    }
2356
2357    if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
2358        (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
2359      DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
2360             "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
2361      return nullptr;
2362    }
2363
2364    if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
2365      if (extinfo->library_namespace == nullptr) {
2366        DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
2367        return nullptr;
2368      }
2369      ns = extinfo->library_namespace;
2370    }
2371  }
2372
2373  ProtectedDataGuard guard;
2374  soinfo* si = find_library(ns, name, flags, extinfo, caller);      // 这里往下调用返回 soinfo 对象
2375  if (si != nullptr) {
2376    si->call_constructors();
2377    return si->to_handle();       // 这里返回的是 调用 to_handle() 函数
2378  }
2379
2380  return nullptr;
2381}

下面给处 find_library 函数的追踪:

首先是 find_library 函数

2159static soinfo* find_library(android_namespace_t* ns,
2160                            const char* name, int rtld_flags,
2161                            const android_dlextinfo* extinfo,
2162                            soinfo* needed_by) {
2163  soinfo* si;
2164
2165  if (name == nullptr) {
2166    si = somain;
2167  } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
2168                             extinfo, /* add_as_children */ false)) {
2169    return nullptr;
2170  }
2171
2172  return si;
2173}

接着是 find_libraries 函数,源码分析知道这个函数分为 4 步,暂未做具体分析

1994static bool find_libraries(android_namespace_t* ns,
1995                           soinfo* start_with,
1996                           const char* const library_names[],
1997                           size_t library_names_count, soinfo* soinfos[],
1998                           std::vector<soinfo*>* ld_preloads,
1999                           size_t ld_preloads_count, int rtld_flags,
2000                           const android_dlextinfo* extinfo,
2001                           bool add_as_children) {
2002  // Step 0: prepare.
2003  LoadTaskList load_tasks;
2004  std::unordered_map<const soinfo*, ElfReader> readers_map;
...
2053    if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
2054      return false;
2055    }
...
2156  return linked;
2157}

然后是 find_library_internal 函数

1896static bool find_library_internal(android_namespace_t* ns,
1897                                  LoadTask* task,
1898                                  ZipArchiveCache* zip_archive_cache,
1899                                  LoadTaskList* load_tasks,
1900                                  int rtld_flags) {
1901  soinfo* candidate;
1902
1903  if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
1904    task->set_soinfo(candidate);
1905    return true;
1906  }
1907
1908  if (ns != &g_default_namespace) {
1909    // check public namespace
1910    candidate = g_public_namespace.find_if([&](soinfo* si) {
1911      return strcmp(task->get_name(), si->get_soname()) == 0;
1912    });
1913
1914    if (candidate != nullptr) {
1915      ns->add_soinfo(candidate);
1916      task->set_soinfo(candidate);
1917      return true;
1918    }
1919  }
1920
1921  // Library might still be loaded, the accurate detection
1922  // of this fact is done by load_library.
1923  TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
1924      task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
1925
1926  if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
1927    return true;
1928  } else {
1929    // In case we were unable to load the library but there
1930    // is a candidate loaded under the same soname but different
1931    // sdk level - return it anyways.
1932    if (candidate != nullptr) {
1933      task->set_soinfo(candidate);
1934      return true;
1935    }
1936  }
1937
1938  return false;
1939}

3. soinfo::to_handle() 函数

(/bionic/linker/linker.cpp)
do_dlopen 函数的最终返回是这个函数的返回,看下 这个函数的实现:

3442void* soinfo::to_handle() {
3443  if (get_application_target_sdk_version() <= 23 || !has_min_version(3)) {
3444    return this;
3445  }
3446
3447  return reinterpret_cast<void*>(get_handle());
3448}

然后调用了 get_handle() 函数。这个函数就是返回了 handle_

3436uintptr_t soinfo::get_handle() const {
3437  CHECK(has_min_version(3));
3438  CHECK(handle_ != 0);
3439  return handle_;
3440}

那 handle_ 的生成是在哪里呢?是在同目录下的 generate_handle 函数

3450void soinfo::generate_handle() {
3451  CHECK(has_min_version(3));
3452  CHECK(handle_ == 0); // Make sure this is the first call
3453
3454  // Make sure the handle is unique and does not collide
3455  // with special values which are RTLD_DEFAULT and RTLD_NEXT.
3456  do {
3457    arc4random_buf(&handle_, sizeof(handle_));
3458    // the least significant bit for the handle is always 1
3459    // making it easy to test the type of handle passed to
3460    // dl* functions.
3461    handle_ = handle_ | 1;
3462  } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) ||
3463           handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) ||
3464           g_soinfo_handles_map.find(handle_) != g_soinfo_handles_map.end());
3465
3466  g_soinfo_handles_map[handle_] = this;
3467}

由上可以看出, handle_ 是 arc4random_buf(&handle_, sizeof(handle_)); 函数生成的随机值。并将这个值放到 static std::unordered_map<uintptr_t, soinfo*> g_soinfo_handles_map 内,这个值与 soinfo 对应。

4. soinfo 结构体

soinfo 结构体就是 so 文件解析后的数据信息,解析处的 节信息,等等等等~~

176struct soinfo {
177 public:
178  typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
179  typedef LinkedList<android_namespace_t, NamespaceListAllocator> android_namespace_list_t;
180#if defined(__work_around_b_24465209__)
181 private:
182  char old_name_[SOINFO_NAME_LEN];
183#endif
184 public:
185  const ElfW(Phdr)* phdr;
186  size_t phnum;
187  ElfW(Addr) entry;
188  ElfW(Addr) base;
189  size_t size;
190
191#if defined(__work_around_b_24465209__)
192  uint32_t unused1;  // DO NOT USE, maintained for compatibility.
193#endif
194
195  ElfW(Dyn)* dynamic;
196
197#if defined(__work_around_b_24465209__)
198  uint32_t unused2; // DO NOT USE, maintained for compatibility
199  uint32_t unused3; // DO NOT USE, maintained for compatibility
200#endif
201
202  soinfo* next;
203 private:
204  uint32_t flags_;
205
206  const char* strtab_;
207  ElfW(Sym)* symtab_;
208
209  size_t nbucket_;
210  size_t nchain_;
211  uint32_t* bucket_;
212  uint32_t* chain_;
213
214#if defined(__mips__) || !defined(__LP64__)
215  // This is only used by mips and mips64, but needs to be here for
216  // all 32-bit architectures to preserve binary compatibility.
217  ElfW(Addr)** plt_got_;
218#endif
219
220#if defined(USE_RELA)
221  ElfW(Rela)* plt_rela_;
222  size_t plt_rela_count_;
223
224  ElfW(Rela)* rela_;
225  size_t rela_count_;
226#else
227  ElfW(Rel)* plt_rel_;
228  size_t plt_rel_count_;
229
230  ElfW(Rel)* rel_;
231  size_t rel_count_;
232#endif
233
234  linker_function_t* preinit_array_;
235  size_t preinit_array_count_;
236
237  linker_function_t* init_array_;
238  size_t init_array_count_;
239  linker_function_t* fini_array_;
240  size_t fini_array_count_;
241
242  linker_function_t init_func_;
243  linker_function_t fini_func_;
244
245#if defined(__arm__)
246 public:
247  // ARM EABI section used for stack unwinding.
248  uint32_t* ARM_exidx;
249  size_t ARM_exidx_count;
250 private:
251#elif defined(__mips__)
252  uint32_t mips_symtabno_;
253  uint32_t mips_local_gotno_;
254  uint32_t mips_gotsym_;
255  bool mips_relocate_got(const VersionTracker& version_tracker,
256                         const soinfo_list_t& global_group,
257                         const soinfo_list_t& local_group);
258#if !defined(__LP64__)
259  bool mips_check_and_adjust_fp_modes();
260#endif
261#endif
262  size_t ref_count_;
263 public:
264  link_map link_map_head;
265
266  bool constructors_called;
267
268  // When you read a virtual address from the ELF file, add this
269  // value to get the corresponding address in the process' address space.
270  ElfW(Addr) load_bias;
271
272#if !defined(__LP64__)
273  bool has_text_relocations;
274#endif
275  bool has_DT_SYMBOLIC;
276
277 public:
278  soinfo(android_namespace_t* ns, const char* name, const struct stat* file_stat,
279         off64_t file_offset, int rtld_flags);
280  ~soinfo();
281
282  void call_constructors();
283  void call_destructors();
284  void call_pre_init_constructors();
285  bool prelink_image();
286  bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
287                  const android_dlextinfo* extinfo);
288  bool protect_relro();
289
290  void add_child(soinfo* child);
291  void remove_all_links();
292
293  ino_t get_st_ino() const;
294  dev_t get_st_dev() const;
295  off64_t get_file_offset() const;
296
297  uint32_t get_rtld_flags() const;
298  uint32_t get_dt_flags_1() const;
299  void set_dt_flags_1(uint32_t dt_flags_1);
300
301  soinfo_list_t& get_children();
302  const soinfo_list_t& get_children() const;
303
304  soinfo_list_t& get_parents();
305
306  bool find_symbol_by_name(SymbolName& symbol_name,
307                           const version_info* vi,
308                           const ElfW(Sym)** symbol) const;
309
310  ElfW(Sym)* find_symbol_by_address(const void* addr);
311  ElfW(Addr) resolve_symbol_address(const ElfW(Sym)* s) const;
312
313  const char* get_string(ElfW(Word) index) const;
314  bool can_unload() const;
315  bool is_gnu_hash() const;
316
317  bool inline has_min_version(uint32_t min_version __unused) const {
318#if defined(__work_around_b_24465209__)
319    return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
320#else
321    return true;
322#endif
323  }
325  bool is_linked() const;
326  bool is_linker() const;
327  bool is_main_executable() const;
328
329  void set_linked();
330  void set_linker_flag();
331  void set_main_executable();
332  void set_nodelete();
333
334  void increment_ref_count();
335  size_t decrement_ref_count();
336
337  soinfo* get_local_group_root() const;
338
339  void set_soname(const char* soname);
340  const char* get_soname() const;
341  const char* get_realpath() const;
342  const ElfW(Versym)* get_versym(size_t n) const;
343  ElfW(Addr) get_verneed_ptr() const;
344  size_t get_verneed_cnt() const;
345  ElfW(Addr) get_verdef_ptr() const;
346  size_t get_verdef_cnt() const;
347
348  bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
349
350  uint32_t get_target_sdk_version() const;
351
352  void set_dt_runpath(const char *);
353  const std::vector<std::string>& get_dt_runpath() const;
354  android_namespace_t* get_primary_namespace();
355  void add_secondary_namespace(android_namespace_t* secondary_ns);
356
357  void set_mapped_by_caller(bool reserved_map);
358  bool is_mapped_by_caller() const;
359
360  uintptr_t get_handle() const;
361  void generate_handle();
362  void* to_handle();
363
364 private:
365  bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
366  ElfW(Sym)* elf_addr_lookup(const void* addr);
367  bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
368  ElfW(Sym)* gnu_addr_lookup(const void* addr);
369
370  bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
371                           const char* sym_name, const version_info** vi);
372
373  void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
374  void call_function(const char* function_name, linker_function_t function);
375  template<typename ElfRelIteratorT>
376  bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
377                const soinfo_list_t& global_group, const soinfo_list_t& local_group);
378
379 private:
380  // This part of the structure is only available
381  // when FLAG_NEW_SOINFO is set in this->flags.
382  uint32_t version_;
383
384  // version >= 0
385  dev_t st_dev_;
386  ino_t st_ino_;
387
388  // dependency graph
389  soinfo_list_t children_;
390  soinfo_list_t parents_;
391
392  // version >= 1
393  off64_t file_offset_;
394  uint32_t rtld_flags_;
395  uint32_t dt_flags_1_;
396  size_t strtab_size_;
397
398  // version >= 2
399
400  size_t gnu_nbucket_;
401  uint32_t* gnu_bucket_;
402  uint32_t* gnu_chain_;
403  uint32_t gnu_maskwords_;
404  uint32_t gnu_shift2_;
405  ElfW(Addr)* gnu_bloom_filter_;
406
407  soinfo* local_group_root_;
408
409  uint8_t* android_relocs_;
410  size_t android_relocs_size_;
411
412  const char* soname_;
413  std::string realpath_;
414
415  const ElfW(Versym)* versym_;
416
417  ElfW(Addr) verdef_ptr_;
418  size_t verdef_cnt_;
419
420  ElfW(Addr) verneed_ptr_;
421  size_t verneed_cnt_;
422
423  uint32_t target_sdk_version_;
424
425  // version >= 3
426  std::vector<std::string> dt_runpath_;
427  android_namespace_t* primary_namespace_;
428  android_namespace_list_t secondary_namespaces_;
429  uintptr_t handle_;
430
431  friend soinfo* get_libdl_info();
432};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容