oneself是什么意思 elf是什么意思( 四 )


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产品 , 假设现在面对两种场景:
目标环境的可写磁盘直接mount为 noexec  , 无法执行代码目标环境内核监控任何非系统路径的程序的执行都会直接告警不管什么样的环境 , 我相信老红队都有办法去绕过 , 这里我们运用上面学到的ELF知识 , 其实有一种更为简单的解法 , 即利用interpreter 。示例如下:
$ cat hello.c#include <stdio.h>int main() { return puts("hello!");}$ gcc hello.c -o hello$ ./hellohello!$ chmod -x hello$ ./hellobash: ./hello: Permission denied$ /lib64/ld-linux-x86-64.so.2 ./hellohello!$ strace /lib64/ld-linux-x86-64.so.2 ./hello 2>&1 | grep execexecve("/lib64/ld-linux-x86-64.so.2", ["/lib64/ld-linux-x86-64.so.2", "./hello"], 0x7fff1206f208 /* 9 vars */) = 0/lib64/ld-linux-x86-64.so.2 本身应该是内核调用执行的 , 但我们这里可以直接进行调用 。这样一方面可以在没有执行权限的情况下执行任意代码 , 另一方面也可以在一定程度上避免内核对execve的异常监控 。
利用(滥用)interpreter我们还可以做其他有趣的事情 , 比如通过修改指定ELF文件的interpreter为我们自己的可执行文件 , 可让内核在处理目标ELF时将控制器交给我们的interpreter , 这可以通过直接修改字符串表或者使用一些工具如 patchelf 来轻松实现 。
对于恶意软件分析的场景 , 很多安全研究人员看到ELF就喜欢用 ldd 去看看有什么依赖库 , 一般ldd脚本实际上是调用系统默认的 ld.so 并通过环境变量来打印信息 , 不过对于某些glibc实现(如glibc2.27之前的ld.so) , 会调用ELF指定的interpreter运行 , 从而存在非预期命令执行的风险 。
当然还有更多其他的思路可以进行拓展 , 这就需要大家发挥脑洞了 。
加固/脱壳与逆向分析比较相关的就是符号表 , 一个有符号的程序在逆向时基本上和读源码差不多 。因此对于想保护应用程序的开发者而言 , 最简单的防护 *** 就是去除符号表 , 一个简单的 strip 命令就可实现 。strip删除的主要是Section中的信息 , 因为这不影响程序的执行 。去除前后进行diff对比可看到删除的section主要有下面这些:
$ diff 0 11c1< There are 35 section headers, starting at offset 0x1fdc:---> There are 28 section headers, starting at offset 0x1144:32,39c32<[27] .debug_arangesPROGBITS00000000 00104d 000020 00001<[28] .debug_infoPROGBITS00000000 00106d 000350 00001<[29] .debug_abbrevPROGBITS00000000 0013bd 000100 00001<[30] .debug_linePROGBITS00000000 0014bd 0000cd 00001<[31] .debug_strPROGBITS00000000 00158a 000293 01MS001<[32] .symtabSYMTAB00000000 001820 000480 1033494<[33] .strtabSTRTAB00000000 001ca0 0001f4 00001<[34] .shstrtabSTRTAB00000000 001e94 000145 00001--->[27] .shstrtabSTRTAB00000000 00104d 0000f5 00001其中 .symtab 是符号表 ,  .strtab 是符号表中用到的字符串 。

推荐阅读