Skip to content
← Tous les articles
· Delta1 Labs Glass.NETDécompilationGuide.NET

Décompiler une app .NET en fichier unique ou autonome avec Glass.NET

Vous avez publié une application .NET, vous glissez le .exe dans un décompilateur et rien de lisible n'en sort. Le problème n'est pas le décompilateur — c'est que dotnet publish possède plusieurs formats et que la plupart ne vous livrent pas d'assembly managé là où vous l'attendez. Voici où vit réellement votre IL dans un build autonome, en fichier unique, ReadyToRun ou Native AOT, et comment l'ouvrir dans Glass.NET.

Vous avez publié une application .NET. Vous voulez maintenant lire ce qui a réellement été livré — peut-être votre propre version dont le code source a disparu depuis longtemps, peut-être un outil dont vous enquêtez sur le comportement. Vous glissez donc le .exe dans Glass.NET et… rien d”utile n”en revient. Pas d”espaces de noms, pas de méthodes, pas de C# — juste un stub, ou un refus net. Il est tentant de conclure que le décompilateur est cassé. Il ne l”est pas. Le problème, c”est que dotnet publish possède plusieurs formats de sortie, et que la plupart ne placent pas d”assembly managé décompilable au chemin que vous visez d”instinct.

Une fois que vous savez quel format vous tenez et où vit réellement son IL managé, la décompilation elle-même est la partie facile. Cet article parcourt les formats — autonome, fichier unique, ReadyToRun et Native AOT — indique exactement où se trouve l”IL lisible dans chacun (ou, en toute honnêteté, quand il n”y en a aucun), puis exécute le flux normal de Glass dessus. Glass.NET est gratuit et purement statique : il lit les métadonnées et l”IL de l”assembly managé et reconstruit le C#, et n”exécute jamais l”application qu”il inspecte. Cela compte doublement ici, car une application publiée est précisément ce que vous auriez autrement dû exécuter pour découvrir ce qu”elle fait.

Ce qui trompe tout le monde : l”apphost n”est pas votre code

Le dotnet publish moderne enveloppe votre programme dans un lanceur natif appelé apphost — le MyApp.exe que vous lancez d”un double-clic. L”apphost est un petit amorceur natif, et son seul rôle est de démarrer le runtime .NET et de le pointer vers votre assembly managé. C”est du code machine natif ; il ne contient aucun de votre C#. Un décompilateur lit des assemblys managés — IL plus métadonnées — donc le viser vers l”apphost .exe, c”est le viser vers le mauvais fichier, tout simplement.

Votre code est dans une .dll managée. Que cette DLL soit à côté de l”apphost ou cachée à l”intérieur est la seule vraie variable, et elle est décidée par le format de publication. Toute la tâche se réduit donc à une question : où est la DLL managée ? Voici la réponse, format par format.

Autonome : ouvrez la DLL managée, pas le .exe

Une publication autonome livre votre application avec sa propre copie privée du runtime .NET, pour qu”elle tourne sur une machine sans .NET installé. Ouvrez le dossier de publication et vous verrez une foule de fichiers : l”apphost natif MyApp.exe, des dizaines d”assemblys du runtime (System.*.dll, Microsoft.*.dll), quelques bibliothèques natives (*.dll, *.so, *.dylib) — et, juste là sur le disque, celui que vous voulez : votre propre assembly managé, MyApp.dll.

Ce MyApp.dll est exactement ce que le compilateur C# a émis — de l”IL ordinaire et des métadonnées complètes. Ouvrez celui-là dans Glass (Fichier ▸ Ouvrir un assembly, ou glissez-le sur la fenêtre), pas le .exe. L”apphost à côté est un leurre ; ignorez-le. Autonome n”est pas fichier unique sauf si vous l”avez aussi demandé, donc par défaut rien n”est empaqueté et rien n”a besoin d”être extrait — la DLL managée est déjà sur le disque, prête à lire. Si vous ne savez pas laquelle des nombreuses DLL est la vôtre, triez par nom et cherchez le nom de votre assembly, ou ouvrez une candidate et vérifiez dans la vue d”information de l”assembly vos attributs de produit plutôt qu”une identité System.*.

Fichier unique : extrayez d”abord le bundle, puis ouvrez la DLL

Une publication en fichier unique (PublishSingleFile) va un cran plus loin. Elle prend ces assemblys managés et les intègre dans l”apphost .exe sous forme de ressources, pour que vous distribuiez un fichier au lieu d”un dossier. L”IL managé est toujours là-dedans, octet pour octet inchangé — mais il est empaqueté dans l”hôte natif, il n”y a donc aucune MyApp.dll sur le disque que Glass puisse ouvrir. Glass lit des assemblys managés ; il n”ouvre pas un bundle natif à votre place. Vous extrayez donc d”abord le bundle avec le mécanisme standard de .NET, puis ouvrez la DLL qui en sort.

L”extracteur est intégré au runtime. Pointez DOTNET_BUNDLE_EXTRACT_BASE_DIR vers un répertoire et lancez l”application une fois ; l”hôte y désempaquette ses assemblys intégrés avant de se lancer :

# application en fichier unique : désempaqueter les assemblys intégrés sur le disque
DOTNET_BUNDLE_EXTRACT_BASE_DIR=./extracted ./MyApp
# ./extracted/<appname>/<hash>/MyApp.dll  — IL managé ordinaire, prêt pour Glass

Une réserve honnête : cette méthode exécute l”application pour qu”elle s”auto-extraie. Pour votre propre version, aucun souci. Pour un binaire auquel vous ne faites pas confiance, ne le lancez pas — recourez plutôt à un extracteur de bundle autonome qui lit la structure documentée du bundle et écrit les DLL intégrées sur le disque sans lancer l”exécutable. Dans les deux cas vous obtenez MyApp.dll sur le disque, et à partir de là Glass reste pleinement statique : il n”ouvre jamais que la DLL déjà extraite. Déposez ce MyApp.dll sur Glass et vous voilà de retour à une décompilation ordinaire.

ReadyToRun : il y a toujours de l”IL en dessous, il se décompile sans souci

ReadyToRun (PublishReadyToRun) est facile à redouter sans raison. R2R précompile une image native de vos méthodes de façon anticipée pour réduire le coût de démarrage — mais il conserve l”IL d”origine à côté de cette image native comme solution de repli. Le résultat reste un assembly managé parfaitement ordinaire, avec métadonnées et IL complets. Glass lit un assembly R2R exactement comme n”importe quelle autre DLL ; le code natif précompilé est simplement ignoré, et vous décompilez l”IL comme d”habitude. R2R change la vitesse de démarrage de votre application, pas le fait qu”on puisse la lire.

Native AOT : il n”y a rien à décompiler — pour personne

Native AOT (PublishAot) est l”exception honnête, et il vaut la peine d”être direct. AOT compile votre IL jusqu”au code machine natif de façon anticipée et jette l”IL. L”artefact publié est un vrai binaire natif : pas d”assembly managé, pas de métadonnées, pas d”IL. Il n”y a rien que Glass — ni ILSpy, ni dotPeek, ni aucun décompilateur .NET — puisse reconstruire, car ce qu”un décompilateur lit a été compilé et a disparu. Ce n”est pas une limite de Glass ; c”est la nature du format, et aucun décompilateur ne peut ramener du code natif vers le C# qui l”a produit. S”il vous faut analyser un binaire NativeAOT, vous êtes en terrain de rétro-ingénierie native — un désassembleur natif — pas de décompilation .NET. (Une échappatoire pratique : beaucoup d”applications réelles ne sont que partiellement AOT, et tout assembly managé laissé hors de l”image AOT redevient une DLL normale et décompilable. Les compromis de protection derrière tout cela sont traités dans obfusquer les applications Native AOT et fichier unique.)

Ensuite, c”est le flux normal de Glass

Une fois que vous avez la DLL managée sur le disque — directement issue d”un dossier autonome, ou extraite d”un bundle en fichier unique — tout ce qui suit est le flux ordinaire de Glass, le même que dans comment décompiler une DLL .NET en C# :

  • Ouvrez-la et orientez-vous. Glass charge les métadonnées et déploie l”assembly en un arbre espaces de noms ▸ types ▸ membres. Jetez d”abord un œil à la vue d”information de l”assembly — framework cible et assemblys référencés — pour confirmer que vous avez pris votre assembly et non un assembly du runtime venu en passager clandestin dans le dossier de publication.
  • Décompilez en C#. Cliquez sur n”importe quel type ou membre et Glass reconstruit du C# lisible à la demande. Vous n”avez pas besoin d”un PDB correspondant ; les métadonnées portent les vrais noms de types et de méthodes, et Glass synthétise les noms de variables locales quand les symboles manquent.
  • Descendez à l”IL quand le C# est ambigu. Basculez le même membre sur la vue IL quand une méthode async ou un itérateur reconstruit se lit bizarrement — l”IL est ce qui s”exécute réellement, c”est donc la vérité de terrain. (Lire l”IL le parcourt.)
  • Exportez vers un projet. Quand vous voulez le code sur le disque pour le grep, le comparer ou l”ouvrir dans un IDE, Fichier ▸ Exporter vers un projet (ou la CLI glass export) écrit un .csproj plus les fichiers .cs reconstruits. Le parcours complet est dans exporter un assembly vers un projet compilable.

À retenir

Le format de publication est une décision d”empaquetage. Il change où vit votre IL managé, pas le fait qu”on puisse le lire. Autonome laisse la DLL sur le disque — ouvrez-la, pas l”apphost. Fichier unique la cache dans l”apphost — extrayez le bundle, puis ouvrez la DLL. ReadyToRun conserve l”IL — ouvrez l”assembly directement. Native AOT compile l”IL et le fait disparaître — et là, il n”y a véritablement rien à décompiler, pour Glass ni pour personne. Sachez lequel vous tenez et la décompilation est à deux clics. Et comme Glass.NET est gratuit et purement statique, vous lisez le tout sans en exécuter une seule ligne. Téléchargez Glass.NET, pointez-le vers la DLL managée et lisez ce qui a été livré.

Essayez Nebula.NET

Renforcez votre code .NET en quelques minutes — commencez avec l'édition gratuite.