c++ - SuspendThread WOW64 在内核代码中挂起

标签 c++ windows winapi wow64

更新:Microsoft 尚未在 Windows 8.1 中修复它。

编辑:结果是 bug在 WOW64 中 - 当线程在长模式 ring-3(用户模式)中挂起时,GetThreadContext() 可能会返回陈旧的内容。我已经建议微软使用 ring-2 来执行翻译。 SuspendThread 然后只会挂起 ring-3 中的线程(就像现在一样 - 无需更改),并且 ring-2 中的崩溃/故障/利用不会影响内核 - 它只会影响 ring-2 和 ring- 3.

此类更改需要更改一些 WinAPI 函数,例如 Wow64Get/SetThreadContext 等。这会破坏依赖未记录功能的应用程序,但这是可以预料的。诚然,转换会更慢,因为从 ring-3 转换到 ring-2 需要几个 CPU 周期(取决于 CPU 系列),但我认为操作系统的作用首先是确保正确运行。翻译已经增加了在 WOW64 下运行的应用程序的开销,所以这也是意料之中的。

我确实希望微软能解决这个问题——否则调试器/Mono 应用程序/Boehm GC/依赖 WOW64 下的 GetThreadContext() 的应用程序将无法工作(对于初学者,我已经看到调试器显示陈旧的堆栈跟踪)。

EDIT2:坏消息。从我与 MSFT (here) 的 Alexey 的谈话来看,它似乎根本无法修复,因为担心修复会破坏依赖未记录功能的应用程序。


原始问题

  • 有些人似乎对以下内容感到困惑。我最初认为这是由于 SuspendThread 在内核模式代码中暂停了一个线程。事实并非如此。以下只是我最初的怀疑,结果证明与真正的根本原因无关——真正的根本原因是 GetThreadContext() 返回的陈旧内容。

来自 MSDN:

挂起线程会导致线程停止执行用户模式(应用程序)代码。

然而,我发现我的 32 位应用程序在 Windows 7 中运行在 WOW64 下,线程 A 在线程 B 上调用 SuspendThread 可以在它运行 64 位代码时暂停它(我希望 不是 用户模式代码)。 EIP 显示挂起的线程停止在

wow64cpu!X86SwitchTo64BitMode:
00000000`759c31b0 ea27369c753300  jmp     0033:759C3627

它的 ESP 已经改变(我知道这是因为,虽然 ESP 指向与该线程堆栈相同的页面,但它的地址比当前堆栈指针高得多)。如果我在上面返回的指令处放置一个断点,然后让线程恢复,我发现 ESP 变回 X86SwitchTo64BitMode 调用之前的值(这是正确的堆栈指针)。我还发现,当单步执行同一个函数时,我永远无法在单步执行的任何时候获得更高地址的 ESP 值。事实上,当单步执行时,ESP 值在 X86SwitchTo64BitMode 调用前后永远不会改变。

此外,我确实通过检查 (DWORD)-1 来确保 SuspendThread 成功。

所有这些让我相信线程在内核模式代码中被挂起。

什么可能导致操作系统在运行非用户模式代码时挂起线程?我该如何防止呢?这基本上阻止了我获取线程 B 的实际当前堆栈指针。请注意,当应用程序在 WOW64 之外(在 native x86 操作系统上)运行时,不存在此类问题。

最佳答案

我已经确认这是在 WOW64 下调用 GetThreadContext 时返回陈旧内容的操作系统问题。

More info here .

感谢所有试图回答这个问题的人。我正在与 MS 合作解决这个问题。

关于c++ - SuspendThread WOW64 在内核代码中挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4144600/

相关文章:

c++ - 在它所属的模板类中使用内部类

c++ - 具有引用成员的类的默认移动构造函数

c++ - 找到存储最小值的元素

iphone - 如何在windows操作系统上打开iphone项目的.m文件

c - 微软怎么能说 WinAPI 中一个字的大小是 16 位呢?

c++ - 逐行读取文本文件(带整数)并将每一行存储为 vector (C++)

Java:如何启用JIT?

.net - 为要连接的 Windows Phone 7 应用程序构建服务的最佳可扩展架构是什么?

c# - 是否可以使用 C# 删除另一个应用程序的大小调整和关闭?

c++ - 从句柄获取文件路径