Является ли первый поток, который запускается внутри процесса Win32, «основным потоком»?Нужно понять семантику

StackOverflow https://stackoverflow.com//questions/9695370

Вопрос

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

После этого я звоню 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 вернуться.

Это происходит в 32-разрядной версии Windows XP SP3.

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

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

Это было полезно?

Решение

Первый запущенный поток не является особенным.

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

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

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

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

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top