【问题标题】:How an assembler instruction could not read the memory it is placed at汇编指令如何无法读取它所在的内存
【发布时间】:2012-05-03 08:25:25
【问题描述】:

在 Windows XP 中使用一些作为 Windows 服务工作的软件并从登录屏幕重新启动,我看到一条臭名昭著的错误消息

“00x...”处的指令引用了“00x...”处的内存。记忆 无法读取。

我向开发人员报告了问题,但再次查看消息,我发现地址是相同的。所以

“00xdf3251”处的指令引用了“00xdf3251”处的内存。记忆 无法读取。

这是否是程序中的错误,但内存/访问权限的状态是什么,或者阻止指令读取它所放置的内存的其他东西是什么。它是特定于服务的吗?

【问题讨论】:

    标签: windows exception memory-management x86


    【解决方案1】:

    我猜想有人试图在地址 0xdf3251 处执行一条指令,并且该位置没有由可读和可执行的内存页支持(可能完全未映射)。

    如果是这种情况,则异常(实际上是页面错误)源自该指令,并且异常处理程序在堆栈上具有其地址(返回的位置,以防异常可以通过某种方式解决并且错误指令处理程序返回时重新启动)。这是您看到的第一个地址。

    页面错误处理程序读取的CR2 寄存器,即您看到的第二个地址,也具有相同的地址,因为它必须包含不可访问的内存位置的地址,而不管页面错误是否已经发生原因:

    • 完全没有映射(根本没有映射页面)
    • 缺少写权限(页面是只读的)
    • 缺少执行权限(页面设置了 no-execute 位)或
    • 缺少内核权限(页面被标记为只能在内核中访问)

    无论是在数据访问期间还是在获取指令时(后者是我们的情况)。

    这样才能使指令和内存访问地址相等。

    代码很可能存在导致内存损坏的错误,并且某些指针(或堆栈上的返回地址)被指向不可访问内存位置的虚假值覆盖。然后以一种或另一种方式指示 CPU 继续在那里执行(很可能使用以下指令之一:jmpcallret)。也有可能在某处出现竞争条件。

    【讨论】:

    • 很好的解释,这里可能就是这种情况。
    【解决方案2】:

    这种崩溃最常见的原因是堆栈损坏。一种非常常见的类型是堆栈缓冲区溢出。在存储在堆栈上的数组中写入太多数据,它会用数据覆盖函数的返回地址。然后当函数返回时,它会跳转到虚假的返回地址,并且由于该地址没有代码,程序会失败。他们将很难修复错误,因为没有简单的方法可以找出损坏发生的位置。

    这是一种相当臭名昭著的错误,它是恶意软件的主要攻击媒介。因为它可以控制程序跳转到带有数据的任意代码。您应该与这些开发人员坐下来并指出这一点,这是一个重大的安全风险。治愈很容易,他们应该更新他们的工具。这些天针对缓冲区溢出的对策是built into the compilers

    【讨论】:

    • 不幸的是,这些对策并不能保证捕获所有可能导致这种情况的损坏。如果它是释放后使用的错误怎么办?
    • use-after-free crash不会导致这种AV,代码和数据地址会不一样。
    • 假设您有一个动态分配的结构,其中包含一个函数指针,并且程序通过该指针调用一个函数。一切都是花花公子,直到您释放结构但继续使用指向它的陈旧指针。然后之前结构所在的内存被新分配的其他东西覆盖。
    • Hmya,当您只知道崩溃地址时,没有什么是不可能的。这就是为什么他需要与开发人员坐下来确保消除这种崩溃的 99% 的可能性。
    猜你喜欢
    • 2015-05-08
    • 2014-06-19
    • 1970-01-01
    • 2018-12-22
    • 2023-03-10
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    相关资源
    最近更新 更多