1

Создаю процесс с помощью CreateProcess() с помощью CREATE_SUSPENDED, а затем создайте небольшой фрагмент кода внутри удаленного процесса для загрузки DLL и вызова функции (экспортируемой этой DLL) с использованием VirtualAllocEx()..., MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE), WriteProcessMemory(), затем позвоните FlushInstructionCache() на этом патче памяти с кодом.Является ли первый поток, который запускает внутри процесса Win32 «основной поток»? Необходимо понять семантику

После этого я вызываю CreateRemoteThread(), чтобы вызвать этот код, создав мне hRemoteThread. Я проверил, что удаленный код работает по назначению. Примечание: этот код просто возвращается, он не вызывает никаких API, отличных от LoadLibrary(), и GetProcAddress(), а затем вызывает экспортированную функцию заглушки, которая в настоящее время просто возвращает значение, которое затем будет передано в качестве статуса выхода потока.

Теперь приходит своеобразное наблюдение: помните, что PROCESS_INFORMATION::hThread все еще приостановлен. Когда я просто игнорирую код выхода hRemoteThread, а также не дожидаюсь его выхода, все идет «отлично». Подпрограмма, которая вызывает CreateRemoteThread(), возвращается и PROCESS_INFORMATION::hThread возобновляется, и (удаленная) программа фактически запускается.

Однако, если я позвоню WaitForSingleObject(hRemoteThread, INFINITE) или сделать следующее (который имеет тот же эффект):

DWORD exitCode = STILL_ACTIVE; 
while(STILL_ACTIVE == exitCode) 
{ 
    Sleep(500); 
    if(!GetExitCodeThread(hRemoteThread, &exitCode)) 
     break; 
} 

затем CloseHandle() это приводит к hRemoteThread отделки, прежде чем PROCESS_INFORMATION::hThread получает возобновился и процесс просто «исчезает». Достаточно разрешить hRemoteThread закончить как-то без PROCESS_INFORMATION::hThread, чтобы заставить процесс умереть.

Это выглядит подозрительно, как состояние гонки, так как при определенных обстоятельствах hRemoteThread все еще может быть быстрее, и процесс, скорее всего, «исчезнет», даже если я оставлю код как есть.

Означает ли это, что первый поток, который запускается в процессе, становится автоматически основным потоком и что существуют специальные правила для этого первичного потока?

У меня всегда было впечатление, что процесс заканчивается, когда его последняя нить умирает, а не когда конкретно нить умирает.

Также обратите внимание: нет вызова ExitProcess() участвует здесь в любом случае, потому что hRemoteThread просто возвращает и PROCESS_INFORMATION::hThread все еще приостановлено, когда я жду hRemoteThread вернуться.

Это происходит в Windows XP SP3, 32 бит.

Редактировать: Я только что попробовал Монитор процессов Sysinternals, чтобы посмотреть, что происходит, и я мог проверить мои наблюдения раньше. Введенный код не терпит крах или что-то еще, вместо этого я вижу, что если я не буду ждать, пока поток не завершится, я закрою программу, в которую был введен код. Я имею в виду, следует ли отложить или что-то вызов CloseHandle(hRemoteThread) ...

Edit + 1: это не CloseHandle(). Если я оставлю это только для теста, поведение не изменится при ожидании завершения потока.

ответ

0

Первый поток для запуска не является специальным.

Например, создайте консольное приложение, которое создает приостановленный поток и завершает исходный поток (путем вызова ExitThread). Этот процесс никогда не заканчивается (в Windows 7 в любом случае).

Или сделайте новый поток подождите пять секунд, затем выйдите. Как и ожидалось, процесс будет жить в течение пяти секунд и выйти, когда вторичная нить завершается.

Я не знаю, что происходит с вашим примером. Самый простой способ избежать гонки - заставить новый поток возобновить исходный поток.

Спекулируя сейчас, я задаюсь вопросом, не приведет ли то, что вы делаете, в любом случае вызвать проблемы. Например, что происходит со всеми DllMain, вызывает неявно загруженные библиотеки DLL? Неужели они неожиданно происходят в неправильной теме, их пропускают, или они откладываются до тех пор, пока ваш код не запустится и не начнется основной поток?

+0

, пожалуйста, объясните последний пункт. Я ** знаю **, это вызовет проблемы, предполагающие, что DLL загружается в том же базовом addr. в моем процессе, как в удаленном процессе, поэтому явная старая «LoadLibrary», переданная в «CreateRemoteThread», не будет летать - вот почему так. Кроме того, когда основной поток приостанавливается после создания процесса, библиотеки DLL уже загружены, хотя я не уверен, был ли их DllMain' уже вызван. Но это не имеет значения, если я не буду называть свою «LoadLibrary» после того, как основной поток начнет запускаться и может находиться внутри самого «DllMain». Thx – 0xC0000022L

+0

Windows обычно не увидит вызов «LoadLibrary» до инициализации статических DLL. Это может вызвать проблемы. В качестве альтернативы, если статические DllMains вызываются в вашем потоке, это будет путать библиотеки DLL, которые предполагают, что поток инициализации будет длиться всю жизнь процесса, что обычно верно. Как я уже сказал, я размышляю, но, похоже, есть много возможностей для поломки. – arx

+0

Хм, хорошо. Как я могу проверить, были ли вызваны «DllMain's» из других DLL? Из прошлого опыта я знаю, что я даже не смог бы назвать 'CreateRemoteProcess' успешным, если только' kernel32.dll' не был инициализирован, и установлено соединение с Win32. Однако вызов 'CreateRemoteProcess' ** здесь ** успешно. По-прежнему возможно, что вы правы, но я так не думаю в данный момент. – 0xC0000022L

0

Коэффициенты хороши тем, что нить с функцией main (или эквивалентной) вызывает ExitProcess (либо явно, либо в своей библиотеке времени исполнения). ExitProcess, хорошо, завершает весь процесс, включая убийство всех потоков. Поскольку основной поток не знает о вашем введенном коде, он не дожидается завершения его.

Я не знаю, что есть хороший способ сделать основной поток должен ожидать твое, чтобы закончить ...

+0

Как? Как бы поток, содержащий 'main()', мог вызывать 'ExitProcess()', если ti не запускается. Я писал в своем вопросе, что основной поток не запускается до введенного кода, когда я сталкиваюсь с проблемой. Когда они запускаются «параллельно», проблема возникает ** не **. – 0xC0000022L

+0

О, мои извинения, я неправильно понял ваш вопрос. Это головоломка. Ваша нить завершается чисто и не выходит из процесса, но процесс все еще умирает? Странный. –

+0

Действительно: -/... напоминает мне о подробностях об ОС. – 0xC0000022L

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