所谓溢出广义上就是超出范围,整数就有溢出,比如8字节无符号整数是0到255 0 - 1就是下溢 255 + 1就是上溢 说正题 int f(int x) { int a[10]; a[11] = x; } 这个就是栈溢出,x被写到了不应该写的地方。在特定编译模式下,这个x的内容就会覆盖f原来的返回地址。也就是原本应该返回到调用位置的f函数,返回到了x指向的位置。一般情况下程序会就此崩溃。但是如果x被有意指向一段恶意代码,这段恶意代码就会被执行。 堆溢出相对比较复杂,因为各种环境堆的实现都不完全相同。但是程序管理堆必须有额外的数据来标记堆的各种信息。堆内存如果发生上面那样的赋值的话就有可能破坏堆的逻辑结构。进而修改原本无法访问的数据。 int f(char *s, int n) { char a[10]; memcpy(a, s, n);
} 这个是栈溢出比较真实一点的例子,如果传入的数据长度大于10就会造成溢出,进而改变f的返回地址。只要事先在特定地址写入恶意代码,代码就会被执行。 堆溢出执行恶意代码的一种情况是通过过长的数据破坏堆结构,使下次申请能得到保存某些特定函数指针的位置,然后进行修改。 栈和堆溢出的一个共性就是第三方可以完全依靠提供特定数据实现代码级别的入侵。玩游戏的话可能知道PSP3000的破解,利用的就是PSP系统显示tiff文件时候的一个溢出漏洞。tiff文件内包含一段入侵代码,载入tiff文件的时候这段代码也会被载入,只不过这个时候各奔不可能被执行。但是tiff中的一部分数据是超长的,并且超长的部分包含了入侵代码的位置。当系统读取这部分数据的时候入侵代码就会被执行。