栈缓冲区溢出
- 2020 年 3 月 8 日
- 笔记
文章源自【字节脉搏社区】-字节脉搏实验室
作者-Jadore
栈:先进后出


动态调试下的栈:


几个寄存器:
EAX:函数执行完后的返回结果
ECX:计数器
EDX、EBX:计算器
ESP:指向栈顶的指针
EBP:指向栈底的指针
ESI、EDI:源地址,目的地址寄存器
EIP:存储CPU要读取指令的地址


莫里斯蠕虫(Morris worm):
https://baike.baidu.com/item/%E8%8E%AB%E9%87%8C%E6%96%AF%E8%A0%95%E8%99%AB/9035909?fr=aladdin
缓冲区溢出(Buffer Overflow|Buffer Overrun):
由于程序设计时缺乏对缓冲区(Buffer)的边界进行检查而导致在向缓冲区写入超过其本身的数据时而引起的异常,一般会对相邻的内存区域进行覆盖,通常会被利用执行恶意代码获取系统权限。
产生缓冲区溢出的几种可能:

1.数组索引不在合法范围内
通常我们可能比较多地注意到数组的上界不应被超过,而往往却不太会在意数组的下界,来看到这个例子:
#include<stdio.h>
int main()
{
int position=-1;
int value=100;
int array[10];
if(position >= 10)
{
return -1;
}
array[position]=value;
return 0;
}

2. 没有保证足够的存储空间存储复制过来的数据:
strcpy是一个不安全的函数,看这个例子:
#include<stdio.h>
int main()
{
int array[]={1,2,3,4,5,6,7,8,9};
int array2[9];
strcpy(array2,array);
return 0;
}
而莫里斯蠕虫利用的不安全函数为gets,gets函数与strcpy函数一样,并没有检查数组越界的功能,当然除了这两个,还有诸如strcat(),strncpy(),strncat(),甚至输入函数scanf()也并不安全,对应的有更加安全的函数,即在函数名后加上_s,如scanf_s()函数

3. 整数溢出:
整数溢出可分为宽度溢出和算术溢出
宽度溢出:把一个宽度较大的操作数赋给宽度较小的操作数,就有可能发生数据截断或符号位丢失(分别对应以下两个例子):
#include<stdio.h>
int main()
{
int a=1;
float b=3.14;
int c;
c=a+b;
return 0;
}
#include<stdio.h>
int main()
{
signed int value1 = 10;
usigned int value2 = (unsigned int)value1;
}
算术溢出,该程序即使在接受用户输入的时候对a、b的赋值做安全性检查,a+b依旧可能溢出:
#include<stdio.h>
int main()
{
int a;
int b;
int sum=a+b;
return 0;
}

4. 空字符错误:
当’ ’用%c输出时是空格,而用%d输出时是0
#include<stdio.h>
int main()
{
char array[]=”1”;
printf(“%d”,str[1]);
return 0;
}
还有一种遍历数组的情况:
#include<stdio.h>
int main()
{
char str[10]=”0123456789″;
int i;
for(i=0;str[i]!='