[软件调试学习笔记]防止栈缓冲区溢出的基于Cookie的安全检查机制

本文主要是介绍[软件调试学习笔记]防止栈缓冲区溢出的基于Cookie的安全检查机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[软件调试学习笔记]防止栈缓冲区溢出的基于Cookie的安全检查机制

Buffer Overrun定义

buffer是程序用来存储数据的连续内存区域,一旦分配完成,其起始地址和大小便固定下来。程序运行过程中,如果使用了超出buffer的区域,那么就发生了buffer overflow(缓冲区溢出)或者buffer overrun(缓冲区越界)。如果该缓冲区分配在stack上,就称之为stack buffer overrun;如果分配在heap,就称为heap overflow。

stack buffer overrun会冲毁thread自身及其父线程的栈信息,我们知道在当前stack frame中,EBP+4为函数返回地址,EBP+8为最后一个参数,EBP+C:倒数第二个参数...。如果EBP+4处的内容被写入一个非法地址,那么函数调用退出的时候就会跳转到一个非法地址,转而执行非法程序。这就是利用stack buffer overrun进行恶意攻击的基本原理。

在vc6.0中,如果程序为debug 版本,by default会启用stack buffer overrun的检测。而在release版本中,则关闭了对其的检测。而在vc8以上版本编译其中,则采用了基于Cookie的stack buffer安全检查机制。

防止Buffer overrun的措施

本文将介绍在VS8及以上版本编译器中采用Cookie机制来防止stack overrun的方法。

首先简要介绍在Debug版本下的stack orverrun(VC8及以上)的检测机制:

1.VC8在紧邻栈指针的位置分配4个字节用于存放安全Cookie。安全Cookie就像一个安全护栏,用于保护其下的栈指针和函数返回地址,他位于局部变量和重要的栈帧信息(栈帧指针及函数返回地址)。这样,如果Cookie之上的局部变量发生溢出,在漫延到栈帧信息前会覆盖Cookie,因此检查Cookie的完整性便可以探测到可能危及栈信息的溢出情况。

2.在给每个局部变量分配空间时,除了补齐内存空间所需的零头部分,编译器还会给每个变量多分配8个字节,分别放置于变量的前后各4个字节,并将其初始化为0xcccccccc。这样,每个变量相当于有了前后2个屏障。一旦这2道屏障受损,则会产生中断(正是cc编码)。

基于Cookie的Stack Buffer安全检测

但是以上开销较大,通常只用于调试版本。为了在release version中也能检测出stack buffer overrun,防止程序因此而受到攻击,VS2005及以上支持了基于Cookie的安全检查机制。

基于Cookie的安全检查机制原理如下:

1.编译器在编译可能发生stack buffer orverrun的函数时,会定义一个特别的局部变量,该局部变量被分配在栈帧中所有其他局部变量和栈帧与函数返回之间,这个变量专门用来保存Cookie,我们将其称为Cookie变量。Cookie变量是一个32位的整数,他的值从全局变量_security_cookie中得到。(该全局变量是定义在C运行库中,我们可以看到默认安装路径下的源代码:c:\program...\visu..8\VC\crt\src\gs_cookie.c可以看到其定义:

#define DEFAULT_SECURITY_COOKIE 0xBB40E64E

DECLSPEC_SELECTRANY UINT_PRT _security_cookie=DEFAULT_SECURITY_COOKIE;

......

(可见_security_cookie变量赋了默认值)。在VC8编译器启动的启动函数中(如WinMainCRTStartup)还会调用_security_init_cookie函数对该变量进行正式的初始化。在crt0.c中,可以看到启动函数的源码如下:

int _tmainCRTStartup(void)

{

_security_init_cookie();//初始化cookie

......

}

因为是在启动函数中初始化全局变量_security_cookie,所以在该process以后的运行过程中,Cookie值是保持不变的。

编译器在为一个函数插入安全Cookie时,他还会与当时的EBP做一次xor,然后将其保存到Cookie变量中,这些指令通常出现在函数的序言(prolog)之后,其典型过程如下:

push ebp

mov ebp,esp

sub esp,0x18//为局部变量分配栈空间

mov eax,[applica!_security_Cookie];//将_security_cookie存入eax

xor eax,ebp;//与ebp xor

mov [ebp-0x4],eax;//存入cookie变量

......

与EBP xor的两个好处:

1. 提高安全cookie的随机性,尽可能使每个函数的_security_cookie都不同。

2.检查EBP值是否被破坏。因为在检查Cookie变量时,会再与EBP再进行一次xor,如果EBP没有发生变化,那么两次xor后Cookie变量的值就应该成全局安全变量_security_cookie的值。

其典型的代码如下:

mov ecx, [ebp-0x4];

pop edi;

xor ecx,ebp;//再xor 一次

pop esi;

call applica!_security_check_cookie(0x***);//开始检查_security_cookie

mov esp,ebp

pop ebp

ret;

而_security_check_cookie是一个只含有4条汇编代码的函数,在crt\intel\secchk.c 中对函数定义如下:

void _security_check_cookie(UINT _PTR cookie)

{

_asm

{

cmp ecx,_security_cookie;

jne failure;

rep ret;

failure:

jmp _report_gsfailure;

}

}

2.安全检查失败处理

因为stack buffer overrun可能覆盖掉函数的本来返回地址,使函数返回到未知的地方,从而使程序出现不可预期的后果。因此这种exception被看作是fatal error,一旦遇到这种错误,程序就会马上终止。但为了debug,在terminate process之前,_report_gsfailure函数会记录下错误发生时的重要信息,并提供JIT调试机会。

[本文摘录于《软件调试》张银奎]

备注:
实际研究发现,当函数中有字符串拷贝处理的时候才会有cookie检查,普通的函数没有这样的检查。

这篇关于[软件调试学习笔记]防止栈缓冲区溢出的基于Cookie的安全检查机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/704844

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

基于Redis自动过期的流处理暂停机制

《基于Redis自动过期的流处理暂停机制》基于Redis自动过期的流处理暂停机制是一种高效、可靠且易于实现的解决方案,防止延时过大的数据影响实时处理自动恢复处理,以避免积压的数据影响实时性,下面就来详... 目录核心思路代码实现1. 初始化Redis连接和键前缀2. 接收数据时检查暂停状态3. 检测到延时过

Redis中哨兵机制和集群的区别及说明

《Redis中哨兵机制和集群的区别及说明》Redis哨兵通过主从复制实现高可用,适用于中小规模数据;集群采用分布式分片,支持动态扩展,适合大规模数据,哨兵管理简单但扩展性弱,集群性能更强但架构复杂,根... 目录一、架构设计与节点角色1. 哨兵机制(Sentinel)2. 集群(Cluster)二、数据分片

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

深入理解go中interface机制

《深入理解go中interface机制》本文主要介绍了深入理解go中interface机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前言interface使用类型判断总结前言go的interface是一组method的集合,不

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连