Je crée un processus en utilisant CreateProcess()
avec le CREATE_SUSPENDED
puis je crée un petit patch de code dans le processus distant pour charger une DLL et appeler une fonction (exportée par cette DLL), en utilisant VirtualAllocEx()
(avec ..., MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE
), WriteProcessMemory()
, puis appelez FlushInstructionCache()
sur ce patch de la mémoire avec le code.Le premier thread qui s'exécute dans un processus Win32 est-il le "thread principal"? Besoin de comprendre la sémantique
Ensuite, j'appelle CreateRemoteThread()
pour invoquer ce code, en me créant un hRemoteThread
. J'ai vérifié que le code à distance fonctionne comme prévu. Remarque: ce code renvoie simplement, il n'appelle aucune API autre que LoadLibrary()
et GetProcAddress()
, suivi de l'appel de la fonction de remplacement exportée qui renvoie actuellement simplement une valeur qui sera ensuite transmise en tant que statut de sortie du thread.
Maintenant vient l'observation particulière: rappelez-vous que le PROCESS_INFORMATION::hThread
est toujours suspendu. Quand j'ignore simplement le code de sortie de hRemoteThread
et n'attends pas non plus qu'il sorte, tout va "bien". La routine qui appelle CreateRemoteThread()
renvoie et PROCESS_INFORMATION::hThread
est reprise et le programme (distant) s'exécute réellement.
Cependant, si je l'appelle WaitForSingleObject(hRemoteThread, INFINITE)
ou effectuer les opérations suivantes (qui a le même effet):
DWORD exitCode = STILL_ACTIVE;
while(STILL_ACTIVE == exitCode)
{
Sleep(500);
if(!GetExitCodeThread(hRemoteThread, &exitCode))
break;
}
suivie CloseHandle()
cela conduit à hRemoteThread
finition avant PROCESS_INFORMATION::hThread
reprend et obtient le processus simplement « disparait ». Il suffit de laisser hRemoteThread
finir en quelque sorte sans PROCESS_INFORMATION::hThread
pour provoquer la mort du processus.
Cela ressemble étrangement à une condition de concurrence, puisque dans certaines circonstances, hRemoteThread
peut être encore plus rapide et le processus pourrait encore "disparaître", même si je laisse le code tel quel. Cela implique-t-il que le premier thread qui s'exécute dans un processus devient automatiquement le thread principal et qu'il existe des règles spéciales pour ce thread primaire?
J'ai toujours eu l'impression qu'un processus se termine lorsque son dernier fil meurt, pas quand un meurt.
Notez également: il n'y a pas d'appel à ExitProcess()
impliqué ici de quelque façon, parce que hRemoteThread
retourne simplement et PROCESS_INFORMATION::hThread
est toujours suspendu quand j'attends hRemoteThread
retourner. Cela se produit sur Windows XP SP3, 32 bits.
Modifier: Je viens d'essayer Sysinternals Process Monitor pour voir ce qui se passe et j'ai pu vérifier mes observations d'avant. Le code injecté ne tombe pas en panne ou quoi que ce soit, à la place je vois que si je n'attends pas le thread, il ne se ferme pas avant de fermer le programme où le code a été injecté. Je pense que l'appel à CloseHandle(hRemoteThread)
devrait être reportée ou quelque chose ...
Modifier + 1: ce n'est pas CloseHandle()
. Si je laisse cela juste pour un test, le comportement ne change pas en attendant que le thread finisse.
s'il vous plaît expliquer le dernier point. Je ** sais ** cela causera des problèmes à supposer qu'une DLL est chargée au même addr de base. Dans mon processus comme dans le processus distant, un bon vieux 'LoadLibrary' explicite passé à' CreateRemoteThread' ne volera pas - c'est pourquoi de cette façon. En outre, lorsque le thread principal est suspendu après la création du processus, les DLL ont déjà été chargées, même si je ne suis pas certain que leur DllMain ait été appelé par la suite. Mais cela ne devrait pas vraiment avoir d'importance tant que je n'appelle pas 'LoadLibrary' après que le thread principal commence à démarrer et pourrait être dans un' DllMain' lui-même. Thx – 0xC0000022L
Windows normalement ne verra jamais un appel à 'LoadLibrary' avant que les DLL statiques aient initialisé. Cela pourrait éventuellement causer des problèmes. Alternativement, si les DllMains statiques sont appelés sur votre thread, cela pourrait confondre les DLL qui supposent que le thread d'initialisation durera toute la vie du processus, ce qui est généralement vrai. Comme je l'ai dit, je spécule, mais il semble y avoir beaucoup de potentiel de bris. – arx
Hmm, d'accord. Comment puis-je vérifier si les 'DllMain's des autres DLL ont été appelés? De l'expérience passée je sais que je ne devrais même pas pouvoir appeler 'CreateRemoteProcess' avec succès à moins que' kernel32.dll' ait été initialisé et une connexion à Win32 établie. Cependant, l'appel à 'CreateRemoteProcess' ** est ** réussi ici. C'est toujours possible que tu aies raison, mais je ne le pense pas pour le moment. – 0xC0000022L