<程序员>11期文章
申明。文章仅代表个人观点,与所在公司无任何联系。
1. 概述
函数堆栈缓存溢出,是操作系统和应用程序安全漏洞最常见,最严重的类型之一。它往往导致可以允许攻击者可以远程执行恶意代码。
例如,以下这段代码[2,p147]就展示了Windows系统RPC调用中的函数堆栈缓存溢出类型的安全漏洞。它就是导致冲击波病毒(Blaster)爆发的根源。
HRESULT GetMachineName(WCHAR *pwszPath)
{
WCHAR wszMachineName[ N + 1 ];
...
LPWSTR pwszServeName = wszMachineName;
while (*pwszPath != L'//')
*pwszServerName++ = *pwszPath++;
...
}
在微软的安全开发周期模型中,专门在安全编码实践中推荐:对于微软的最新C/C++编译器,使用GS选项编译选项,加入检测函数堆栈缓存溢出错误额外代码。
那么,GS编译选项的内部原理是什么?它是如何检测函数的堆栈缓存溢出?如何使用?本文将会深入探讨这些问题。
2. Windows 系统的堆栈结构
为了说明/GS 编译选项的内部原理,我们需要先从Windows 系统的堆栈结构谈起。
用下面这段程序举例:
int test( int iLen, char *pBuf);
int _tmain(int argc, _TCHAR* argv[])
{
char * pBuf = "AAAAAAAAAAAAAAAAAAAA";
test( 10, pBuf );
return 0;
}
int test( int iLen, char *pBuf)
{
char p[10];
strncpy( p, pBuf, 20 );
return 0;
}
细心的读者也许已经看出,在执行 strncpy 会有堆栈溢出。我们后面会具体分析这一点。我们先看一下具体的汇编指令是如何操作函数调用时的堆栈的。
在 main 函数调用 test 函数时,有以下指令:
0040100b 8b45fc mov eax,[ebp-0x4]
0040100e 50 push eax ;参数pBuf
0040100f 6a0a push 0xa ;参数10
00401011 e80a000000 call GSTest1!test (00401020) ;调用test
00401016 83c408 add esp,0x8
可以看出,在函数调用时(C函数调