《程序员》5月文章。申明。文章仅代表个人观点,与所在公司无任何联系。
- 概述
在前面的安全编码实践的文章里,我们讨论了GS编译选项和
第一:GS和DEP是缓解(mitigation)措施。
第二:GS和DEP存在其自身的局限性。例如,GS不是对
那么,一个很自然的问题就是,
答案之一是静态代码分析工具。本文会着重介绍微软提供的C
- Prefast介绍
2.1历史
Prefast是微软研究院提出的静态代码分析工具。
2.2 如何获得Prefast
目前有两个办法可以获得Prefast工具。
- Prefast包括在Visual Studio 2005 /2008的团队版本(team edition)中。
- Prefast包括在Windows驱动程序开发包(Micro
soft Windows Driver Kits)的开发环境中。
需要指出的是,Visual Studio的团队版本的价格要高于Visual Studio个人版本,而Windows驱动程序开发包是免费下
下载Windows驱动程序开发包可以通过http://
安装好WDK后Prefast就已经直接在其开发环境下使
2.3使用Prefast
在Visual Studio的团队版本中,使用Prefast,打开Proje
如果直接使用CL.exe命令行编译器,采用/
图1:VSTS中使用Prefast(Code Analysis)
使用在WDK中的Prefast,有以下几个重要命令。
- 运行Prefast:prefast build -cZ
- 查看Prefast输出结果:
- 命令行:prefast list
- GUI:prefast view
有关在WDK下使用Prefast的详细步骤,
- Prefast输出的警告(warning)信息
上面的介绍可以看出Prefast的使用操作并不难。
警告 C6001: using uninitialized memory <variable>,使用未初始化的变量。
例子:
#include "stdafx.h"
int f( bool b )
{
int i;
if ( b )
{
i = 0;
}
return i; // 当b为假时,变量i未初始化
}
大家也许会问,使用未初始化的变量会导致安全漏洞吗?
修补:初始化变量。
警告C6029: possible buffer overrun in call to <function>: use of unchecked value,使用未验证的参数可能导致缓存溢出。
例子:
#include "windows.h"
void f(char *buff, DWORD cbLen, DWORD cbRead, HANDLE hFile)
{
if (!ReadFile (hFile, &cbLen, sizeof (cbLen), &cbRead, NULL))
{
// code ...
if (!ReadFile (hFile, buff, cbLen, &cbRead, NULL)) // warning 6029
{
// code ...
}
}
}
在上面这个例子中,第一次的ReadFile得到的cbL
修补:验证参数。在第二个ReadFile之前验证cbL
if (cbLen <= sizeof (buff)) // check length
警告C6057: buffer overrun due to number of characters/number of bytes mismatch in call to <function>,字符(characters)
对于ANSI字符串类型,字符数目和字节数目是一致的。
例子:
#include<tchar.h>
#include<windows.h>
void f( HINSTANCE hInst, UINT uID )
{
TCHAR buff[128];
if ( LoadString ( hInst, uID, buff, sizeof buff ) ) // warning C6057
{
// code...
}
}
LoadString期望的参数是字符串缓存的字符数目。
修补:正确计算数组中元素的个数。
LoadString ( hInst, uID, buff, (sizeof buff)/(sizeof buff[0]) )
警告C6201: buffer overrun for <variable>, which is possibly stack allocated: index <name> is out of valid index range <min> to <max>,数组索引的越界可能导致缓存溢出。
例子:
void f()
{
int buff[25];
for (int i=0; i <= 25; i++) // i exceeds array bound
{
buff[i]=0; // initialize i
// code ...
}
}
修补:确保数组索引不越界。
警告C6202: buffer overrun for <variable>, which is possibly stack allocated, in call to <function>: length <size> exceeds buffer size <max>,使用缓存区时,给出的长度超出缓存区长度的最大值。
例子:
#include <memory.h>
void f( )
{
int intArray[5];
char charArray[5];
memset ((void *)charArray, 0, sizeof intArray);
// code ...
}
修补:正确的缓存长度。这里sizeof intArray应该是sizeof charArray。
警告C6204: possible buffer overrun in call to <function>: use of unchecked parameter <variable>,使用缓存区时,
例子:
#include<string.h>
void f(char *pCh)
{
char buff[10];
strcpy(buff, pCh);
}
pCh的值没有验证就直接使用了。
修补:验证传入的参数。加入检查:if (strlen(pCh) >= sizeof buff) return;
限於篇幅,
- 静态代码分析工具的局限
静态代码分析工具是SDL(安全软件开发周期)
由于程序控制流和数据流的复杂程度,
- 漏报:我们上面举出的代码例子都是非常简单的。
随着代码复杂度的增大,尤其是跨函数之间逻辑和数据的交互关系, 往往给静态代码分析带来极大的困难。 - 误报:分析信息的不完备,会导致误报警告信息。
- 漏报:我们上面举出的代码例子都是非常简单的。
- 总结
Prefast是微软提供的针对C/C++程序的静态代码
- 参考文献
- PREfast Step-by-Step,http://www.
microsoft.com/whdc/DevTools/ tools/PREfast_steps.mspx,Micro soft http://msdn2.microsoft.com/en- us/library/ms680339(VS.85). aspx - Code Analysis for C/C++ Warnings,http://msdn2.
microsoft.com/en-us/library/ a5b9aa09.aspx,Microsoft - MS08-014 : The Case of the Uninitialized Stack Variable Vulnerability, http://blogs.technet.com/swi/
archive/2008/03/11/the-case- of-the-uninitialized-stack- variable-vulnerability.aspx, SWI, Microsoft
- PREfast Step-by-Step,http://www.