更新:微软还没有在Windows8.1中修复它。
编辑:这原来是WOW64中的错误 - GetThreadContext()可能会在长模式ring-3 (用户模式)中挂起线程时返回陈旧的内容。我已经向微软建议使用ring-2来执行翻译。然后,SuspendThread将只在ring-3中挂起线程(就像现在一样--没有必要的更改),而ring-2中的崩溃/故障/漏洞不会影响内核--它只会影响ring-2和ring-3。
这样的改变将需要更改一些WinAPI函数,如Wow64Get/SetThreadContext等。这将破坏依赖无文档化功能的应用程序,但这是意料之中的。当然,转换要慢一些,因为从ring-3过渡到ring-2需要几个CPU周期(取决于CPU系列),但我认为操作系统的作用首先是确保正确的操作。翻译已经增加了运行在WOW64下的应用程序的开销,所以这也是意料之中的。
我确实希望微软能够解决这个问题--否则在WOW64下依赖WOW64()的调试器/ Mono应用程序/ Boehm GC /应用程序将无法工作(首先,我已经看到调试器显示了陈旧的堆栈跟踪)。
EDIT2:坏消息。从我和微软(这里)的亚历克西的谈话来看,它看起来可能根本没有被修复,因为担心修复会破坏那些依赖于无文档功能的应用程序。
原始问题
GetThreadContext()返回的陈腐内容。来自MSDN:
Suspending a thread causes the thread to stop executing user-mode (application) code.
然而,我发现我在Windows 7下运行的32位应用程序,线程A调用线程B上的SuspendThread,可以在运行64位代码时暂停它(我想这不是用户模式代码)。EIP显示挂起的线程停止在
wow64cpu!X86SwitchTo64BitMode:
00000000`759c31b0 ea27369c753300 jmp 0033:759C3627由于它的ESP已经改变(我知道这一点,因为当ESP指向与该线程的堆栈相同的页面时,它的地址比当前堆栈指针高得多)。如果我在上面返回的指令上放置一个断点,然后让线程继续运行,我发现ESP会更改回X86SwitchTo64BitMode调用之前的值(这是正确的堆栈指针)。我还发现,当单步进入同一个函数时,在单个步骤的任何一点上,我都无法得到较高的地址ESP值。实际上,在单步执行时,ESP值在X86SwitchTo64BitMode调用之前和之后都不会发生变化。
此外,我还确保了SuspendThread通过检查(DWORD)-1而获得成功。
所有这些都使我相信线程在内核模式代码中是挂起的。
是什么原因导致操作系统在运行非用户模式代码时挂起线程?我怎么才能防止这种情况?这基本上阻止了我获得线程B的实际堆栈指针。注意,当应用程序运行在WOW64之外(在原生x86操作系统上)时,不存在这样的问题。
发布于 2010-11-13 05:58:01
我已经确认这是一个操作系统问题,当GetThreadContext在WOW64下被调用时,返回陈旧的内容。
这里有更多的信息。
感谢每一个试图回答这个问题的人。我正在和MS合作解决这个问题。
发布于 2010-11-10 13:47:33
参见以下解释:GetThreadContext in Wow64
本文解释了x86和amd64模式之间的转换是在用户模式下进行的.
发布于 2010-11-10 13:29:11
您的线程在用户模式下做什么?当您调用SuspendThread时,它似乎已经处于内核模式。是否有可能在挂起系统功能时执行系统功能?
是什么原因导致操作系统在运行非用户模式代码时挂起线程?
许多系统或库调用可能导致切换到内核模式。而且,由于Windows内核在大多数情况下都是可重入的,所以从一个线程切换到另一个线程,而第一个线程处于内核模式是非常正常的。
我怎么才能防止这种情况?
只是一个想法:创建一个只执行空循环(例如for(;;);)的线程,并挂起该线程。这个程序不应该在内核模式下挂起。
另外,为什么ESP寄存器等是否正确对你很重要?我希望您正在编写某种调试器或相关的东西,因为这就是SuspendThread的目的。
https://stackoverflow.com/questions/4144600
复制相似问题