从研究底层和汇编以来,已经多次接触到“栈溢出”这个名词了。

这次在汇编码中看到了个不明就里的 ___security_cookie ,查了下,原来是编译器的安全检查机制。转载一篇文章:

首先,security cookie并不是windows系统自带的保护机制,并不是说一个确实存在溢出漏洞的
程序,放到带security cookie保护的环境中,就不能正常溢出了。
那么,到底是什么是security cookie呢?
我觉得从广义上讲,它应该是一种保护栈的机制,提供这种保护的,是程序本身,编译进程序本身的
代码提供的,而不是系统中某个运行在黑暗角落中的线程。
所以,既然是程序自身就带上的,为了不给程序员带来额外的负担,这份工作就交给编译器来完成了。
vc6.0的cl.exe是不带这个功能的,只有vc.net以后面版本的cl.exe才带这个功能,就所谓的/GS选项。
即用vc.net的cl编译器时,/GS选项默认就打开了。
现在,我们知道了这个机制的提供方,那么,这个机制到底是怎么一回事呢?
熟悉函数调用及返回前后的汇编指令的人肯定很清楚,在win32平台,对于stdcall类型的函数调用,
当call指令运行完毕,当前的堆栈结构基本上是这样的:

局变2  ebp-8   低地址

局变1  ebp- 4
ebp  ebp
返回地址 ebp+4
参数1  ebp+8
参数2  ebp+c
参数3  ebp+10
参数4  ebp+14   高地址

第一列是堆栈中存放的dword的内容,第二列是用ebp作为栈地址的索引时,它对应的应该用ebp表示的值,

说得形象一点,ebp中存放着栈的一个地址(栈其实也是一片内存,ebp只是指向其中一个对当前函数内部比较
重要的地址,其实是相当重要),栈的其它位置都是通过这个ebp来寻址的,即我们给函数的第一个形参的
地址,就是ebp+8,第二个就是ebp+c,我们定义的局部变量的地址,第一个局部变量是ebp-4,第二局部变量的
地址就是ebp-8,依此类推。但这也不是一定的,上面说的是理想情况,如果我们在函数里定了一个数组,
如 char buf[8];并且是定义的第一个局部变量,那么它的地址肯定就不是ebp-4,还是ebp-8。所以,数组
比较特殊,结构体也比较特殊,其根本原因是栈是从高地址向低地址生长的,而我们的数组,结构体,
却是从低向高地址生长的,两者矛盾的结果就是寻址上的微妙变化。
当然,这里为了方便说明问题,都默认定义的变量,传入的参数,都是四字节对齐的,并且一个变量一个
双字。你可以把数组理解一个4字节的char,也就是一个双字了。
话说回来,当call运行完毕,当前的堆栈结构已经给出,如果在函数里调用strcpy()往局部变量1 里考入
东西,对长度没有进行检测,那么ebp-4,ebp,ebp+4,还有后面的地址,其所在的内容都会被覆盖掉。这里
溢出就发生了,我们控制住了ret的返回地址,然后...
嗯,为了防止这一切,新的cl编译器的/GS选项加上入所谓的"security cookie",如何加入的?在哪加入的
呢?
先看看加入"security cookie"后的call指令运行完以后,堆栈的变化。

局变2  ebp-c   低地址

局变1  ebp-8
XXXXX  ebp-4
ebp  ebp
返回地址 ebp+4
参数1  ebp+8
参数2  ebp+c
参数3  ebp+10
参数4  ebp+14   高地址

变化很明显,在ebp上面,第一个局部变量的下面,填入的一个新的值,这个值就是所谓的"security cookie"

.按照前面说的溢出过程,ebp- 4的内容被覆盖掉,即security cookie的值被修改,在函数返回,即执行ret
指令前,会call另一个函数,这个函数就是用来对比 ebp-4的值和当时push到栈中的值是不是一样,不一样的
话,就说明溢出了,然后进程被终止。
那么,你大概会产生以下几个问题:
1. 这个security cookie是如何计算出来的?
security cookie是一个双字,也可以说是一个int,其本身是保存在全局变量里的,其创建是编译器在编译
阶段就创建的,然后写入到.data段里,即在PE里就保存了这个值。
但这个值又是变化的,windows装载器完成必要的前期准备工作后(如创建进程,为栈分配内存,等待)
把 EIP设置为PE里的代码入口处,第一个执行的指令就是一个call调用,这个call调用就是用来初始化这个
cookie值的,当然,这段代码也是公开的,但没有关系,这个算法保证这个cookie值是随机的,hacker也
是不能在一个shellcode中可以猜出来的。
具体算法我不打算在此说明,感兴趣的读者可以自己编译一下再反汇编一下看看。

2.是什么时候填入到栈里面的?

我们知道了这个 security cookie的计算和初始化过程,那么,它必须在函数调用时写入到ebp-4里面才有用。
所以,过去的不带这种保护的代码,在函数入口处一般是这样的:
push ebp
mov ebp,esp
sub ebp,n   ;这条指令可能不同,不过多数情况下都是这样来为局部变量分配空间的
然后,后面就开始执行我们的代码了,
加入这种保护后,会在sub ebp,n后面,加入一条像这样的指令:
mov     dword ptr [ebp-4],XXX
XXX就是security cookie的值,这个值保存在全局变量里,通过RVA+PE头地址,实际上也可以说成是
绝对地址来引用了。
到这里security cookie的值就写入栈了,然后在函数返回前检测一下就行了。

到了这里,你大概又会产生一个新的问题,

必须为每一个函数调用都写入security cookie进行保护吗?
答案是否定的,要不然我们的程序的执行效率会受到一定的影响,并且可能还不小。
那么,就应该存在一定的规则,什么时候进行这种保护,什么时候不需要。
其依据当然也很简单,有溢出可能的,就加入这种保护,没有溢出可能的,就不加。
那怎么样才算是有溢出可能呢?
这个是编译器进行判断的,像函数里定义了char数组,后面又用字符串操作函数进行了一定的操作,就说明
可能存在溢出。编译器在编译这个函数里的时候就加上security cookie的保护。
当然,这里还有一些其它的很具体的规则,在msdn里有更详细的描述。

还有其它一些问题没有在这里说明,可以把这些问题留给大家

1.有对付security cookie的检测的方法吗?(答案是有的,但好像都不是很优美)
2.有关security异常的异常处理函数
3./safeSEH对 SEH处理的变化

___security_cookie机制,防止栈溢出的更多相关文章

  1. ___security_cookie机制

    .text:00411500 ; int __cdecl wmainCRTStartup().text:00411500 _wmainCRTStartup proc near             ...

  2. [02] HEVD 内核漏洞之栈溢出

    作者:huity出处:http://www.cnblogs.com/huity35/版权:本文版权归作者所有.文章在看雪.博客园.个人博客同时发布.转载:欢迎转载,但未经作者同意,必须保留此段声明:必 ...

  3. gcc栈溢出保护机制:stack-protector

    关键词:stack-protector.stack-protector-strong.stack-protector-all等等. 1. gcc栈保护机制stack-protector简介 gcc提供 ...

  4. 逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试

    GS简介: Windows的缓冲区安全监测机制(GS)可以有效的阻止经典的BOF攻击,因为GS会在函数调用前往函数栈帧内压入一个随机数(canary),然后等函数返回前,会对canary进行核查,判断 ...

  5. C++内存机制中内存溢出、内存泄露、内存越界和栈溢出的区别和联系

    当我们在用C++做底层驱动的时候,经常会遇到内存不足的警告,究其原因,往往是因为内存出现溢出,泄露或者越界等原因.那么他们之间有什么联系吗? 内存溢出(out of memory) 是指程序在申请内存 ...

  6. security cookie 机制(2)--- 初始化___security_cookie

    在 cookie 检查中,必定先要取出初始的 cookie 值: 0011392E A1 14 70 11 00       mov         eax,dword ptr [___securit ...

  7. [转载]Linux 线程实现机制分析

    本文转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 支持原创.尊重原创,分享知识! 自从多线程编程的概念出现在 Linux ...

  8. Java 内存区域和GC机制分析

    目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection, ...

  9. Java GC回收机制

    优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...

随机推荐

  1. 使用Application Loader打包上传AppStore流程

    配置完你的证书,Bundle Identifier 和描述文件的配置 然后配置工程打开你项目工程 第一步,这里不能选择模拟器,选择iOS Device 如果不支持横屏,把这2个勾去掉 然后查看版本号和 ...

  2. s3c2440 lcd 显示图片裸机程序

    因为前面的裸机程序非常的简单,就不写博了. 程序的流程: 1,初始化C SP 2,关看门狗 3,初始化SDRAM 4,读出 NAND FLASH 中的 包含图片的程式放到SDRAM里面 5,跳转到SD ...

  3. 【python cookbook】【字符串与文本】3.利用shell通配符做字符串匹配

    问题:当工作在Linux shell下时,使用常见的通配符模式(即,*.py.Dat[0-9]*.csv等)来对文本做匹配 解决方案:fnmatch模块提供的两个函数fnmatch().fnmatch ...

  4. 160918、BigDecimal运算

    java.math.BigDecimal.BigDecimal一共有4个够造方法,让我先来看看其中的两种用法: 第一种:BigDecimal(double val)Translates a doubl ...

  5. bootstrap导航条在手机上默认展开二级目录,必须用setTimeout才能实现

    bootstrap导航条在手机上默认展开二级目录,必须用setTimeout才能实现 $(document).ready(function() { $('.dropdown').hover(funct ...

  6. 使用MeanJS Yeoman Generator

    1.首先全局安装该生成器 sudo npm install -g generator-meanjs 2.为项目创建一个路径 mkdir xmen && cd xmen 3.创建app ...

  7. ACE的接受器(Acceptor)和连接器(Connector):连接建立模式

    ACE_Acceptor工厂的open()方法,或是它的缺省构造器(它实际上会调用open()方法),来开始被动侦听连接.当接受器工厂的open()方法被调用时,如果反应堆单体还没有被实例化,open ...

  8. sharepint 数据视图 添加超链接

    1. 数值域清除数值,输入文本 详细进度 2. 添加连接 到 哪个页面 3. 将inteid拖过来 4. 连接到项目显示表单 5. 直接改下面的连接地址 <a href="http:/ ...

  9. [转]application windows are expected to have a root view controller错误

    转载地址:http://blog.sina.com.cn/s/blog_6784e6ea01017jfy.html 最新更正:这个提示几乎不影响编译和运行,可以不用设置.     产生这个提示的操作: ...

  10. Android 自定义ScrollView ListView 体验各种纵向滑动的需求

      分类: [android 进阶之路]2014-08-31 12:59 6190人阅读 评论(10) 收藏 举报 Android自定义ScrollView纵向拖动     转载请标明出处:http: ...