2015-12-21 2 views
0

Я хочу вставить часть кода в работающий модуль, используя метод приостановки потока.Изменение контекста заметной/ожидаемой темы

  1. SuspendThread
  2. GetThreadContext
  3. DoSomething
  4. ResumeThread

Мой вопрос заключается в том, что произойдет, если нить я в настоящее время инъекционный в извещающем/waitable режима (WaitForSingleObject, GetMessage) , что произойдет, как только я удалю команду ResumeThread.

+1

Рассмотрите возможность чтения [Функция SuspendThread приостанавливает поток, но делает это асинхронно] (https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743) и [Почему вы должны никогда не приостанавливать поток] (https://blogs.msdn.microsoft.com/oldnewthing/20031209-00/?p=41573). – IInspectable

+0

Я не уверен, как приостановление нити связано с инъекционным кодом, а я второй возражений IInspectable. Но SuspendThread/ReleaseThread не должен влиять на вызовы API, если вы их правильно используете. (Например, WaitForSingleObjectEx может сразу вернуться с WAIT_IO_COMPLETION, но если вы правильно обрабатываете этот случай, это не имеет значения.) –

+0

@IInpectable, вы даже прочитали ссылки, которые вы размахиваете здесь? Раймонд Чен говорит, что * «чтобы убедиться, что поток действительно приостановлен, вам необходимо выполнить синхронную операцию, зависящую от того, что поток приостановлен» * и сразу дает пример такого метода: * «Традиционный способ это нужно вызвать 'GetThreadContext' * *. Угадай, что? Это то, что он написал в OP. Подумайте о том, как читать ссылки, которые вы говорите другим людям, чтобы читать ** перед **, вы предлагаете им рассмотреть их чтение. – conio

ответ

1

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


Допустим, что целевая тема в данный момент находится в пользовательском режиме. Вы сохраните все регистры позже, установите RIP, чтобы указать на код и позвонить ResumeThread(). В какой-то момент ваш код начинает выполняться, делает все, что он делает, восстанавливает все регистры, сохраненные кодом впрыска, и позволяет программе возобновить нормальную работу.

Теперь можно сказать, что целевая нить ждет. Ожидание означает, что поток выполняет системный вызов, который сообщает планировщику не планировать поток для выполнения, пока что-то не произойдет (событие сигнализируется и т. Д.). Вы сохраняете регистры контекста пользовательского режима (так, как они были при вызове sysenter), установите RIP, чтобы указать на код и позвонить ResumeThread(). Это все хорошо и приятно, но планировщик по-прежнему не планирует его исполнять до тех пор, пока условия ожидания не будут удовлетворены.

После завершения ожидания поток завершает свою работу в режиме ядра, возвращается в пользовательский режим и вместо выполнения команды ret, следующей за sysenter, продолжает выполнять ваш код. Наконец, ваш код восстанавливает все регистры и переходит к сохраненному RIP (от ntdll!ZwWaitForSingleObject или тому подобное), и все продолжается как обычно.

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


так в основном то, что происходит то, что вы должны ожидать случиться:

  • Если вы вызвали SetThreadContext(), контекст пользовательского режима изменяется, и компьютер ведет себя соответственно, независимо от того, или нить ожидала, или нет.
  • Если поток ждал чего-то, он продолжает ждать того же, независимо от того, вы вызываете «SetThreadContext()» или нет.
  • Если поток был в ожидаемом ожидании, до того, как системный вызов будет возвращен, он будет уверен, что пользовательская APC-очередь пуста (либо потому, что есть пользовательские БТРы, и она вызвала их, либо потому, что очередь была пуста, а условие «обычного» ожидания наконец, произошло). Это, опять же, независимо от того, звоните ли вы SetThreadContext() или нет.
+1

Звучит как просить о бедствии для меня. Взаимодействие между частью пользовательского режима WaitForSingleObject и ядром не документировано, поэтому, когда ядро ​​следующее планирует поток и контекст был изменен, так что остальная часть WaitForSingleObject никогда не запускается ... ну, результат будет непредсказуемым , Почему бы не использовать CreateRemoteThread, как и все остальные? –

+0

Obviosly это низкоуровневая разработка, но не менее важно для некоторых приложений, специфичных для домена (приложения для обеспечения безопасности, приложения, которые взаимодействуют с драйверами ядра и т. Д.), Хороший ответ, +1. –

Смежные вопросы