栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围。
堆溢出的产生是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般在递归中产生。堆溢出很可能由无限递归(Infinite recursion)产生,但也可能仅仅是过多的堆栈层级。
int f(int x)
{
int a;
a = x;
}
这个就是栈溢出,x被写到了不应该写的地方。在特定编译模式下,这个x的内容就会覆盖f原来的返回地址。也就是原本应该返回到调用位置的f函数,返回到了x指向的位置。一般情况下程序会就此崩溃。但是如果x被有意指向一段恶意代码,这段恶意代码就会被执行。
堆溢出相对比较复杂,因为各种环境堆的实现都不完全相同。但是程序管理堆必须有额外的数据来标记堆的各种信息。堆内存如果发生上面那样的赋值的话就有可能破坏堆的逻辑结构。进而修改原本无法访问的数据。
int f(char *s, int n)
{
char a;
memcpy(a, s, n);
...
这个是栈溢出比较真实一点的例子,如果传入的数据长度大于10就会造成溢出,进而改变f的返回地址。只要事先在特定地址写入恶意代码,代码就会被执行。
标签:溢出