欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

防御代码重用攻击的一个简单方案

来源:本站整理 作者:佚名 时间:2020-02-11 TAG: 我要投稿

代码重用攻击的顺利进行需要两个必不可少的条件:
通过某种方式劫持程序控制流。
获取内存中目标代码片段的位置信息。
对于代码重用攻击的防御必须立足于这两个环节,务必至少破坏其中之一,才能阻止攻击的进行。
针对这一点,我实施了将进程空间中非必须的指令用空指令,也即0x90覆盖掉这一简单的保护方案(以下称为程序运行时裁剪)。这一保护方案立足于阻止代码重用攻击对目标程序内存中代码片段位置信息的准确获取,进而阻止攻击。要处理和解决的问题主要有:
1   程序函数依赖的静态分析
2   动态链接器的修改和重编译
 
方案的设计与实现
当前Linux系统中普遍使用Glibc所提供的动态链接器ld.so来实施对可执行程序的装载。同时GNU Binutils套件中诸如objdump,readelf等强大的二进制文件处理工具为方案的具体实施提供了强有力的工具。
方案的总体流程图如下:

 
程序的静态分析
静态分析关注ELF文件。它保存了足够多的信息。
ELF文件中储存有其所需的动态链接库信息和其所使用的动态链接器相关信息。

后续我们必须修改目标程序ELF文件的相应位置,使其使用新的动态链接器进行装载。
 
静态分析的整体思路
对目标程序进行静态分析的思路可以归纳为以下几点:
对程序本体ELF文件进行分析,得出其依赖的动态链接库和第一层调用所涉及的库函数。
在程序所依赖的动态链接库中寻找第一层所调用的库函数,记录其位置信息,包括动态链接库名称,和在对应动态链接库内的相对位移。
以上两步得到的信息为起点,在相应的动态链接库内递归地寻找依赖的函数,并记录相关信息,直到不再有新的信息出现,完成程序运行所必需的函数的定位。
 
具体分析规则的编写
必须明确要从对目标程序的静态分析中获取的信息有哪些,如何获取,定义存储这些信息的数据结构等等,为后续的进一步处理提供支持。对目标程序进行静态分析时,就必须获取目标程序所依赖的函数的相关信息,包括函数所在的动态链接库名称和其在对应动态链接库内的相对位置。
A  第一层调用的库函数
目标程序第一层调用的库函数往往是显式的出现在程序的源码中,如以下示例代码toy.c:
#include  
int main() 

    char *s="hello"; 
    printf("string is %s\n",s); 
    return 0; 

很明显,其调用的第一层库函数为printf ()函数。
nm命令主要是用来列出某些文件中的符号表(包括一些函数和全局变量等),以下是nm命令的一个典型输出:

我们关心的库函数则以U为输出的标志,因此,只需对nm命令的输出结果做以下处理,就可以得到第一层调用的库函数。
nm toy | grep –w U | awk '{printf $2 "\n"}'
对toy执行该命令的输出结果如下:

B 在动态链接库内递归寻找函数
首先要先在动态链接库中定位到第一层库函数。
ELF文件中所存储着的有可能不是函数真正的“名字”。比如说,printf ()函数,其在对应的动态链接库libc.so.6中实际上是_IO_printf函数,类似的对应还有很多。所以在定位第一层调用的库函数时,必须建立这样一个函数名的映射关系。在相应的动态链接库中递归地去寻找时,处理的都是真正的函数名,无需再进行函数名的映射。
本文编写shell脚本,利用Linux自带的工具进行相关处理。该脚本的核心在于两个函数的编写,以及这两个函数之间调用关系的精心组织:
getaddr函数:
getaddr(){
flag=`grep -w  "$1" $2`
out=$2
out=${out%a*}"protect"
if [ -n "$flag" ];then
grep -w  "$1" $2|awk '{print $2 " " $3}' >>"$out"
fi
}
getaddr取得函数的开始和结束位置,参数为函数名,”所在库名__addr”,将结果保存至“所在库名_protect”文件中,留待提供给动态链接器进行相应处理。
getfunc函数:
getfunc(){
start=`grep -no $1 $3| cut -d ":" -f 1`
end=`grep -no $2 $3| cut -d ":" -f 1`
let n=$end-$start-1
funcs=$(grep -A $n -P "$1.*>:" $3 | grep -Po '(?)')
for func in $funcs
do
{
#处理形如型数据
if [[ $func =~ "+" ]];then
func=${func%+*}
fi
func="$func">"
printf "$func\n"
}
done
}
getfunc取得某个函数中依赖的其他函数名,参数为函数起、始地址和所在库名。
工作模式是:以获取到的第一层调用库函数为起点,根据函数名,先使用getaddr函数获取所有第一层调用的函数的开始和结束位置。将得到的函数开始和结束位置为参数,在相应的动态链接库中调用getfunc函数得到该函数所依赖的其他函数,将之作为参数,传递给getaddr函数,如此不断进行下去,直到没有新的函数信息被添加进来。
我们以以下libc.so.6的反汇编结果来看:

[1] [2] [3] [4] [5]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载