防缓冲区溢出工具StackShield分析

StackShield是一个防止缓冲区溢出的工具。主要是通过数组来保存返回地址,避免stack smashing攻击。stack smashing攻击如下图所示。图中展示的是x86下的一个栈帧结构,攻击者利用C语言中不检查数组边界的特点,在往数组局部变量写值的时候,写越界,以特定的值覆盖返回地址,从而达到在程序返回时执行恶意代码的目的。

StackShield的防护思路是,另外开辟一个数组保存返回地址,在函数返回时从数组中恢复返回地址,从而达到保护返回地址的目的,如下图所示。

其程序的主要结构如下所示:

 

 

其主要文件及其相关关系如下所示。

addrcallcheck.h

定义一个全局变量shielddatabase

const char accheader[] =

"#-----------------------------------------\n"

".data\n"

".comm shielddatabase,4,4\n"

"#-----------------------------------------\n";

 

把该全局变量的值与寄存器相比,如果不同,则报错。

const char acccall[] =

"#-----------------------------------------\n"

"       cmpl $shielddatabase,<REGISTER>\n"

"       jbe .LSHIELDCALL<CALLCOUNT>\n"

"       movl $1,%eax\n"

"       movl $-1,%ebx\n"

"       int $0x80\n"

".LSHIELDCALL<CALLCOUNT>:\n"

"#-----------------------------------------\n";

retrangecheck.h

定义一个全局变量shielddatabase

const char rrcheader[] = /* Identical to accheader */

"#-----------------------------------------\n"

".data\n"

".comm shielddatabase,4,4\n"

"#-----------------------------------------\n";

 

把该全局变量的值与寄存器相比,如果不同,则报错

const char rrcepilog[] =

"#-----------------------------------------\n"

"       cmpl $shielddatabase,(%esp)\n"

"       jbe .LSHIELDRETRANGE<EPILOGCOUNT>\n"

"       movl $1,%eax\n"

"       movl $-1,%ebx\n"

"       int $0x80\n"

".LSHIELDRETRANGE<EPILOGCOUNT>:\n"

"#-----------------------------------------\n";

globalretstack.h

定义三个全局变量:retptr,指向返回数组的当前指针;rettop,指向返回地址栈顶的指针;retarray,指向返回数组的指针(栈底);

const char grsheader[] =

"#-----------------------------------------\n"

".data\n"

".comm retptr,4,4\n"

".comm rettop,4,4\n"

".comm retarray,<BUFFSIZE>,4\n"

"#-----------------------------------------\n";

 

如果当前栈指针小于等于栈顶(栈是向下增长),则把当前的返回地址加入到数组中去;

const char grsprolog[] =

"#-----------------------------------------\n"

"        pushl %eax\n"

"        pushl %edx\n"

"        movl retptr,%eax\n"

"        cmpl %eax,rettop\n"

"        jbe .LSHIELDPROLOG<PROLOGCOUNT>\n"

"        movl 8(%esp),%edx\n"

"        movl %edx,(%eax)\n"

".LSHIELDPROLOG<PROLOGCOUNT>:\n"

"        addl $4,retptr\n"

"        popl %edx\n"

"        popl %eax\n"

"#-----------------------------------------\n";

 

如果当前指针小于等于栈顶指针,则把当前指针所指向的值写回栈中;

const char grsepilog[] =

"#-----------------------------------------\n"

"        pushl %eax\n"

"        pushl %edx\n"

"        addl $-4,retptr\n"

"        movl retptr,%eax\n"

"        cmpl %eax,rettop\n"

"        jbe .LSHIELDEPILOG<EPILOGCOUNT>\n"

"        movl (%eax),%edx\n"

"        movl %edx,8(%esp)\n"

".LSHIELDEPILOG<EPILOGCOUNT>:\n"

"        popl %edx\n"

"        popl %eax\n"

"#-----------------------------------------\n";

 

在函数的main入口处,为retptrrettop赋值;

const char grsmainprolog[] =

"#-----------------------------------------\n"

"        movl $retarray,retptr\n"

"        movl $retarray,rettop\n"

"        addl $<BUFFSIZE>,rettop\n"

"#-----------------------------------------\n";

 

检查堆栈中的返回地址是否与当前指针指向的返回地址是否一致,判断其是否被修改

const char grsdetectattackepilog[] =

"#-----------------------------------------\n"

"        pushl %eax\n"

"        pushl %edx\n"

"        addl $-4,retptr\n"

"        movl retptr,%eax\n"

"        cmpl %eax,rettop\n"

"        jbe .LSHIELDEPILOG<EPILOGCOUNT>\n"

"       movl (%eax),%edx\n"

"       cmpl %edx,8(%esp)\n"

"   je .LSHIELDEPILOG<EPILOGCOUNT>\n"

"   movl $1,%eax\n"

"   movl $-1,%ebx\n"

"   int $0x80\n"

".LSHIELDEPILOG<EPILOGCOUNT>:\n"

"        popl %edx\n"

"        popl %eax\n"

"#-----------------------------------------\n";

 

在向当前的retptr中写入当前堆栈返回值的时候,增加检查是否越界的功能(prolog,前序)

const char grsanticrashprolog[] =

"#-----------------------------------------\n"

"        pushl %eax\n"

"        pushl %edx\n"

"   cmpl $0xFFFFFFFF,retptr\n"

"   je .LSHIELDANTICRASHPROLOG<PROLOGCOUNT>\n"

"       movl retptr,%eax\n"

"       cmpl %eax,rettop\n"

"       jbe .LSHIELDPROLOG<PROLOGCOUNT>\n"

"       movl 8(%esp),%edx\n"

"       movl %edx,(%eax)\n"

".LSHIELDPROLOG<PROLOGCOUNT>:\n"

"       addl $4,retptr\n"

".LSHIELDANTICRASHPROLOG<PROLOGCOUNT>:\n"

"        popl %edx\n"

"        popl %eax\n"

"#-----------------------------------------\n";

 

在向当前的retptr中写入当前堆栈返回值的时候,增加检查是否越界的功能(epilog

const char grsanticrashepilog[] =

"#-----------------------------------------\n"

"   cmpl $0xFFFFFFFF,retptr\n"

"   je .LSHIELDEPILOG<EPILOGCOUNT>\n"

"#-----------------------------------------\n";

程序运行分析

程序的选项主要包括以下几类:

1.  -canticrash防止指针越界造成崩溃。

2.  -ddetectattack,当攻击发生时,也就是数组中保存的返回地址和堆栈指针中的返回地址不一致时,终止程序。如果没有这个选项,则直接使用数组的保存的返回地址,而不去计较是否一致。

3.  -faddrcallcheck

4.  –gglobalretstack

5.  –rretrangecheck

6.  –e,指定入口函数,从该函数起,启动返回地址检查机制。 

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值