访问数组越界有多危险?

访问数组之外​​的数组有多危险(C语言中)? 有时候可能会发生,我从数组外读取(现在我明白了,然后访问我的程序的某些其他部分使用的内存,甚至超出了该范围),或者我试图将值设置为数组之外的索引。 该程序有时会崩溃,但有时只是运行,只会产生意想不到的结果。

现在我想知道的是,这真的有多危险? 如果它损害我的程序,它并不坏。 另一方面,如果它在我的程序之外打破了某些东西,因为我设法访问了一些完全不相关的内存,那么我想它是非常糟糕的。 我读了很多'任何事情都可能发生','细分可能是最不好的问题','你的硬盘可能变成粉红色,独角兽可能会在你的窗户下唱歌',这很好,但真正的危险是什么?

我的问题:

  • 从阵列外读取值会损害除我的程序之外的任何东西吗? 我会想象看看事情不会改变任何事情,或者它会改变我碰巧遇到的文件的'上次打开'属性吗?
  • 除了我的程序之外,可以在数组外面设置值的方式是否会损害任何东西? 从这个stackoverflow问题我收集到,有可能访问任何内存位置,没有安全保证。
  • 我现在从XCode中运行我的小程序。 这是否为我的程序提供了一些额外的保护,使其无法到达自己的内存之外? 它会伤害XCode吗?
  • 任何有关如何安全地运行我自己的错误代码的建议?
  • 我使用OSX 10.7,Xcode 4.6

    这是我的第一个Stackoverflow问题。 我尽可能多地花时间阅读这个主题,但我可能错过了很多资源。 如果您觉得我没有做足够的研究并且/或者您发现此问题存在其他问题,请告诉我。


    就ISO C标准(语言的官方定义)而言,访问超出其范围的数组具有“未定义的行为”。 这个字面意思是:

    行为,在使用不可移植或错误的程序结构或错误数据时,本国际标准对此没有要求

    一个不规范的说明扩展了这一点:

    可能存在未定义的行为范围包括从完全忽略情况而产生不可预知的结果,在翻译或程序执行期间以文档化的方式表现环境特征(无论是否发布诊断消息),终止翻译或执行(发行的诊断消息)。

    这就是理论。 现实是什么?

    在“最好”的情况下,您将访问当前正在运行的程序拥有的一些内存(这可能会导致您的程序行为异常),或者它不属于当前正在运行的程序(这可能会导致程序崩溃像分段故障一样)。 或者您可能会尝试写入您的程序拥有的内存,但标记为只读; 这可能也会导致程序崩溃。

    假设你的程序在一个操作系统下运行,该操作系统试图保护彼此并行运行的进程。 如果你的代码运行在“裸机”上,说明它是OS内核还是嵌入式系统的一部分,那么就没有这种保护。 你的行为不端的代码是应该提供这种保护的。 在这种情况下,损坏的可能性要大得多,包括在某些情况下对硬件(或附近的事物或人)造成的物理损坏。

    即使在受保护的操作系统环境中,保护措施也不总是100%。 例如,操作系统错误允许非特权程序获得根(管理)访问权限。 即使使用普通用户权限,发生故障的程序也会占用过多的资源(CPU,内存,磁盘),可能会导致整个系统停机。 许多恶意软件(病毒等)利用缓冲区溢出来获得对系统的未授权访问。

    (一个历史的例子:我听说在一些具有核心内存的旧系统上,反复地访问单个内存位置可能会导致大量内存消失,其他可能性包括破坏CRT显示器和移动读取/将磁盘驱动器的磁头写入驱动器箱的谐波频率,使其穿过桌面并落到地板上。)

    总有天网公司担心。

    底线是:如果你可以写一个程序来故意做坏事,至少在理论上可能出现一个错误的程序可能意外地做同样的事情。

    实际上,在MacOS X系统上运行的错误程序不太可能会比崩溃更严重。 但是不可能完全防止错误的代码执行非常糟糕的事情。


    总的来说,今天的操作系统(无论如何都是流行的)使用虚拟内存管理器来运行受保护内存区域中的所有应用程序。 事实证明,简单地读或写一个位于已分配/分配给进程的区域之外的REAL空间中的位置并非非常简单(据说)。

    直接回答:

    1)读取几乎不会直接损害另一个进程,但是如果您碰巧读取用于加密,解密或验证程序/进程的KEY值,它可能会间接损害进程。 如果您根据您正在阅读的数据做出决定,那么阅读越界可能会对您的代码产生一些不利/意外的影响

    2)如果你正在写入的内存地址实际上是一个硬件寄存器(这个地址实际上不是用于数据存储,而是用于控制某些内存的地址),那么通过写入内存地址可访问的地址,的硬件)而不是RAM位置。 事实上,除非你正在编写一些不可重写(或某种性质)的一次性可编程位置,否则你通常不会损坏某些东西。

    3)通常从调试器内运行以调试模式运行代码。 在调试模式下运行时,TEND可以(但并非总是)在您完成某些考虑到实践或完全违法的事情时更快地停止您的代码。

    4)永远不要使用宏,使用已经有数组索引边界检查内置的数据结构等....

    其他我应该补充一点,上述信息仅适用于使用带有内存保护窗口的操作系统的系统。 如果要为嵌入式系统编写代码,甚至使用不具有内存保护窗口(或虚拟寻址窗口)的操作系统(实时或其他)的系统,那么在读取和写入内存时应该小心谨慎。 同样在这些情况下,应始终采用SAFE和SECURE编码实践来避免安全问题。


    不检查范围可能导致丑陋的副作用,包括安全漏洞。 其中一个丑陋的是执行任意代码。 在经典的例子中:如果你有一个固定大小的数组,并使用strcpy()来放置一个用户提供的字符串,那么用户可以给你一个字符串,它溢出缓冲区并覆盖其他内存位置,包括CPU应该返回的代码地址当你的功能完成时。

    这意味着您的用户可以向您发送一个字符串,这会导致您的程序实质上调用exec("/bin/sh") ,这会将其转化为shell,执行您希望在系统上执行的任何操作,包括收集所有数据,机器进入僵尸网络节点。

    有关如何完成此操作的详细信息,请参阅粉碎乐趣和利润堆栈。

    链接地址: http://www.djcxy.com/p/36357.html

    上一篇: How dangerous is it to access an array out of bounds?

    下一篇: C cache optimization for direct mapped cache