Saturday, February 17, 2007

C\C++ Boundary and Error Check (1)

Sample:</br>

void CopyData(char *szData) {
char cDest[32];
strcpy(cDest,szData);
// 使用 cDest
...
}

char *szNames[] = {"Michael","Cheryl","Blake"};
CopyData(szName[1]);

  • 缓冲区溢出是指当计算机程序向缓冲区内填充的数据位数超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
  • 操作系统所使用的缓冲区又被称为堆栈,在各个操作进程之间,指令被临时存储在堆栈当中,堆栈也会出现缓冲区溢出。
  • 缓冲区溢出是由编程错误引起的。如果缓冲区被写满,而程序没有去检查缓冲区边界,也没有停止接收数据,这时缓冲区溢出就会发生。
  • 缓冲区溢出主要出现在 C 和 C++ 中,因为这些语言不执行数组边界检查和类型安全检查。

当编写 C 和 C++ 代码时,应注意如何管理来自用户的数据。如果某个函数具有来自不可靠源的缓冲区,请遵循以下规则:
  • 要求代码传递缓冲区的长度并进行检查。
  • 探测内存。
  • 采取防范措施。

以下代码的问题在于函数不能判断 szName 的长度,这意味着将不能安全地复制数据。函数应知道 szName 的大小:

void Function(char *szName, DWORD cbName) { char szBuff[MAX_NAME];
// 复制并使用 szName
if (cbName < MAX_NAME) strncpy(szBuff,szName,MAX_NAME-1);
}
然而,您不能想当然地信任 cbName。攻击者可以设置该名称和缓冲区大小,因此必须进行检查!

void Function(char *szName, DWORD cbName) {
char szBuff[MAX_NAME];

#ifdef _DEBUG
// 探测
memset(szBuff, 0x42, cbName);
#endif

// 复制并使用 szName
if (cbName < MAX_NAME) strncpy(szBuff,szName,MAX_NAME-1);
}

注意:只能在调试版中这样做,以便在测试过程中捕获缓冲区溢出。

void Function(char *szName) {
char szBuff[MAX_NAME];

if(strlen(szName) >= MAX_NAME || strlen(szName)<0) { /* Do something appropriate, such as throw an error. */
}
else {
strncpy(szBuff,szName,MAX_NAME-1);
}

}


完成同样目的的更容易方式是使用 strncpy() 库例程:
strncpy(dst, src, dst_size-1);
dst[dst_size-1] = '0'; /* Always do this to be safe! */
如果 src 比 dst 大,则该函数不会抛出一个错误;当达到最
大尺寸时,它只是停止复制字符。注意上面调用 strncpy() 中的
-1。如果 src 比 dst 长,则那给我们留有空间,将一个空字符
放在 dst 数组的末尾。

Digg!

No comments: