1

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.

Répondre

0

Le premier thread à exécuter n'est pas spécial. Par exemple, créez une application de console qui crée un thread suspendu et termine le thread d'origine (en appelant ExitThread). Ce processus ne se termine jamais (sur Windows 7 de toute façon).

Ou faites le nouveau thread attendez cinq secondes, puis quittez. Comme prévu, le processus va vivre pendant cinq secondes et quitter lorsque le thread secondaire se termine.

Je ne sais pas ce qu'il se passe avec votre exemple. Le moyen le plus simple d'éviter la course est de faire en sorte que le nouveau fil reprenne le fil d'origine.

En spéculant maintenant, je me demande si ce que vous faites n'est pas susceptible de causer des problèmes de toute façon. Par exemple, qu'arrive-t-il à tous les appels DllMain pour les DLL implicitement chargées? Se produisent-ils de façon inattendue sur le mauvais fil, sont-ils ignorés, ou sont-ils reportés jusqu'à ce que votre code soit exécuté et que le fil principal commence?

+0

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

+0

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

+0

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

0

Les chances sont bonnes que le thread avec la fonction main (ou équivalent) appelle ExitProcess (explicitement ou dans sa bibliothèque d'exécution). ExitProcess, bien, quitte l'ensemble du processus, y compris la suppression de tous les threads. Comme le thread principal ne connaît pas votre code injecté, il n'attend pas qu'il finisse.

Je ne sais pas qu'il ya une bonne façon de faire le fil conducteur attente pour vous de compléter ...

+0

Comment? Comment le thread contenant 'main()' pourrait-il appeler 'ExitProcess()' si ti ne s'exécute pas? J'ai écrit dans ma question que le fil principal ne fonctionne pas avant le code injecté, quand je rencontre le problème. Quand ils fonctionnent "en parallèle", le problème ne se produit pas **. – 0xC0000022L

+0

Oh, mes excuses, j'ai mal interprété votre question. C'est un casse-tête. Votre thread se termine proprement, et ne quitte pas le processus, mais le processus meurt toujours? Étrange. –

+0

En effet, il est: -/... me rappelle de mettre des détails sur l'OS. – 0xC0000022L

Questions connexes