10月1日整理了缓冲区溢出的C语言例子,今天再整理一下由于程序员编程错误导致的问题。可以理解为常规缓冲区溢出。常规缓冲区溢出是指由于程序员书写错误导致的显式缓冲区溢出漏洞。根据其产生方式,程序行为和调用函数的区别,分成为面几类。
- 给数组赋值字符串越界
缓冲区赋值超过缓冲区长度的字符串常量则会导致缓冲区溢出。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char cArray[10]="abcdefghijk";
return 0;
}
上面例子中,数组长度声明为10,给它赋值的字符串"abcdefghijk"长度为11,超过数组本身本身的长度10,导致缓冲区溢出。在数组初始化的时候,一定要注意初始化字符串的长度不要超过给数组合法范围。
- 数组下标访问越界
数组下标为负数或数组下标超过数组长度的时候,会发生缓冲区溢出。例如
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char cArray[10];
cArray[10]=10;
return 0;
}
数组下标值为10,超过数组cArray的长度10,导致发生缓冲区溢出。防止出现问题的方法是对数组下标的取值范围进行判定,即可避免。
- 初始化内存越界
初始化内存越界是指在对缓冲区空间使用memset初始化的时候,没有考虑到缓冲区的长度,导致初始化长度大于数组长度,发生缓冲区溢出。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int iArray[10];
memset(iArray,0,20);
return 0;
}
数组的长度时10,使用memset初始化内存的长度为20,因此导致缓冲区溢出。
- 指针操作越界
指针操作越界是指对指针动态分配内存空间后,对指针进行算术运算或者取下标操作,使得操作后的支付指向不合理范围,导致缓冲区溢出。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int *p;
int *t=20
p=malloc(sizeof(int)*10);
p[t]=10;
*(p+t)=11;
return 0;
}
上面例子中,声明了指针p,给指针p分配内存空间10,后面对指针进行算术运算导致缓冲区溢出。防止方法是对指针进行算法运算操作之前需要对变量的值范围进行校验,确保指针指向合理的区间范围。
- 字符串拷贝越界
在使用strcpy等字符串拷贝时,注意src拷贝给des时,如果src长度超过des长度,则会发生溢出。
例如:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char a[5];
char *p="abcdef";
strcpy(a,p);
printf("%s",a);
return 0;
}
当把指针p指向的字符串拷贝到a数组时,6个字符长度超过了数组a长度5,导致发生缓冲区溢出。进行字符串拷贝时,一定要注意来源字符串的长度要小于等于目的缓冲区长度。
- 格式化字符串导致的缓冲区溢出
格式化字符串导致缓冲区溢出是指对字符串格式化时,没有对字符串长度加以限制导致的缓冲区溢出。是一种由越界写数据引起的缓冲区溢出。在使用sprinrf进行格式化字符串时,导致缓冲区溢出。当格式化字符串时,要注意格式化参数长度
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char a[10];
char *p="3.14159";
sprintf(a,"p的值为%f",p);
printf("%s",a);
return 0;
}
上面例子中数组a声明为10个字符长度,但是字符串p长度虽然不足10个字符,但是要添加“"p的值为”字符串,其长度超过10个,所以发生a的缓冲区溢出。
下面是整理的10种数组越界情况,以及上面的例子可以作为静态代码检测分析工具的进行缓冲区溢出检测检测的Benchmark。
例子:下面有10个数组越界情况,在VS 2012上调试通过。
array.h头文件
int i,j;
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int arr1[MAX_LEN];
int arr2[MAX_LEN1];
int arr3[MAX_GLEN];
ConsoleApplication5.cpp,源文件
#include "stdafx.h"
#include "array.h"
#define MAX_LEN 5
#define MAX_LEN1 MAX_LEN
#define SUM(x) x*x
inline int fun(int x);
inline int fun(int x)
{
return x * x;
}
int _tmain(int argc, _TCHAR* argv[])
{
int iStatus=0;
int num[5];
int i=0;
for(int i=0; i<5; i++)
num[i]=i*2;
i++;
num[i]=20;
int data=10;
char *p=NULL;
scanf_s("%s",p);
//第一种情况
for(i=0;i<=10;i++)
{
arr[i] = 0;
printf("%d\n",i);
}
//第二种情况
for(i=0;i<10;i++)
{
arr[i] = 0;
printf("%d\n",i);
j=i;
}
++j;
printf("arr[%d]=%d\n",j,arr[j]);
//第三种情况
j=-1;
arr[j]=-1;
//第四种情况
for(i=0;i<=5;i++)
{
arr1[i]=i;
printf("%d\n",arr1[i]);
}
//第五种情况
for(i=0;i<=5;i++)
{
arr2[i]=i;
printf("%d\n",arr2[i]);
}
//第六种情况
for(i=0;i<10;i++)
{
arr3[i]=i;
printf("%d\n",arr3[i]);
}
printf("第六种情况循环结束后 i=%d \n",i);
arr3[i]=10;
printf("第六种情况循环结束后 arr3[%d]=%d \n",i,arr3[i]);
++i;
arr3[i]=11;
printf("第六种情况arr3[%d]=\n",i,arr3[i]);
//第七种情况
for(i=0;i<10;i++)
{
arr3[i]=i;
printf("%d\n",arr3[i]);
}
int c=SUM(2+3)-1;
arr3[c]=10;
//第八种情况
int d=fun(3);
d++;
for(i=0;i<10;i++)
{
arr3[i]=i;
printf("%d\n",arr3[i]);
}
arr3[d]=10;
//第八种情况
for(i=10;i>0;i--)
{
arr3[i]=i;
printf("%d\n",arr3[i]);
}
i--;
arr3[i]=0;
arr3[i--]=-1;
//第九种情况
i=10;
while(i>0)
for(i=10;i>=0;i--)
{
arr[i]=i;
printf("%d\n",arr[i]);
}
printf("第9种情况循环结束后 arr[%d]=%d \n",i,arr[i--]);
arr[i--]=-1;
//第十种情况
j=10;
do
{
arr[j]=j--;
}while(j>=0);
printf("第10种情况循环结束后 arr[%d]=%d \n",--j,arr[j]);
return 0;
}
关注安全 关注作者