在运行时定位 ELF 共享库导出
Locating ELF shared library exports at runtime
是否可以仅使用其内存映像提取已加载共享库的导出符号?
我说的是 .dynsym 部分中列出的符号。据我了解,我们可以这样做:
定位库的基地址。
例如通过读取/proc/<pid>/maps
可以找到内存区域它们是从磁盘上的库映射的,然后我们可以查找 ELF 魔法字节来找到 ELF header,它给了我们基地址。
从程序headers中找到PT_DYNAMIC段。
解析ELFheader,然后遍历程序 headers 以找到包含 .dynamic 部分的段。
提取动态符号的位置 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_HASH
或DT_GNU_HASH
)中推断出来:this answer给出了一些代码这样做的。
标准散列 table(不再用于 GNU 系统)是 quite simple。第一个条目是 nchain
即:
The number of symbol table entries should equal nchain
GNU 哈希 table 更复杂。
是否可以仅使用其内存映像提取已加载共享库的导出符号?
我说的是 .dynsym 部分中列出的符号。据我了解,我们可以这样做:
定位库的基地址。
例如通过读取/proc/<pid>/maps
可以找到内存区域它们是从磁盘上的库映射的,然后我们可以查找 ELF 魔法字节来找到 ELF header,它给了我们基地址。从程序headers中找到PT_DYNAMIC段。
解析ELFheader,然后遍历程序 headers 以找到包含 .dynamic 部分的段。提取动态符号的位置 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_HASH
或DT_GNU_HASH
)中推断出来:this answer给出了一些代码这样做的。
标准散列 table(不再用于 GNU 系统)是 quite simple。第一个条目是 nchain
即:
The number of symbol table entries should equal
nchain
GNU 哈希 table 更复杂。