ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ctf-wiki ELF 符号表(.symtab / Elf32_Sym)深度解析:从结构定义到符号解析与定位

ctf-wiki ELF 符号表(.symtab / Elf32_Sym)深度解析:从结构定义到符号解析与定位 文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载导读本文基于 ctf-wiki 仓库 ELF 文件结构 · 符号表 一文展开系统讲解 Linux ELF 目标文件中符号表Symbol Table的数据结构、字段语义、符号类型与绑定规则并串联仓库中与之配套的 节区总览、ELF 基础信息、字符串表 与 动态链接节区 等内容。读完本文你将能看懂readelf输出的符号表条目理解st_value、st_info、st_shndx三个关键字段在不同目标文件类型下的真实含义并能依据sh_link与st_name手动定位任意符号对应的名字字符串。符号表链接过程中的粘合剂熟悉编译原理的读者会知道编译程序时必须有一套结构来管理程序中的符号以便对函数和变量进行重定位。ELF 目标文件中的**符号表Symbol Table**正是承担这一职责的核心结构。链接的本质就是把多个不同的目标文件相互粘在一起。实际上目标文件相互粘合的过程就是目标文件之间对地址的引用——即函数和变量的地址的相互引用。而在粘合过程中符号就是其中的粘合剂一个文件中对某符号的引用通过链接器与另一个文件中该符号的定义建立联系最终被解析为具体的地址。需要特别注意的是目标文件中的符号表包含了一些通用的符号这部分信息在进行了strip操作后就会消失。这些符号信息可能包括变量名、函数名即编译期非运行期的调试与链接辅助信息。在 ctf-wiki 的 ELF 文件结构 文档中节区被归类为SHT_SYMTAB值 2包含符号表与SHT_DYNSYM值 11动态链接符号表两种类型二者使用的数据结构相同Elf32_Sym/Elf64_Sym但用途与生命周期不同节区类型生命周期说明.symtabSHT_SYMTAB编译期保存完整符号信息strip后消失.dynsymSHT_DYNSYM运行期动态链接所需的符号最小集合运行期保留本节区的更多背景可参考仓库中的 Sections 总览 与 Dynamic Sections。符号表的数据结构Elf32_Sym符号表可以被视为一个数组数组中的每一个元素都是一个结构体。以 32 位为例每个符号表项的 C 定义如下typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym;每个字段的含义如下字段说明st_name符号在字符串表中对应的索引。如果该值非 0则它表示了给出符号名的字符串表索引否则符号表项没有名称。注外部 C 符号在 C 语言和目标文件的符号表中具有相同的名称。st_value给出与符号相关联的数值具体取值依赖于上下文可能是一个正常的数值、一个地址等等。st_size给出对应符号所占用的字节大小。如果符号没有大小或者大小未知则此成员为 0。st_info给出符号的类型和绑定属性低 4 位为类型高 4 位为绑定。之后会给出若干取值和含义的绑定关系。st_other目前主要承载符号的可见性visibility信息取 0 表示默认可见。st_shndx如果符号定义在该文件中那么该成员为符号所在节在节区头部表中的下标如果符号不在本目标文件中或者对于某些特殊的符号该成员具有一些特殊含义。其中符号表中下标 0 存储了符号表的一个特殊元素它作为所有未定义符号的索引具体取值如下名称取值说明st_name0无名称st_value00 值st_size0无大小st_info0无类型局部绑定st_other0无附加信息st_shndx0无节区这一第 0 项的约定与节区头部表索引 0SHN_UNDEF的约定一致——在 basic-info.md 中可以看到索引 0 的节头同样作为未定义节区引用的占位项存在因此符号表下标 0 的元素天然表示未定义符号。st_value符号值在不同上下文中的含义在 Linux 的 ELF 文件中st_value的具体解释取决于符号的种类该符号对应着一个变量那么st_value表明该变量在内存中的偏移。我们可以由这个值获取其文件偏移具体步骤为获取该符号对应的st_shndx进而获取到相关的节区根据节区头元素可以获取节区的虚拟基地址和文件基地址计算关系为value - 内存基虚拟地址 文件偏移 - 文件基地址即文件偏移 value - 节区虚拟基地址 节区文件基地址。该符号对应着一个函数那么st_value表明该函数在文件中的起始地址。此外不同的目标文件类型对st_value的解释也不同这一点在 ctf-wiki 的符号取值一节有明确说明在可重定位文件中st_value保存了节区索引为SHN_COMMON的符号的对齐约束在可重定位文件中st_value保存了已定义符号的节区偏移即st_value保留了从st_shndx所标识节区的头部到符号位置的偏移在可执行文件和共享目标文件中st_value包含一个虚拟地址。为了使这些文件中的符号对动态链接器更有用节区偏移针对文件的解释给出了与节区号无关的虚拟地址针对内存的解释。也就是说同一个st_value在.o文件中是相对节区的偏移而在链接完成后的可执行文件中则变成了最终的虚拟地址。这也是在逆向分析如 ctf-wiki 的 PWN / 逆向 方向中读取 ELF 符号时必须区分文件类型的根本原因。st_info符号类型与绑定st_info一个字节同时编码了两类信息符号类型Symbol Type与符号绑定Symbol Binding。ELF 规范提供了如下宏来拆分与构造该字段#define ELF32_ST_TYPE(i) ((i)0xf) #define ELF32_ST_INFO(b, t) (((b)4) ((t)0xf)) #define ELF32_ST_BIND(i) ((i)4)即低 4 位是类型高 4 位是绑定ELF32_ST_INFO(b, t)用于在构造符号时把绑定b与类型t合成一个字节。Symbol Type低 4 位名称取值说明STT_NOTYPE0符号的类型没有定义。STT_OBJECT1符号与某个数据对象相关比如一个变量、数组等等。STT_FUNC2符号与某个函数或者其他可执行代码相关。STT_SECTION3符号与某个节区相关。这种类型的符号表项主要用于重定位通常具有 STB_LOCAL 绑定。STT_FILE4一般情况下符号的名称给出了生成该目标文件相关的源文件的名称。如果存在的话该符号具有 STB_LOCAL 绑定其节区索引是 SHN_ABS 且优先级比其他 STB_LOCAL 符号高。STT_LOPROCSTT_HIPROC13~15保留用于特定处理器。共享目标文件中的函数符号比较特殊当另一个目标文件从共享目标文件中引用一个函数时链接器自动为被引用符号创建过程链接表PLT项。共享目标中除了STT_FUNC其它符号将不会通过过程链接表自动被引用。如果一个符号的值指向节内的特定位置则它的节索引号st_shndx包含了它在节头表中的索引。当一个节在重定位过程中移动时该符号值也做相应改变对该符号的引用继续指向程序中的相同位置。有些特定节索引值具有其他语义见下文st_shndx一节。Symbol Binding高 4 位ELF32_ST_BIND(i)取st_info的高 4 位这部分信息确定了符号的链接可见性及其行为名称取值说明STB_LOCAL0表明该符号为局部符号在包含该符号定义的目标文件以外不可见。相同名称的局部符号可以存在于多个文件中互不影响。STB_GLOBAL1表明该符号为全局符号对所有将被组合在一起的目标文件都是可见的。一个文件中某个全局符号的定义将满足另一个文件对相同全局符号的未定义引用。我们称初始化非零变量的全局符号为强符号只能定义一次。STB_WEAK2弱符号与全局符号类似不过它们的定义优先级比较低。STB_LOPROC STB_HIPROC13这个范围的取值保留给处理器专用语义。补充说明在每个符号表中所有具有STB_LOCAL绑定的符号都优先于弱符号和全局符号。符号表节区头部的sh_info成员即包含第一个非局部符号的符号表索引——这一点在 basic-info.md 的sh_link sh_info表格中有所体现对SHT_SYMTAB/SHT_DYNSYM类型的节区sh_link指向符号名字符串表Linux 下通常为.strtab/.dynstr在 Section Header Table 中的索引sh_info则保存首个非局部符号的下标。此外全局符号与弱符号的主要区别如下当链接器在链接多个可重定位目标文件时不允许定义多个相同名字的STB_GLOBAL符号。另一方面如果存在一个已定义全局符号则同名的弱符号的存在不会引起错误链接器会优先选择全局定义忽略弱符号定义。类似地如果一个公共符号存在st_shndx域为SHN_COMMON的符号则同名的弱符号的存在不会引起错误链接器会选择公共定义忽略弱符号定义。当链接器寻找文件库时它会提取包含未定义全局符号的成员可能是一个全局符号或者弱符号。链接器不会为了解未定义弱符号的问题而提取文件未定义的弱符号的值为 0。st_other符号可见性原文档指出st_other目前为 0、其含义未被定义这是早期 ELF 规范的表述。在 glibc ≥ 2.2 的 Linux 实现中st_other的低 2 位已被用于承载符号可见性Symbol VisibilitySTV_DEFAULT(0)、STV_INTERNAL(1)、STV_HIDDEN(2)、STV_PROTECTED(3)。例如 dynamic-sections.md 中.dynsym的Elf32_Sym定义就明确将st_other注释为 Symbol visibility under glibc2.2。可见性会影响动态链接器在跨模块符号解析时的行为例如STV_HIDDEN符号不会被导出到动态符号表之外。st_shndx节区索引与特殊值st_shndx给出符号定义所在节区在 Section Header Table 中的下标。除了普通的节区下标外以下特殊索引具有独立语义名称取值说明SHN_ABS0xfff1符号的取值具有绝对性不会因为重定位而发生变化。SHN_COMMON0xfff2符号标记了一个尚未分配的公共块。符号的取值给出了对齐约束与节区的 sh_addralign 成员类似。也就是说链接编辑器将在地址位于 st_value 的倍数处为符号分配空间。符号的大小给出了所需要的字节数。SHN_UNDEF0此索引值表示符号没有定义。当链接编辑器将此目标文件与其他定义了该符号的目标文件进行组合时此文件中对该符号的引用将被链接到实际定义的位置。在更完整的节头特殊下标表中见 basic-info.md还有SHN_LORESERVE0xff00保留索引值范围下界、SHN_LOPROC0xff00、SHN_HIPROC0xff1f处理器相关范围、SHN_HIRESERVE0xffff保留索引值范围上界等取值系统保留SHN_LORESERVE到SHN_HIRESERVE之间的索引值它们不在节头表中引用。如何定位符号对应的字符串符号表中存储的并不是符号名的字符串本身而只是一个字符串表索引st_name。那么对于一个符号如何定位其对应字符串的地址呢具体步骤如下找到符号字符串节区根据 Section Header Table 中符号节头SHT_SYMTAB/SHT_DYNSYM的sh_link成员获取该符号节中对应符号字符串节通常为.strtab/.dynstr在 Section Header Table 中的下标进而获取对应字符串节区的地址。获取符号名偏移根据该符号定义中的st_name获取该符号名的偏移即符号名在对应字符串节中的偏移。拼接定位将字符串节的起始地址与st_name偏移相加即可定位一个符号对应的字符串以NULL结尾的地址。这一机制与 字符串表String Sections 文档的描述完全对应.strtab保存默认字符串表包含以NULL结尾的字符串变量名、函数名字符串表首尾字节都是NULL索引 0 的字符串要么没有名字、要么名字为空字符串可以通过其在字符串表中的首字母下标来索引且索引可以引用节区中的任意字节、可以存在对子字符串的引用、同一个字符串可被引用多次。.shstrtab与.strtab存储结构类似但它存储的是节区名的字符串由 ELF 头的e_shstrndx成员给出索引。在动态链接场景下这一查找过程被动态链接器实际使用_dl_fixup中先通过D_PTR(l, l_info[DT_SYMTAB])获取动态符号表再通过D_PTR(l, l_info[DT_STRTAB])获取动态字符串表随后以strtab sym-st_name取得符号名字符串并交给_dl_lookup_symbol_x做符号查找——完整调用链见仓库中的 Symbol Resolve 一文。符号查找的加速结构符号哈希表对于需要快速按名字查找符号的动态链接过程ELF 还提供了符号哈希表Symbol Hash Table来加速访问。其核心是一个由Elf32_Word构成的表bucket数组包含nbucket个元素chain数组包含nchain个元素二者都保存符号表索引且chain数组元素与符号表元素一一对应因此符号表元素个数必须与nchain相同。查找流程为哈希函数对符号名计算出一个值x取bucket[x % nbucket]得到一个符号表索引y若该索引对应的符号不是目标符号则继续沿chain[y]依次向下一个同哈希值的符号索引查找直到找到目标符号或遇到值为STN_UNDEF的链项。该图与相关说明详见 Misc Sections 文档GNU 还提供了性能更优的.gnu.hash变体。实践视角用 readelf / nm 观察符号表理解了Elf32_Sym的结构后可以使用标准工具验证上述概念以下命令为 Linux 下通用操作与仓库文档互为印证readelf -s hello.o # 查看可重定位文件的 .symtab注意 st_value 为节区偏移 readelf -s /bin/ls # 查看可执行文件的 .symtab readelf --dyn-syms /bin/ls # 仅查看动态符号表 .dynsym readelf -S hello.o # 查看节区头核对 .symtab 的 sh_link / sh_info nm hello.o # 以更友好的形式列出符号及类型T/D/B/U 等 strip hello.o readelf -s hello.o # 观察 strip 后 .symtab 消失观察要点可重定位文件中全局函数符号的st_value是其在.text节内的偏移而可执行文件中则已是虚拟地址——对应上文符号取值部分的三条规则readelf -S输出中.symtab一行的Link列指向.strtabInfo列给出第一个非局部符号的索引——对应sh_link/sh_info的语义对可执行文件执行strip后.symtab与.strtab被移除但运行期动态链接所需的.dynsym/.dynstr会保留程序仍可正常运行。小结ELF 符号表是链接与动态加载的枢纽Elf32_Sym以紧凑的 16 字节32 位结构编码了符号名索引st_name、符号值st_value、大小st_size、类型与绑定st_info、可见性st_other以及定义所在节区st_shndx。理解st_value在可重定位文件与可执行文件中的不同解释、st_info的类型/绑定编码、SHN_ABS/SHN_COMMON/SHN_UNDEF三个特殊节索引以及通过sh_linkst_name定位符号名的三步流程是阅读 ELF、进行逆向分析和理解动态链接机制的基础。本仓库 ELF 结构 系列文档Sections、Code Sections、String Sections、Dynamic Sections、Misc Sections提供了完整的上下文可作为进一步学习的入口。赞分享文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载相关推荐ctf-wiki 详解 ELF 动态链接符号解析从 _dl_runtime_resolve 到 _dl_fixup 的完整链路ctf wiki 详解 ELF 动态链接符号解析从 _dl_runtime_resolve 到 _dl_fixup 的完整链路 导读本文以 ctf wiki文档网络安全教程ELF 字符串表节区.strtab / .shstrtab / .dynstr深度解析符号名索引机制与节区定位原理ELF 字符串表节区.strtab / .shstrtab / .dynstr深度解析符号名索引机制与节区定位原理 本文以 ctf wiki 仓库中 EL文档网络安全教程ctf-wiki 内核调试指南System.map 符号表解析与 stripped vmlinux 符号恢复实战ctf wiki 内核调试指南System.map 符号表解析与 stripped vmlinux 符号恢复实战 本文是 ctf wiki 中「Linux 内文档网络安全教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表