58 votes

Forcer le CLR x86 sur une assemblée .NET "tout processeur".

Dans .NET, l'option de compilation "Platform Target : Any CPU' permet à une assembly .NET de s'exécuter en 64 bits sur une machine x64, et en 32 bits sur une machine x86. Il est également possible de forcer un assemblage à s'exécuter en x86 sur une machine x64 en utilisant l'option de compilation "Platform Target : x86".

Est-il possible d'exécuter un assembly avec le drapeau 'Any CPU', mais de déterminer s'il doit être exécuté dans le CLR x86 ou x64 ? Normalement, cette décision est prise par le chargeur CLR/OS (d'après ce que j'ai compris) sur la base du bitness du système sous-jacent.

J'essaie d'écrire une application C# .NET qui peut interagir avec (lire : injecter du code dans) d'autres processus en cours d'exécution. Les processus x64 ne peuvent injecter que dans d'autres processus x64, et de même avec x86. Idéalement, j'aimerais profiter de la compilation JIT et de la fonction Toute unité centrale pour permettre à une seule application d'être utilisée pour injecter dans les processus x64 ou x86 (sur une machine x64).

L'idée est que l'application soit compilée en tant que Toute unité centrale . Sur une machine x64, il s'exécuterait en tant que x64. Si le processus cible est x86, il devrait se relancer lui-même, forçant le CLR à l'exécuter en x86. Cela est-il possible ?

61voto

Ohad Horesh Points 2153

Vous pouvez connaître le mode d'exécution d'une application et le modifier de manière statique à l'aide de la commande CorFlags application. Pour savoir comment l'application fonctionnera, utilisez :

corflags <PathToExe>

Pour modifier le mode d'exécution de l'application, utilisez :

corflags /32bit+  <PathToExe>

Le fichier EXE s'exécutera alors comme un processus 32 bits. Les informations sur la façon dont l'assemblage doit s'exécuter sont stockées dans l'en-tête PE. Voir la question de Stack Overflow Comment savoir si un fichier DLL natif est compilé en x64 ou x86 ? .

Si vous souhaitez injecter du code au moment de l'exécution, vous devez écrire un fichier .NET profiler dans C++ /COM. Voir Internes .NET : L'API de profilage y Profilage (référence API non gérée) pour plus de détails.

Vous devrez implémenter le callback JitCompilationStarted et faire votre travail à cet endroit. Si vous allez dans cette direction, vous devrez construire le fichier DLL d'injection à la fois en x86 et en x64. Les fichiers DLL natifs seront chargés par la commande CLR une fois que les variables d'environnement suivantes seront définies :

Cor_Enable_Profiling=0x1
COR_PROFILER={CLSID-of-your-native-DLL-file}

Si vous l'avez correctement configuré, la version 64 bits "verra" les processus 64 bits et la version 32 bits "verra" les processus 32 bits.

0 votes

Merci pour l'info :) Je connaissais l'application corflags, mais je me demandais s'il y avait un moyen d'obtenir un résultat similaire par programmation au moment de l'exécution.

1 votes

Une fois que le processus est en cours d'exécution, il est impossible de modifier son contexte !

0 votes

Changer le contexte au moment de l'exécution ne signifie pas simplement définir un bit dans l'en-tête PE, un processus 32 bits fonctionne sous la couche d'émulation WOW. Je ne vois pas comment un processus peut sauvegarder son état au moment de l'exécution, faire un changement de contexte et continuer à fonctionner. Voir ce lien : blogs.msdn.com/oldnewthing/archive/2008/12/22/9244582.aspx

9voto

user123067 Points 1298

Cela fait un moment que je n'ai pas essayé, mais je crois que le bitness du processus qui appelle l'assemblage détermine s'il sera JITé en x86 ou x64.

Ainsi, si vous écrivez une petite application de console et que vous la construisez en x86, et une autre en x64, l'exécution de l'une ou l'autre entraînera l'exécution des autres assemblages chargés dans le processus en 32 ou 64 bits. Ceci, bien sûr, suppose que vous vous exécutez sur une machine 64 bits.

4 votes

Oui, je suis conscient que vous pouvez le forcer en l'intégrant dans un assemblage de lanceur x86, mais je me demandais si vous pouviez le forcer dynamiquement pour les assemblages compilés 'Any CPU'. Merci en tout cas, je reviendrai probablement à cette solution si je ne trouve rien d'autre. Je l'aurais bien noté mais je n'ai pas assez de représentants.

1 votes

Les processus sont soit 64 bits, soit 32 bits. Si l'assemblage est chargé dans un processus 32 bits et qu'il est construit en tant que Any CPU, il sera JITé en 32 bits, dans un processus 64 bits, il sera JITé en 64. Comment envisagez-vous de créer l'assemblage qui héberge vos assemblages ?

6voto

Graviton Points 28358

Je ne sais pas si je peux vous aider. Mais voici mon expérience.

J'ai une demande d'accueil, A.exe ( compilé en x86), et j'ai une application client, B.exe ( compilé en tant que ANY CPU ), de l'application hôte. Et je lance B.exe de A.exe en utilisant le System.Diagnostic.Process classe.

Le problème est que si je mets les deux sur une machine x64, alors A.exe s'exécutera en tant que x86, alors que le B.exe fonctionnera en x64 .

Mais si A.exe appelle l'assemblage c ( c.dll qui est compilé sous la forme Any CPU ), et B.exe appelle également c.dll alors c.dll suivra l'application qui l'appelle. En d'autres termes, sur une machine 64 bits, lorsque A.exe l'appelle, il se comportera comme x86 dll, alors que lorsque B.exe l'appelle, il se comportera comme x64 .

6voto

KarlW Points 131

J'ai fait quelque chose de similaire en créant deux (vraiment trois) binaires. Le premier détectait si le processus dans lequel j'essayais d'injecter était 32 ou 64 bits. Ce processus lancera alors la version 32 ou 64 bits de votre binaire d'injection (et non pas se relancer lui-même comme vous l'avez mentionné).

Cela peut sembler compliqué, mais vous pouvez facilement réaliser cela au moment de la construction avec un événement post-construction qui fait une copie de votre binaire de sortie et utilise la fonction CorFlags pour forcer la copie à s'exécuter en 32 bits. De cette façon, vous n'avez pas à déployer l'utilitaire CorFlags avec votre application, ce qui n'est probablement pas légal pour une raison quelconque de toute façon.

Je pense que cela est assez similaire à votre idée initiale et ne nécessite pas vraiment plus de travail, sauf pour un événement de construction de deux lignes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X