SuspendThread WOW64 приостанавливается в коде ядра - PullRequest
6 голосов
/ 10 ноября 2010

ОБНОВЛЕНИЕ : Microsoft еще не исправила это в Windows 8.1.

РЕДАКТИРОВАТЬ : Получилосьчтобы быть ошибкой в WOW64 - GetThreadContext () может вернуть устаревшее содержимое, когда поток приостановлен в длинном режиме ring-3 (пользовательский режим).Я предложил Microsoft использовать кольцо-2 для выполнения перевода.В этом случае SuspendThread будет только приостанавливать поток в кольце-3 (как это происходит сейчас - никаких изменений не требуется), а сбой / ошибка / эксплойт в кольце-2 не повлияет на ядро ​​- это повлияет только на кольцо-2 и кольцо-3.

Такие изменения потребуют изменения некоторых функций WinAPI, таких как Wow64Get / SetThreadContext и т. Д. Это приведет к поломке приложений, использующих недокументированные функции, но этого и следовало ожидать.Конечно, трансляция будет медленнее, поскольку для перехода от кольца 3 к кольцу 2 (в зависимости от семейства процессоров) требуется несколько циклов ЦП, но я думаю, что роль ОС - это прежде всего обеспечение правильной работы.Трансляция уже добавляет накладные расходы на приложения, работающие под WOW64, поэтому этого тоже следует ожидать.

Я действительно надеюсь, что Microsoft исправит эту проблему - в противном случае отладчики / моно-приложения / Boehm GC / приложения, использующие GetThreadContext () в разделеWOW64 не будет работать (для начала я видел, как отладчики показывают трассировку устаревшего стека).

EDIT2 : плохие новости.Из моего разговора с Алексеем из MSFT ( здесь ) это выглядит так, как будто оно вообще не может быть исправлено, опасаясь, что это исправит приложения, использующие недокументированные функции.


Оригинальный вопрос

  • Некоторые люди, похоже, смущены следующим.Первоначально я думал, что это произошло из-за приостановки потока SuspendThread в то время как в коде режима ядра.Не былоСледующее было просто моим первоначальным подозрением, которое, как оказалось, не имело ничего общего с действительной первопричиной - устаревшим содержимым, возвращаемым GetThreadContext().

из MSDN:

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

Однако я обнаружил, что мое 32-разрядное приложение в Windows 7, работающее под управлением WOW64, поток A, вызывающий SuspendThread в потоке B, может приостановить его, пока выполняется 64-разрядный код (который яможно ожидать, что не код режима пользователя).EIP показывает, что приостановленный поток остановился на

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

с измененным ESP (я знаю это, потому что, хотя ESP указывает на ту же страницу, что и стек этого потока, он имеет гораздо более высокий адрес, чем текущийуказатель стека).Если я поместил точку останова в инструкцию, к которой вернулось вышеизложенное, и затем возобновил поток, я обнаружил, что ESP возвращается к значению до вызова X86SwitchTo64BitMode (который является правильным указателем стека).Я также обнаружил, что при одном шаге в одну и ту же функцию я никогда не смогу получить более высокое значение ESP адреса в любой точке одного шага.На самом деле, при однократном шаге значение ESP никогда не изменяется до и после вызова X86SwitchTo64BitMode.

Кроме того, я удостоверился, что SuspendThread преуспел, проверив (DWORD) -1.

Все этизаставляет меня поверить, что поток приостановлен в коде режима ядра.

Что может быть причиной того, что ОС приостанавливает поток, пока выполняется код не в режиме пользователя?Как мне это предотвратить?Это в основном мешает мне получить фактический текущий указатель стека потока B. Обратите внимание, что когда приложение работает за пределами WOW64 (на собственной операционной системе x86), такой проблемы не существует.

Ответы [ 4 ]

3 голосов
/ 13 ноября 2010

Я подтвердил, что это проблема ОС, возвращающая устаревшее содержимое при вызове GetThreadContext в WOW64.

Подробнее здесь .

Спасибо всем, кто пытался ответить на этот вопрос. Я работаю с MS, чтобы решить эту проблему.

1 голос
/ 10 ноября 2010

См. Это объяснение: GetThreadContext в Wow64

В этой статье объясняется, что переход между режимами x86 и amd64 осуществляется в пользовательском режиме.

0 голосов
/ 10 ноября 2010

Что ваша нить делает в пользовательском режиме? Кажется, что он уже в режиме ядра, когда вы звоните SuspendThread. Возможно ли, что она выполняет системную функцию в тот момент, когда вы ее приостановили?

Что может быть причиной того, что ОС приостанавливает поток, пока выполняется код не в пользовательском режиме?

Многие системные или библиотечные вызовы могут привести к переключению в режим ядра. А поскольку в большинстве случаев ядро ​​Windows спроектировано для повторного входа, переключение с одного потока на другой, когда первый находится в режиме ядра, является вполне нормальным.

Как мне предотвратить это?

Просто идея: создайте поток, который просто выполняет пустой цикл (например, for(;;);), и приостановите этот поток. Этот не должен быть приостановлен в режиме ядра.


Кроме того, почему для вас важно, чтобы регистры ESP и т. Д. Были правильными? Я надеюсь, что вы пишете какой-то отладчик или что-то связанное, потому что это то, для чего SuspendThread.

0 голосов
/ 10 ноября 2010

Технически, когда поток вообще не работает, он не запускает ни кода режима ядра, ни кода режима пользователя. Так что ваши наблюдения не противоречат утверждению.

Beisdes, вы не должны возиться с этим. Было бы ошибкой ОС, если бы вы (в пользовательском режиме) могли контролировать выполнение кода режима ядра.

...