一、 超越整数范围的溢出
当执行算法以计算缓冲区大小,真正的安全性漏洞会随同这些缺陷一起出现。请看下面的示例:
void func(char *b1, int c1, char *b2, int c2) {
const int MAX = 48;
if (c1 + c2 > MAX) return;
char *pBuff = new char[MAX];
memcpy(pBuff,b1,c1);
memcpy(pBuff+c1,b2,c2);
}
上面的代码看起来没有问题,但如果将 c1 和 c2 相加,结果超过 232-1,您就会意识到有问题了。例如,0xFFFFFFF0 和 0x40 相加的结果为 0x30(十进制为 48)。当这些值用于 c1 和 c2 时,加起来的和可以通过大小检查,然后代码会将大约 4GB 复制到 48 个字节的缓冲区。这样就会出现缓冲区溢出!类似于这样的许多错误都可以被利用,使攻击者将代码注入您的进程中。
那像这种问题如何解决呢?
可以在可能发生溢出的地方,加上条件判断,比如解决上面的问题, 可以写为:
If( c1 < 0 || c2 < 0 || c1 + c2 > MAX ) return;
二、 类型转换时的溢出
在一个复杂的应用程序中,一个表达式中包含了各种类型的变量,这时在运算过程中就包括了各种的默认类型转换。这个默认类型转换都是按你想的过程进行的吗? 先看如下的例子
, 首先, 自己猜测一下结果:
#include
int main()
{
signed short intb1, intb2;
unsigned short uintb;
long longc1, longc2;
unsigned long ulongc1, ulongc2;
longc1 = -34;
ulongc1 = 7;
uintb = 3;
intb1 = -84;
if( longc1 > ulongc1 )
printf("%ld > %lu /n", longc1, ulongc1);
else
printf("%ld < %lu /n", longc1, ulongc1);
if( longc1 > uintb )
printf("%ld > %u /n", longc1, uintb);
else
printf("%ld < %u /n", longc1, uintb);
if( intb1 > uintb )
printf(" %d > %u /n", intb1, uintb);
else
printf(" %d < %u /n", intb1, uintb);
longc2 = ulongc1 + longc1;
printf("%lu + %ld = %ld /n", ulongc1, longc1, longc2);
ulongc2 = ulongc1 + longc1;
printf("%lu + %ld = %lu /n", ulongc1, longc1, ulongc2);
if( ulongc1 + longc1 > 0)
printf("%lu + %ld > 0 /n", ulongc1, longc1);
}输出的结果是:
-34 > 7
-34 < 3
-84 < 3
7 + -34 = -27
7 + -34 = 4294967269
7 + -34 > 0
以上的程序在
GCC2.9 上编译,liunx7.3上运行的结果。
从输出的结果来看,和你预期的输出结果一样吗?
也许从下面的输出结果,你能了解到问题出在那里了吗?
7 + -34 = -27
7 + -34 = 4294967269
7 + -34 > 0
是的,从中我们就可以看出, 类型转换的作用。
现在来解释一下如下表示式:
7 + -34 > 0
因为 ulongc1 是无符号数,
longc1是有符号数 ,所以longc1转换为无符号相加,产生如下结果:
ulongc1 + longc1 = 4294967269
这时,自然
ulongc1 + longc1 > 0
对于longc1 > uintb 以及
intb1 > uintb 的比较过程中, 默认的转换中,都将双字节short类型(不管是有无符号)先转换为有符号四字节类型int , 再进行比较,所以才比较出正确的结果。
从以上的测试来看, 我们来看如下一段介绍默认类型转换的:
在
C语言中,在进行表达式计算时,如果其中有多种类型时,一般先进行类型转换,再进行计算。默认的类型转换是从字节少向字节多的转换,有符号的向无符号类型转换。因些,如果算术运算符的一个操作数是有符号整数,另一个是无符号整数,那么有符号整数会被转换为无符号整数,计算结果自然也是无符号数。
发现其中也有不完善的地方, 因为低于四字节的类型,如char , unsigned char , short, unsigned shourt 都是先转换为int 类型,再进行计算, 数据没有丢失及溢出,因此不存在判断错误。所以要注意的就是int 以及 unsigned int混合,此时何正确进行判断呢?
只要先有符号数的范围检查:
if ((longc1 > 0)
&& (longc1 > ulongc1))
{
// longc1 > ulongc1
}