关于Windows安全保护机制——栈守护天使GS的问题

首先,这次记录的是GS栈守护机制的一些理解和问题,并不是基于栈守护的原理,去做相关的突破和溢出,所以如果发现主题不对,还请及时退出,避免浪费您的时间。当然如果您不介意 给我看看哪里有出错的地方,也欢迎给出意见

————————————————————分割线—————————————————————
我们都知道,所谓的缓冲区溢出的最重要的一个点就是,将返回地址覆盖为Shellcode执行的地址,也就是说返回地址的覆盖是必经的一步,微软为了针对栈溢出的之一特征,专门在编译程序的时候提供了一个安全的编译选项——GS,(需要注意这里的GS不是64位下的GS段寄存器)这个安全编译选项在VS里边的属性里边可以看到(我的环境是VS2008):
在这里插入图片描述
为什么说GS机制是微软提供的以想对抗栈溢出的编译机制呢?我们知道,在一般的程序中缓冲区、EBP、返回地址是在一起的,在栈溢出的时候,只要向下淹没,就会将返回地址替换,然后再执行retn指令的时候,跳转到ShellCode的执行处,但是与之不同的是,GS这个编译机制,会在缓冲区之后向栈中压入一个随机的双字节的数据,我们称之为“SecurityCookie”,"SecurityCookie"的位置决定了如果想要正常的实施栈溢出就必然会淹没“SecurityCookie”,但是GS的编译机制这个时候就起作用了,在调用别的函数的时候,执行返回指令之前,GS机制都会引导,函数先去做一个校验,我们称校验的这个过程为“SecurityCheck”,顾名思义就是对“SecurityCookie”进行校验,判断“SecurityCookie”有没有发生改变,如果产生改变那么就证明发生了栈溢出事件,此时程序不会直接去执行原来的返回指令(也就是不会跳到ShellCode的地方),而是会触发异常,以此来避免栈溢出的产生。原理图如下:
正常编译情况下的栈溢出
在这里插入图片描述
GS安全编译机制下的栈溢出
在这里插入图片描述
在GS安全编译机制下编译的程序,会看到,在EBP和返回地址之前会插入一个随机数,这个随机数我们称之为SecurityCookie,在栈溢出之后,SecurityCookie很明显也会被修改,而我们的SecurityCookie会在此之前存放到.data段来存放一个SecurityCookie的副本,在栈溢出之后,进行SecurityCheck的时候会利用.data段的这个副本去对SecurityCookie进行比较,如果比较发现数据被修改,则说明产生了栈溢出,那么就会触发异常。这样就避免了栈溢出的攻击。

***取消GS安全编译选项:***在使用VS进行程序编译的时候,还是打开上边的属性对话框,把GS(缓冲区安全检查修改为是就好了),但是这个时候你可以编写一个简单的程序,放到IDA里边反汇编查看一下,会发现还是有SecurityCookie的代码,之前在这个如何取消GS的问题上有点纠结,但是后来用OD动态调试的时候,发现 在选择了GS缓冲区安全检查了之后,动态调试,在main函数里边调用另一个函数的时候,在这个函数在执行返回指令之前,会跳转到另一个函数里边,也就是我们之前说的SecurityCheck,但是在取消勾选GS的时候,用IDA直接反汇编看,你还是会看到SecurityCookie的代码,但是在用OD动态调试的时候,会发现函数调用之后是直接返回的,不会进行SecurityCheck的操作。因此,在编译的时候取消GS选项其实是已经关闭了缓冲区安全检查的,这也就是从另一个方面再一次解释了GS到底是什么?GS 编译选项为每个函数调用增加了一些额外的数据和操作,用以检测栈中的溢出
也就是说,是否存在GS机制(缓冲区安全检查),只需要看在函数调用执行过程中是否在栈中压入SecurityCooike,以及是否去执行了SecurityCheck/

**GS机制的限制;**由于相较于一般的函数调用产生了额外的数据和操作,所以导致性能相较有所下降,这也就导致了GS机制本身有他的限制,以下几种情况,系统不会在函数调用的时候应用GS机制:
1、函数不包含缓冲区(这个很好验证,在开启GS的情况下,写一个简单的加法调用,就可以进行验证,确实是没有GS检查的)
2、函数被定为具有变量参数列表
3、函数使用无保护的关键字标记
4、函数在第一个语句包含内嵌汇编代码
5、缓冲区不是8字节类型或者小于4字节
当然考虑到这些情况,微软也专门提供了一条语句来避免这些例外情况:(专门用来为不符合GS添加条件的函数添加GS检查)

#pragma strict gs check

添加了这句代码之后,就可以为任意一个函数添加SecurityCookie

上边说的几种例外中的第三个 函数使用无保护的关键字标记的意思是,在定义函数的时候使用__declspec(safebuffers)关键字对函数进行标记,具体用法如下:

https://docs.microsoft.com/en-us/cpp/cpp/safebuffers?view=vs-2019

当然,在各个版本里边GS保护机制的调整也有所不一样的地方,但是大致的原理是相同的,在VS2005之后的版本,在开启GS之后,还会在栈上边调整缓冲区的位置,以及将函数的参数备份,防止在函数调用的时候产生栈溢出将函数的参数覆盖掉。

SecurityCookie生成的过程
1、系统用.data节的第一个双字(DWORD)作为原始Cookie(程序涉及到的所有的函数的Cookie都是用这个种子生成的)(这个需要注意,不一样的版本,在Cookie生成的过程中,选择的种子很可能不一样,组要根据版本去具体判断)
2、在每一次运行的时候,产生的Cookie都是不一样的,这样大大确保了Cookie的随机性
3、在栈帧初始化之后,系统用当前的ESP去和Cookie异或来生成SecurityCookie,同时每一个函数的SecurityCookie都是不相同的
4、在函数返回前,完成SecurityCheck之后,系统用ESP将原来的Cookie种子再还原出来,以便下一个函数使用

GS的不足
GS机制本身作为一种安全保护策略,在直接性的对抗GS的时候确实不太好冲出,但是它本市的机制也就导致有很大的不足之处。我们都知道,GS是基于栈的保护机制,因此对于堆溢出的漏洞和攻击GS就没有办法了,同时GS对于基于异常的攻击也会表示无能为力。

这篇文章,需要感谢@Angelki对于我问题的解答

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值