转自:http://kb.cnblogs.com/a/1439184/
Buffer Overrun定义
防止Buffer overrun的措施
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变量赋了默认值)。在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
failure:
}
[本文摘录于《软件调试》张银奎]