elf是什么意思 elf是什么意思英语( 四 )


为什么要这么做呢?如果把动态链接相关的代码也放到内核中,就会导致内核执行功能过多 , 内核的理念一直是能不在内核中执行的就不在内核中处理,以避免出现问题时难以更新而且影响系统整体的稳定性 。事实上内核中对ELF文件结构的支持是相当有限的,只能读取并理解部分的字段 。
用户空间内核返回用户空间后,对于静态链接的程序是直接执行,没什么好说的 。而对于动态链接的程序,实际是执行interpreter的代码 。ELF的interpreter作为一个段,自然是编译链接的时候加进去的,因此和编译使用的工具链有关 。对于Linux系统而言,使用的一般是GCC工具链 , 而interpreter的实现,代码就在glibc的 elf/rtld.c 中 。
interpreter又称为dynamic linker , 以glibc2.27为例,它的大致功能如下:
将实际要执行的ELF程序中的内存段加载到当前进程空间中;将动态库的内存段加载到当前进程空间中;对ELF程序和动态库进行重定向操作(relocation);调用动态库的初始化函数(如 .preinit_array, .init, .init_array );将控制流传递给目标ELF程序,让其看起来自己是直接启动的;其中参与动态加载和重定向所需要的重要部分就是Program Header Table中 PT_DYNAMIC 类型的Segment 。前面我们提到在Section Header中也有一部分参与动态链接的section,即 .dynamic。我在自己解析动态链接文件的时候发现,实际上 .dynamic section中的数据 , 和 PT_DYNAMIC 中的数据指向的是文件中的 同一个地方 ,即这两个entry的s_offset和p_offset是相同 。每个元素的类型如下:
typedef struct{Elf32_Sword d_tag;/* Dynamic entry type */union{Elf32_Word d_val;/* Integer value */Elf32_Addr d_ptr;/* Address value */} d_un;} Elf32_Dyn;d_tag表示实际类型,并且d_un和d_tag相关,可能说是很有拓展性了:) 同样的,标准中定义了几十个d_tag类型,比较常用的几个如下:
DT_NULL: 表示_DYNAMIC的结尾DT_NEEDED: d_val保存了一个到字符串表头的偏移,指定的字符串表示该ELF所依赖的动态库名称DT_STRTAB: d_ptr指定了地址保存了符号、动态库名称以及其他用到的字符串DT_STRSZ: 字符串表的大小DT_SYMTAB: 指定地址保存了符号表DT_INIT/DT_FINI: 指定初始化函数和结束函数的地址DT_RPATH: 指定动态库搜索目录DT_SONAME: Shared Object Name,指定当前动态库的名字( logical name )其中有部分的类型可以和Section中的 SHT_xxx 类型进行类比 , 完整的列表可以参考ELF标准中的 Book III: Operating System Specific 一节 。
在interpreter根据 DT_NEEDED 加载完所有需要的动态库后,就实现了完整进程虚拟内存映像的布局 。在寻找某个动态符号时,interpreter会使用 广度优先 的方式去进行搜索,即先在当前ELF符号表中找,然后再从当前ELF的 DT_NEEDED 动态库中找 , 再然后从动态库中的 DT_NEEDED 里查找 。
因为动态库本身是位置无关的(PIE),支持被加载到内存中的随机位置,因此为了程序中用到的符号可以被正确引用 , 需要对其进行重定向操作 , 指向对应符号的真实地址 。这部分我在之前写的关于GOT,PLT和动态链接的文章中已经详细介绍过了,因此不再赘述 , 感兴趣的朋友可以参考该文章 。
实际案例有人也许会问,我看你bibi了这么多,有什么实际意义吗?呵呵,本节就来分享几个我认为比较有用的应用场景 。
Interpreter Hack在渗透测试中 , 红队小伙伴们经常能拿到目标的后台shell权限,但是遇到一些部署了HIDS的大企业,很可能在执行恶意程序的时候被拦截,或者甚至触发监测异常直接被蓝队拔网线 。这里不考虑具体的HIDS产品,假设现在面对两种场景:

推荐阅读