Win32 プロセス内で実行される最初のスレッドは「プライマリ スレッド」ですか?セマンティクスを理解する必要がある
-
13-12-2019 - |
質問
を使用してプロセスを作成します 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()
. 。テストのためにこれを省略した場合、スレッドが終了するのを待っているときの動作は変わりません。
解決
最初に実行するスレッドは特別なものではありません。
たとえば、一時停止されたスレッドを作成し、(ExitThread を呼び出して) 元のスレッドを終了するコンソール アプリを作成します。このプロセスは決して終了しません (Windows 7 ではとにかく)。
または、新しいスレッドを 5 秒間待機させてから終了します。予想通り、プロセスは 5 秒間存続し、セカンダリ スレッドが終了すると終了します。
あなたの例で何が起こっているのかわかりません。競合を回避する最も簡単な方法は、新しいスレッドを元のスレッドに再開させることです。
今推測すると、あなたのやっていることはいずれにしても問題を引き起こす可能性が低いのではないかと思います。たとえば、すべてに何が起こるかというと、 DllMain
暗黙的にロードされた DLL を呼び出しますか?これらは間違ったスレッドで予期せず発生しているのでしょうか、スキップされているのでしょうか、それともコードが実行されてメインスレッドが開始されるまで延期されているのでしょうか?
他のヒント
のスレッドが成立する可能性は高いです。 main
(または同等の) 関数呼び出し ExitProcess
(明示的に、またはランタイム ライブラリ内で)。 ExitProcess
, そうですね、すべてのスレッドの強制終了を含むプロセス全体を終了します。メインスレッドは挿入されたコードについて知らないため、コードが終了するのを待ちません。
メインスレッドが完了するまでメインスレッドを待機させる良い方法があるかどうかはわかりません...