栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围。
堆溢出的产生是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般在递归中产生。堆溢出很可能由无限递归(Infinite recursion)产生,但也可能仅仅是过多的堆栈层级。
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的返回地址。只要事先在特定地址写入恶意代码,代码就会被执行。
所谓溢出广义上就是超出范围,整数就有溢出,比如8字节无符号整数是0到2550
-
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中的一部分数据是超长的,并且超长的部分包含了入侵代码的位置。当系统读取这部分数据的时候入侵代码就会被执行。
堆内存溢出: OutOfMemoryError,是ERROR。
一、什么是Error:
Error用于指示应用程序不应该试图捕获的严重问题。
二、什么是Exception:
Exception类及其子类用于指示应用程序需要处理的异常。
三、Error与Exception之间的联系:
1.继承联系:
Error与Exception都继承java.lang.Throwable(所有错误或异常的超类)。
2.检查异常:
未检查异常: Error与RuntimeException及其子类称为未检查异常(未显示提醒的异常),java编译器未检查的代码块,当程序运行时可能出现的异常,在没有try和catch,也没有throws的情况下,仍然可以编译通过。
如:OutOfMemoryError(内存溢出异常),StackOverflowError(堆栈溢出时,抛出该错误),ArrayIndexOutOfBoundsException(数组超出排序索引范围时抛出)等异常。
检查异常:
除了Error与RuntimeException及其子类其他都称为检查异常(提醒处理的异常),这类异常如果没有try和catch,也没有throws的情况下,编译是不能通过的。
如:TimeoutException(阻塞 *** 作超时时,抛出该异常),IOException(当发生某种 I/O 异常时,抛出此异常)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)