Является ли первый поток, который запускается внутри процесса Win32, "основным потоком"? Нужно понимать семантику
Я создаю процесс, используя 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
возвращать.
Это происходит на Windows XP SP3, 32-битная.
Изменить: Я только что попробовал Sysinternals Process Monitor, чтобы увидеть, что происходит, и я мог проверить свои наблюдения из ранее. Внедренный код не аварийно завершает работу или что-то еще, вместо этого я вижу, что если я не жду потока, он не завершает работу, прежде чем закрыть программу, в которую был введен код. Я думаю, что вызов CloseHandle(hRemoteThread)
должно быть отложено или что-то...
Изменить +1: это не CloseHandle()
, Если я оставлю это только для теста, поведение не изменится при ожидании завершения потока.
2 ответа
Первый поток для запуска не особенный.
Например, создайте консольное приложение, которое создает приостановленный поток и завершает исходный поток (вызывая ExitThread). Этот процесс никогда не завершается (во всяком случае, в Windows 7).
Или заставьте новый поток подождать пять секунд, а затем выйдите. Как и ожидалось, процесс будет жить в течение пяти секунд и завершится, когда вторичный поток завершится.
Я не знаю, что происходит с твоим примером. Самый простой способ избежать гонки - заставить новую нить возобновить исходную нить.
Размышляя сейчас, я удивляюсь, если то, что вы делаете, вряд ли вызовет проблемы в любом случае. Например, что происходит со всеми DllMain
призывает к неявно загруженным DLL? Они неожиданно происходят в неправильном потоке, пропускаются или откладываются до тех пор, пока ваш код не запустится и основной поток не запустится?
Хорошие шансы, что нить с main
(или эквивалентные) вызовы функций ExitProcess
(явно или в своей библиотеке времени выполнения). ExitProcess
Ну, выходит из всего процесса, включая уничтожение всех потоков. Поскольку основной поток не знает о введенном вами коде, он не ждет его завершения.
Я не знаю, есть ли хороший способ заставить основной поток ждать завершения вашего...