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

编辑:事实证明这是WOW64中的bug-当线程在long模式ring-3(用户模式)下挂起时,GetThreadContext()可能返回陈旧的内容。我建议微软使用ring-2进行翻译。然后SuspendThread只会将环3中的线程挂起(如现在那样-无需进行任何更改),而环2中的崩溃/故障/攻击不会影响内核-只会影响环2和环- 3。

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

我确实希望Microsoft能够解决此问题-否则调试器/Mono应用程序/Boehm GC/依赖于WOW64下的GetThreadContext()的应用程序将无法工作(对于初学者来说,我已经看到调试器显示了过时的堆栈跟踪)。

EDIT2 :坏消息。从我与MSFT(here)的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之外(在 native x86 OS上)运行时,不存在此类问题。

    最佳答案

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

    More info here

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

    07-28 04:28