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


目标环境的可写磁盘直接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 是符号表中用到的字符串 。
仅仅去掉符号感觉还不够,熟悉汇编的人放到反编译工具中还是可以慢慢还原程序逻辑 。通过前面的分析我们知道,ELF执行需要的只是Program Header中的几个段,Section Header实际上是不需要的 , 只不过在运行时动态链接过程会引用到部分关联的区域 。大部分反编译工具,如IDA、Ghidra等,处理ELF是需要某些section信息来构建程序视图的,所以我们可以通过构造一个损坏Section Table或者ELF Header令这些反编译工具出错,从而干扰逆向人员 。
当然,这个方法并不总是奏效,逆向人员可以通过动态调试把程序dump出来并对运行视图进行还原 。一个典型的例子是Android中的JNI动态库,有的安全人员对这些so文件进行了加密处理,并且在 .init/.initarray 这些动态库初始化函数中进行动态解密 。破解这种加固方法的策略就是将其从内存中复制出来并进行重建,重建的过程可根据segment对section进行还原,因为segment和section之间共享了许多内存空间,例如:

推荐阅读