整数溢出
- 无符号整数
- 有符号整数
- 截断
- 配合不安全函数进行栈溢出
1 |
|
上表中,会把输入的InputTest传给无符号短整型OutputTest。无符号的16位整数(2个字节)可以表示0~2^16 -1,也就是0xFFFF
运行结果:
从上面可以发现,如果输入的值为0~65535,显示是没有问题的。如果超过了65535(比如65536),那么返回的结果是0,65537结果是1。
老规矩,拖入ida pro动态分析
给scanf下断点,可以看到,值最终存放在ecx寄存器中。
如果我们输入65535,也就是0xFFFF.
如果输入65536,结果是0x10000
接下来的步骤是:OutputTest = InputTest,对应的汇编为:
1 | mov dx, [ebp-4] |
也就是将0018FF44这个地址的数值赋给eax,并做与操作.这样就完全剔除了高16位,只保留低16位的数值。
这也是为什么输入65536后数值会从0重新开始增加。
无符号整数的上溢和下溢
负数 = 负数的补码 = 负数的反码 + 1
E.G: -1 可以表示为 100000001,取反 111111110,再加1,也就是111111111
对于无符号的整数,-1 = 0xFFFFFFFF
常见的问题:
void memcpy(void dest, const void *src, size_t n):从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
void memset(void s, int ch, size_t n):将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
下溢:
1 | BOOL fun(size_t cbSize) |
cbsize = 0,那么memset的第三个参数就为-1,而第三个参数为无符号整数,因此数据为0xFFFFFFFF,空间超过可执行的范围,因此崩溃。
上溢:
1 | BOOL fun(char *s1, size_t len1, char *s2, size_t len2) |
len1和len2都是无符号整数,如果len1=8,len2=0xFFFFFFFF,那么对于len1+len2+1这个运算来说,len2+1会变成0,然后再加上8,那么它的结果就是8。也就是说,new可能只分配了8个字节的空间,但是却要将长为0xFFFFFFFF的字符串复制到这个空间,那么结果就会造成程序的崩溃。
有符号整数
- 有符号整数之间的比较。
- 有符号整数的运算。
- 无符号整数和有符号整数的对比。
1 | int copy_something(char *buf, int len) |
上述代码的问题同样出在memcpy函数的第三个参数。由于memcpy使用的是无符号整数作为第三个参数的,但是最初的len是有符号整数。假设我们赋予len一个负值,那么就一定能够通过if语句的检测,但是当这个负值被运用在memcpy函数中时,len就可能变成一个非常大的正数,导致缓冲区及其后面的内容被改写,使得程序崩溃。
截断问题
截断问题主要发生在高位数的整数(如32位)复制到低位数的整数(如16位)的时候,发生的溢出现象
1 | BOOL fun(byte *name, DWORD cbBuf) |
对于fun函数来说,如果它的第二个参数cbBuf的值为0x00010020,由于cbCalculatedBufSize只能接收16位的内容,那么在赋值后,该变量的值为0x0020,因此new仅仅分配了0x20这么多的字节,但是name的大小实际为0x00010020,这就造成了缓冲区溢出情况的出现。
使用整数溢出实现栈溢出
1 |
|