6

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

编辑:这原来是 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 的 Alexey 的对话(这里)看来,它可能根本无法修复,因为担心修复会破坏依赖于未记录功能的应用程序。


原始问题

  • 有些人似乎对以下内容感到困惑。我最初认为这是由于 SuspendThread 在内核模式代码中挂起线程。不是。以下只是我最初的怀疑,结果与实际根本原因无关 - 这是由返回的陈旧内容GetThreadContext()

来自 MSDN:

Suspending a thread causes the thread to stop executing user-mode (application) code.

然而,我发现我在 Windows 7 中的 32 位应用程序在 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 之外(在本机 x86 操作系统上)运行时,不存在此类问题。

4

4 回答 4

3

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

更多信息在这里

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

于 2010-11-13T05:58:01.843 回答
1

请参阅此说明:Wow64 中的 GetThreadContext

本文解释说,x86 和 amd64 模式之间的转换是在用户模式下完成的。

于 2010-11-10T13:47:33.907 回答
0

你的线程在用户模式下做什么?当您调用SuspendThread. 它是否有可能在您暂停它的那一刻执行系统功能?

什么可能导致操作系统在运行非用户模式代码时挂起线程?

许多系统或库调用可能会导致切换到内核模式。而且因为 Windows 内核在大多数情况下被设计为可重入的,所以当第一个线程处于内核模式时从一个线程切换到另一个线程是很正常的。

我该如何防止呢?

只是一个想法:创建一个正在执行空循环(例如for(;;);)的线程并挂起该线程。这个不应该在内核模式下挂起。


另外,为什么 ESP 寄存器等正确对您很重要?我希望您正在编写某种调试器或相关的东西,因为这就是SuspendThread目的。

于 2010-11-10T13:29:11.390 回答
-1

从技术上讲,当一个线程根本不运行时,它既不运行内核模式代码,也不运行用户模式代码。所以你的观察与陈述并不矛盾。

Beisdes,你不应该搞砸这个。如果您(在用户模式下)可以控制是否执行内核模式代码,那将是一个操作系统错误。

于 2010-11-10T13:11:22.583 回答