在运行时定位 ELF 共享库导出

Locating ELF shared library exports at runtime

是否可以仅使用其内存映像提取已加载共享库的导出符号?

我说的是 .dynsym 部分中列出的符号。据我了解,我们可以这样做:

  1. 定位库的基地址。
    例如通过读取/proc/<pid>/maps可以找到内存区域它们是从磁盘上的库映射的,然后我们可以查找 ELF 魔法字节来找到 ELF header,它给了我们基地址。

  2. 从程序headers中找到PT_DYNAMIC段。
    解析ELFheader,然后遍历程序 headers 以找到包含 .dynamic 部分的段。

  3. 提取动态符号的位置 table。
    迭代 ElfN_Dyn 结构以找到d_tags DT_STRTAB 和 DT_SYMTAB。这些将为我们提供字符串 table(带有符号名称)和动态符号 table 本身的地址。

这就是我跌跌撞撞的地方。 .dynamic 部分有一个标记为字符串的大小 table (DT_STRSZ),但没有指示符号 table 的大小。它仅包含单个条目的大小 (DT_SYMENT)。如何检索 table?

中的符号条目数

.dynsym 部分的大小应该可以推断出这一点,但是ELF 文件在内存中表示为段。 table段不需要加载到内存中,只能通过读取相应的文件来(可靠地)访问。

我相信这是可能的,因为动态链接器必须知道符号的大小table。但是,动态加载器可能在加载文件时将其存储在某处,而链接器只是使用缓存的值。虽然将符号 table 加载到内存中似乎有些愚蠢,但不要加载少量字节及其大小。

动态符号的大小table必须从符号散列table(DT_HASHDT_GNU_HASH)中推断出来:this answer给出了一些代码这样做的。

标准散列 table(不再用于 GNU 系统)是 quite simple。第一个条目是 nchain 即:

The number of symbol table entries should equal nchain

GNU 哈希 table 更复杂。