Является ли первый поток, который запускается внутри процесса 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Ну, выходит из всего процесса, включая уничтожение всех потоков. Поскольку основной поток не знает о введенном вами коде, он не ждет его завершения.

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

Другие вопросы по тегам