AndroidLinker与SO加壳技术之下篇

本文详细探讨了Android系统中动态链接库SO的链接过程,包括定位dynamic section、解析dynamic section、加载依赖SO和重定位等步骤。重点分析了重定位的详细过程,解释了如何修复导入符号的引用。此外,文章还介绍了SO加壳技术,探讨了loader执行时机和如何在内存中还原并加载SO。
摘要由CSDN通过智能技术生成

点此查看上篇《AndroidLinker与SO加壳技术之上篇》

2.4 链接

链接过程由 soinfo_link_image 函数完成,主要可以分为四个主要步骤:

1. 定位 dynamic section,
由函数 phdr_table_get_dynamic_section 完成,该函数会遍历 program header,找到为类型为 PT_DYNAMIC 的 header, 从中获取的是 dynamic section 的信息,主要就是虚拟地址和项数。

2. 解析 dynamic section
dynamic section本质上是类型为Elf32_Dyn的数组,Elf32_Dyn 结构如下

typedef struct {

    Elf32_Sword d_tag;      /* 类型(e.g. DT_SYMTAB),决定 d_un 表示的意义*/

    union {

        Elf32_Word  d_val;  /* 根据 d_tag的不同,有不同的意义*/

        Elf32_Addr  d_ptr;  /* 虚拟地址 */

    } d_un;

} Elf32_Dyn;

Elf32_Dyn结构的d_tag属性表示该项的类型,类型决定了dun中信息的意义,e.g.:当d_tag = DT_SYMTAB表示该项存储的是符号表的信息,d_un.d_ptr 表示符号表的虚拟地址的偏移,当d_tag = DT_RELSZ时,d_un.d_val 表示重定位表rel的项数。
解析的过程就是遍历数组中的每一项,根据d_tag的不同,获取到不同的信息。
dynamic section 中包含的信息主要包括以下 3 类:

- 符号信息

- 重定位信息

- init&finit funcs

3. 加载 needed SO
调用 find_library 获取所有依赖的 SO 的 soinfo 指针,如果 SO 还没有加载,则会将 SO 加载到内存,分配一个soinfo*[]指针数组,用于存放 soinfo 指针。

4. 重定位
重定位SO 链接中最复杂同时也是最关键的一步。重定位做的工作主要是修复导入符号的引用,下面一节将对重定位过程进行详细分析。

soinfo_link_image 的示意代码:

static bool soinfo_link_image(soinfo* si, const Android_dlextinfo* extinfo) {

...

    // 1. 获取 dynamic section 的信息,si->dynamic 指向 dynamic section

    phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,

                                   &dynamic_count, &dynamic_flags);

...

    // 2. 解析dynamic section

    uint32_t needed_count = 0;

    for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {

        switch (d->d_tag) {

         // 以下为符号信息

         case DT_HASH:

            si->nbucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[0];

            si->nchain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[1];

            si->bucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8);

            si->chain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8 + si->nbucket * 4);

            break;

         case DT_SYMTAB:

            si->symtab = reinterpret_cast<ElfW(Sym)*>(base + d->d_un.d_ptr);

            break;

         case DT_STRTAB:

            si->strtab = reinterpret_cast<const char*>(base + d->d_un.d_ptr);

            break;

         // 以下为重定位信息

         case DT_JMPREL:

            si->plt_rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr);

            break;

         case DT_PLTRELSZ:

            si->plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值