android - 在 Android 6.0 上读取 Elf32 的 PT_DYNAMIC 条目时出现内存访问错误

标签 android c elf dynamic-linking relocation

为了 Hook Android 应用程序的 libc 函数(即 app_process32),我首先读取保存在 /proc/self/maps 中的整个地址空间以及每个加载的 ELF ,我覆盖匹配的重定位条目。

读取一行/proc/self/maps:

Elf32_Addr start, end;
sscanf(line, "%8x-%8x", &start, &end);

然后我通过检查魔法来检查它是否是 ELF。如果它是 ELF,我读取它的 PT_DYNAMIC 段并循环遍历它的条目:

Elf32_Ehdr *ehdr = (Elf32_Ehdr *) start;
Elf32_Phdr *phdr = (Elf32_Phdr *) ((unsigned char *) ehdr + ehdr->e_phoff);
Elf32_Half phnum = ehdr->e_phnum;
Elf32_Addr dynamic = 0;    

for (; phnum > 0; --phnum, ++phdr) {
    if (phdr->p_type == PT_DYNAMIC) {
        dynamic = start + phdr->p_vaddr;
        break;
    }
}

以下是我迭代动态条目的方法:

Elf32_Dyn *dyn;
for (dyn = (Elf32_Dyn *) dynamic; dyn->d_tag; dyn++) {
    Elf32_Addr addr = dyn->d_un.d_ptr;
    Elf32_Sword val = dyn->d_un.d_val;

    switch (dyn->d_tag) {
        // rest of the code.
    }
}

对于某些共享对象来说,这很好,但是对于某些共享对象,我在检查 for 循环条件 dyn->d_tag 时收到 SIGSEGV。为什么 PT_DYNAMIC 指向我无法读取的位置?我还注意到 dynamic 通常是 > end,可以吗?

我使用的设备运行 32 位 Android 6.0。

最佳答案

这个计算:

dynamic = start + phdr->p_vaddr;

仅适用于在地址 0 处链接的 ELF 镜像,这对于共享库和位置无关的可执行文件来说是典型的,但不是必需的。

我猜测您有一些共享库已预先链接到非 0 地址。

该库未预先链接:

readelf -Wl foo.so | egrep 'LOAD|DYNAMIC'
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000684 0x000684 R E 0x200000
  LOAD           0x000e40 0x0000000000200e40 0x0000000000200e40 0x0001e0 0x0001e8 RW  0x200000
  DYNAMIC        0x000e50 0x0000000000200e50 0x0000000000200e50 0x000190 0x000190 RW  0x8

prelink -r 0x120000 foo.so 之后的相同库:

readelf -Wl foo.so | egrep 'LOAD|DYNAMIC'
  LOAD           0x000000 0x0000000012000000 0x0000000012000000 0x000684 0x000684 R E 0x200000
  LOAD           0x000e40 0x0000000012200e40 0x0000000012200e40 0x0001e0 0x0001e8 RW  0x200000
  DYNAMIC        0x000e50 0x0000000012200e50 0x0000000012200e50 0x000190 0x000190 RW  0x8

如果预链接库加载到应用程序的预链接地址 (start==0x12200000),您最终会得到 dynamic == 0x12200e50+0x12200000 这显然是假的。

要解决这个问题,您需要:

dynamic = start + phdr->p_vaddr - first_pt_load->p_vaddr;

其中 first_pt_load 是最低的 PT_LOAD 段(对于非预链接库,其具有 .p_vaddr == 0,并且 0x12000000 对于预链接的)。

关于android - 在 Android 6.0 上读取 Elf32 的 PT_DYNAMIC 条目时出现内存访问错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55180723/

相关文章:

android - 未处理的异常 : NoSuchMethodError while setting values in setter in Model class

我可以看到 init 和 ctors 中的函数吗

c++ - 指向不同类型的指针

linux-kernel - ebpf 加载器之间的主要区别

c - 函数 "main"的代码在目标文件中的哪里开始?

php - 用于连接 MySQL 数据库的 PHP 文件放置的正确位置是什么

android - onCellLocationChanged 的​​问题

android - 带有对话框 fragment 的 tabview android.view.WindowManager$BadTokenException :

c - 为什么会出现浮点异常

c - 为数的质因数找到更好的算法