Besoin d'un audit de sécurité ?
Devis personnalisé sous 24h
Rétro-Ingénierie / .NET

Reverse Engineering .NET : Décompilation, Analyse et Protection du Code Managé

Par Ayi NEDJIMI 1 mars 2026 Lecture : 30 min ~5000 mots
#ReverseEngineering #DotNET #Décompilation #dnSpy #Malware #Obfuscation

1. Introduction : pourquoi le reverse engineering .NET est incontournable

Le framework .NET de Microsoft est devenu l'un des environnements de développement les plus répandus au monde, propulsant des applications d'entreprise, des services cloud Azure et -- de façon croissante -- des malwares sophistiqués. Contrairement au code natif compilé en instructions machine, le code .NET est compilé en Intermediate Language (IL/MSIL), un bytecode riche en métadonnées qui se prête remarquablement bien à la décompilation. Cette caractéristique fondamentale fait du reverse engineering .NET une discipline à part entière, plus accessible que l'analyse binaire x86/x64 mais néanmoins confrontée à des défis croissants avec l'adoption massive de l'obfuscation.

Les chiffres parlent d'eux-mêmes : selon les rapports ANY.RUN et VirusTotal de 2025, plus de 40 % des malwares Windows analysés sont développés en .NET. Des familles comme AgentTesla, AsyncRAT, NjRAT, RedLine Stealer et Quasar RAT dominent le paysage des menaces, toutes écrites en C# et exploitant les facilités du framework pour l'accès réseau, la manipulation du registre et l'injection de processus. Pour les analystes SOC, les chercheurs en threat intelligence et les reverse engineers, maîtriser l'analyse .NET n'est plus une option -- c'est une compétence de survie.

Ce guide exhaustif couvre l'ensemble du workflow d'analyse .NET : de la compréhension de l'architecture CLR jusqu'aux techniques avancées de déobfuscation, en passant par le debugging IL, l'analyse de malwares réels et les stratégies de protection du code managé. Chaque section propose des exemples concrets, des commandes reproductibles et des liens vers nos ressources complémentaires sur l'anti-rétro-ingénierie utilisée par les APT et la déobfuscation de malwares polymorphes.

Cadre légal : Le reverse engineering à des fins de sécurité, d'interopérabilité ou de recherche est protégé par la directive européenne 2009/24/CE (article 6) et par le DMCA (section 1201(f)) aux États-Unis. Toutefois, respectez toujours les termes de licence des logiciels analysés et les lois de votre juridiction.

Prérequis techniques

Cet article suppose une familiarité avec le développement C# ou VB.NET, les concepts fondamentaux de la compilation et une machine virtuelle isolée pour l'analyse de malwares. Pour le guide général d'analyse malware, consultez notre article dédié.

2. Architecture .NET : CLR, IL/MSIL, JIT et Assemblies

2.1 Le Common Language Runtime (CLR)

Le CLR est le moteur d'exécution de .NET, l'équivalent de la JVM pour Java. Il fournit un environnement managé qui gère la mémoire (garbage collector), la sécurité (Code Access Security, désormais déprécié dans .NET Core), le chargement des types et la compilation Just-In-Time (JIT). Comprendre le CLR est fondamental pour le reverse engineering car c'est lui qui transforme le bytecode IL en code natif exécutable.

L'architecture du CLR se décompose en plusieurs composants critiques pour l'analyste :

  • Class Loader : charge les assemblies et résout les dépendances. Point d'interception pour les techniques d'injection (Assembly.Load, Assembly.LoadFrom).
  • JIT Compiler (RyuJIT) : compile le code IL en code natif à la volée, méthode par méthode. Le code natif généré peut être capturé avec WinDbg + SOS pour une analyse post-JIT.
  • Garbage Collector (GC) : gestion automatique de la mémoire avec trois générations. Les malwares .NET peuvent manipuler le GC pour éviter la détection en mémoire.
  • Type System : définit la hiérarchie des types (classes, interfaces, structs, enums). Les métadonnées de types sont la clé de la décompilation réussie.
  • Exception Handler : gestion structurée des exceptions (SEH managé). Les obfuscateurs utilisent intensivement les blocs try/catch/finally pour complexifier le control flow.

2.2 Intermediate Language (IL/MSIL/CIL)

L'Intermediate Language -- appelé IL, MSIL (Microsoft Intermediate Language) ou CIL (Common Intermediate Language) -- est un bytecode stack-based, conceptuellement similaire au bytecode Java mais avec des spécificités propres à .NET. Chaque instruction IL manipule une pile d'évaluation (evaluation stack) : les opérandes sont poussés sur la pile, les opérations consomment les éléments du sommet et poussent le résultat.

Les instructions IL les plus fréquemment rencontrées en analyse de malwares :

// Instructions de chargement (Load)
ldstr "http://c2server.evil.com"    // Charge une chaîne sur la pile
ldarg.0                             // Charge le premier argument (this pour les méthodes d'instance)
ldc.i4 0x1337                       // Charge un entier 32 bits
ldsfld class Malware.Config::Key    // Charge un champ statique

// Instructions d'appel
call void [System.Net.Http]System.Net.Http.HttpClient::GetAsync(string)
callvirt instance string [mscorlib]System.IO.StreamReader::ReadToEnd()
newobj instance void Malware.Payload::.ctor()

// Instructions de contrôle de flux
br.s IL_0042          // Branch inconditionnelle (jump)
brfalse.s IL_0028     // Branch si false/null/0
brtrue IL_005A        // Branch si true/non-null/non-0
ret                   // Return

// Instructions de stockage
stloc.0               // Stocke le sommet de la pile dans la variable locale 0
stfld string Malware.Config::C2Url  // Stocke dans un champ d'instance

Une particularité essentielle du IL pour le reverse engineering : chaque instruction référence des metadata tokens qui pointent vers les tables de métadonnées de l'assembly. Cela signifie que même sans symboles de debug, on dispose des noms de types, méthodes, champs et paramètres -- un luxe inexistant en analyse de binaires natifs. C'est pourquoi les obfuscateurs .NET se concentrent en priorité sur le renommage de ces éléments.

2.3 Structure des assemblies .NET (PE + métadonnées)

Un assembly .NET est un fichier PE (Portable Executable) augmenté de structures spécifiques au CLR. L'en-tête PE standard contient un répertoire CLR Header (aussi appelé COM+ Runtime Header, à l'offset DataDirectory[14]) qui pointe vers les métadonnées .NET. Cette structure est critique car c'est elle que les outils de décompilation analysent en premier.

Les tables de métadonnées (Metadata Tables) constituent le coeur de l'assembly et contiennent :

Table Contenu Intérêt pour le RE
TypeDef Définitions de types (classes, structs) Structure du programme, hiérarchie de classes
MethodDef Définitions de méthodes + RVA du code IL Points d'entrée, fonctions critiques
Field Champs des types Configurations, clés, URLs
MemberRef Références vers des membres externes APIs utilisées (réseau, crypto, fichiers)
AssemblyRef Assemblies référencées Dépendances, frameworks utilisés
UserString Chaînes littérales du code URLs C2, clés de chiffrement, messages
StandAloneSig Signatures de variables locales Compréhension des fonctions
CustomAttribute Attributs personnalisés Obfuscation markers, Confuser tags
Pipeline de Compilation .NET & Points d'Analyse Code Source C# / VB.NET F# Compilateur Roslyn / csc vbc / fsc Assembly .NET PE Header + CLR Header IL/MSIL Bytecode Metadata Tables Resources / Manifest CLR + JIT RyuJIT Compiler Runtime Code Natif x86/x64/ARM Exécution CPU Points d'Analyse du Reverse Engineer Analyse Statique (IL) dnSpy, ILSpy, dotPeek Décompilation IL → C# Analyse Dynamique dnSpy Debugger, breakpoints IL Intercept réseau, API Monitor Déobfuscation de4dot, string decryption Control flow restore Les métadonnées riches du IL permettent une décompilation quasi parfaite du code non obfusqué Contrairement au code natif, les noms de classes, méthodes et variables sont conservés dans l'assembly

3. Outils de décompilation .NET

3.1 dnSpy : le couteau suisse du reverse .NET

dnSpy (et son fork maintenu dnSpyEx) est l'outil le plus populaire pour le reverse engineering .NET. Il combine un décompilateur, un éditeur de code IL, un debugger managé et un éditeur hexadécimal, le tout dans une interface graphique unique. Son atout majeur : la capacité de débugger directement du code décompilé, placer des breakpoints sur du C# reconstitué et inspecter les variables en temps réel.

Les fonctionnalités clés de dnSpy pour l'analyse de malwares :

  • Décompilation multi-format : C#, VB.NET, IL avec basculement instantané.
  • Debugger intégré : attach à un processus en cours ou lancement en mode debug. Supporte les breakpoints conditionnels, l'inspection du heap managé et le step-through IL.
  • Édition de l'IL : modification directe des instructions IL pour patcher des vérifications anti-debug ou des routines de déchiffrement.
  • Recherche avancée : recherche dans les métadonnées, les chaînes, les références à une méthode/type spécifique.
  • Module de sauvegarde : export de l'assembly modifié avec préservation des métadonnées.
# Lancement de dnSpy en mode débogage d'un malware .NET
# Toujours dans une VM isolée !
dnSpy.exe --process-id <PID>

# Ou lancement direct avec breakpoint sur le Main
dnSpy.exe malware.exe --breakpoint Main

# Recherche de toutes les chaînes contenant "http"
# Menu: Edit → Search → String → "http"

3.2 ILSpy : le décompilateur open-source de référence

ILSpy est le décompilateur open-source le plus fiable pour le .NET, maintenu activement par la communauté .NET. Contrairement à dnSpy (dont le développement originel est arrêté), ILSpy bénéficie de mises à jour régulières avec le support des dernières fonctionnalités C# (records, pattern matching, async streams). Il est disponible en version standalone, en extension VS Code (ilspy-vscode) et en outil CLI (ilspycmd).

# Utilisation de ilspycmd en ligne de commande pour l'analyse batch
# Décompiler un assembly en projet C#
ilspycmd malware.dll -o ./output-project -p

# Décompiler un type spécifique
ilspycmd malware.exe -t "Malware.Core.C2Client"

# Lister toutes les méthodes d'un assembly
ilspycmd malware.exe --list methods

3.3 dotPeek, de4dot et outils complémentaires

JetBrains dotPeek est un décompilateur gratuit qui excelle dans la génération de projets Visual Studio reconstituables à partir d'assemblies. Sa force réside dans la qualité de la décompilation et la capacité à servir de symbol server, permettant de débugger du code tiers dans Visual Studio comme s'il disposait des sources originales.

de4dot est l'outil de déobfuscation .NET le plus connu. Bien que son développement soit ralenti, il reste efficace contre la majorité des obfuscateurs commerciaux et détecte automatiquement le type d'obfuscation utilisé :

# Détecter le type d'obfuscation
de4dot --detect malware.exe
# Output: Detected ConfuserEx v1.0.0

# Déobfusquer automatiquement
de4dot malware.exe -o malware-clean.exe

# Déobfuscation avec options spécifiques
de4dot malware.exe --strtyp delegate --strtok 0x06000123 -o clean.exe

# Pipeline complet d'analyse
de4dot malware.exe -o step1.exe && ilspycmd step1.exe -o ./decompiled -p
Outil Décompilation Debugging Déobfuscation Édition IL CLI Prix
dnSpy/dnSpyEx Excellente Oui (intégré) Non Oui Non Gratuit (GPL)
ILSpy Excellente Non Non Non Oui Gratuit (MIT)
dotPeek Très bonne Via VS Non Non Non Gratuit
de4dot Non Non Oui (auto) Non Oui Gratuit (GPL)
Telerik JustDecompile Bonne Non Non Non Non Gratuit
.NET Reflector Excellente Via VS Non Plugin Non Payant (~95$)

4. Décompilation et analyse : méthodologie pratique

4.1 Triage initial : identifier un binaire .NET

Avant toute décompilation, il faut confirmer que le binaire est bien un assembly .NET. Plusieurs indicateurs permettent cette identification rapide :

# Vérification avec file (Linux)
file suspect.exe
# Output: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

# Vérification avec CFF Explorer / PE-bear
# Chercher le CLR Runtime Header dans les Data Directories (index 14)
# COM+ Runtime Header RVA != 0 → .NET assembly

# Vérification avec Python (pefile)
import pefile
pe = pefile.PE("suspect.exe")
if hasattr(pe, 'DIRECTORY_ENTRY_COM_DESCRIPTOR'):
    print(f".NET detected - Runtime version: {pe.DIRECTORY_ENTRY_COM_DESCRIPTOR}")
    
# Vérification avec strings (recherche rapide)
strings suspect.exe | grep -i "mscoree\|mscorlib\|System.Runtime"

L'import de mscoree.dll (spécifiquement la fonction _CorExeMain) dans la table d'imports est le marqueur le plus fiable d'un exécutable .NET. Cette DLL est le bootstrap du CLR : quand Windows charge l'exécutable, il appelle _CorExeMain qui initialise le CLR et transfère l'exécution au point d'entrée managé défini dans les métadonnées.

4.2 Exploration des métadonnées et namespaces

Une fois l'assembly identifié et ouvert dans dnSpy ou ILSpy, l'exploration des métadonnées fournit une cartographie immédiate du programme. L'arbre de navigation révèle la structure hiérarchique : Assembly → Modules → Namespaces → Types → Membres. Voici les éléments à examiner en priorité :

  • Manifest de l'assembly : version .NET ciblée, culture, strong name (signature), liste des assemblies référencées.
  • Resources embarquées : les malwares .NET embarquent souvent des payloads chiffrés, des configurations ou des DLL compressées dans les ressources managées.
  • Attributs personnalisés : les obfuscateurs laissent souvent des traces ([assembly: Confuser.Runtime], [assembly: SmartAssembly.Attributes]).
  • Entry Point : la méthode marquée comme entry point dans les métadonnées. Correspond généralement à Main(string[] args) ou, pour les malwares, à un nom obfusqué.
// Exemple de structure typique d'un malware .NET
// Namespace principal souvent obfusqué
namespace a8f3e2
{
    // Classe principale avec entry point
    internal static class b7c1d9
    {
        // Entry point - Main obfusqué
        private static void c4a2e1(string[] args)
        {
            // Déchiffrement de la configuration
            string config = d5b3f2.e6c4a3("base64encodedstring==");
            
            // Initialisation du C2
            f7d5b4 client = new f7d5b4(config);
            client.g8e6c5(); // Boucle principale
        }
    }
    
    // Classe de déchiffrement des chaînes
    internal static class d5b3f2
    {
        internal static string e6c4a3(string input)
        {
            byte[] data = Convert.FromBase64String(input);
            // XOR ou AES déchiffrement
            return Encoding.UTF8.GetString(Decrypt(data));
        }
    }
}

4.3 Identification des entry points et du flux d'exécution

L'identification du flux d'exécution commence par le point d'entrée managé, mais les malwares .NET modernes utilisent plusieurs techniques pour complexifier ce flux :

  • Module Initializers (.cctor) : le constructeur statique du module (<Module>.cctor) s'exécute avant Main. Les malwares l'utilisent pour l'anti-debug ou le déchiffrement précoce.
  • Assembly Resolve Events : handlers AppDomain.AssemblyResolve qui chargent dynamiquement des assemblies depuis les ressources ou le réseau.
  • Reflection Loading : Assembly.Load(byte[]) pour charger des assemblies en mémoire sans les écrire sur disque.
  • Dynamic Method Invocation : MethodInfo.Invoke() pour appeler des méthodes par réflexion, cachant le vrai flux d'exécution.

Astuce d'analyste : tracer les Assembly.Load

Placez un breakpoint sur System.Reflection.Assembly.Load(byte[]) dans dnSpy. Quand le breakpoint est atteint, examinez le tableau d'octets sur la pile -- c'est souvent le payload réel du malware. Sauvegardez ces octets et ouvrez-les comme un nouvel assembly dans dnSpy pour continuer l'analyse. Cette technique est documentée dans notre guide sur la déobfuscation de malwares polymorphes.

5. Debugging avancé avec dnSpy

5.1 Configuration du debugger pour l'analyse malware

Le debugger intégré de dnSpy est un outil puissant qui permet de débugger du code .NET directement depuis la vue décompilée. Contrairement à WinDbg + SOS qui nécessite une connaissance approfondie du runtime, dnSpy offre une expérience similaire à Visual Studio pour l'analyse de binaires inconnus.

Configuration recommandée pour l'analyse de malwares :

# Configuration dnSpy pour l'analyse malware
# 1. Désactiver le JIT optimization pour voir le code IL original
# Debug → Options → Debugger → "Suppress JIT optimization on module load" ✓

# 2. Activer le break on module load pour intercepter les Assembly.Load
# Debug → Options → Debugger → "Break on module load" ✓

# 3. Configurer l'anti-anti-debug
# Debug → Options → Debugger → "Prevent managed debugger detection" ✓

# 4. Points de breakpoint stratégiques
# System.Net.WebClient::DownloadString
# System.Net.Http.HttpClient::SendAsync
# System.IO.File::WriteAllBytes
# System.Diagnostics.Process::Start
# System.Reflection.Assembly::Load
# Microsoft.Win32.Registry::SetValue

5.2 Breakpoints IL et inspection du runtime

Les breakpoints dans dnSpy fonctionnent aussi bien sur le code C# décompilé que sur les instructions IL brutes. Pour les malwares obfusqués où la décompilation échoue partiellement, basculer en vue IL et placer des breakpoints sur des instructions spécifiques est souvent la seule approche viable.

Techniques de debugging avancées :

  • Breakpoints conditionnels : déclencher le break uniquement quand une condition est remplie (ex: quand la chaîne passée à WebClient.DownloadString contient "http").
  • Tracepoints : logger des valeurs sans arrêter l'exécution. Idéal pour capturer les chaînes déchiffrées à la volée.
  • Memory dumps ciblés : dans la fenêtre Locals, faire un clic droit sur un objet → Save pour extraire les données en mémoire (payload déchiffré, clés crypto).
  • Edit and Continue : modifier le code IL en cours d'exécution pour contourner les anti-debug. Changer un brfalse en brtrue pour inverser un test anti-VM.
// Exemple : patcher un anti-debug check en IL
// Code original (anti-debug)
IL_0000: call bool [mscorlib]System.Diagnostics.Debugger::get_IsAttached()
IL_0005: brfalse.s IL_000C    // Si pas de debugger, continue
IL_0007: call void MalwareClass::SelfDestruct()
IL_000C: nop                   // Code principal

// Patch : remplacer brfalse.s par brtrue.s (opcode 0x2D → 0x2C)
// Ou remplacer l'appel SelfDestruct par des nop (0x00)
IL_0000: call bool [mscorlib]System.Diagnostics.Debugger::get_IsAttached()
IL_0005: brtrue.s IL_000C     // PATCHÉ : saute toujours au code principal
IL_0007: call void MalwareClass::SelfDestruct()
IL_000C: nop

5.3 Contournement des techniques anti-debug .NET

Les malwares .NET utilisent plusieurs techniques anti-debugging que l'analyste doit savoir contourner. Ces techniques sont détaillées dans notre article sur les techniques anti-rétro-ingénierie des APT, mais voici les plus courantes spécifiques au .NET :

Technique Anti-Debug Méthode de détection Contournement
Debugger.IsAttached Vérifie si un debugger managé est attaché Option dnSpy "Prevent detection" ou patch IL
Debugger.IsLogging() Vérifie le logging debugger Patch de la méthode appelante
Timing checks Stopwatch, DateTime.Now deltas Patch des comparaisons de temps
CheckRemoteDebuggerPresent P/Invoke vers kernel32 Hook de la fonction ou patch du call
Anti-VM (WMI queries) Détection VMware/VBox/Hyper-V Modifier les réponses WMI ou patch
Module enumeration Recherche de dnSpy.exe dans les processus Renommer dnSpy en un nom anodin

6. Obfuscation .NET : techniques et outils

6.1 Panorama des obfuscateurs .NET

L'obfuscation .NET est une industrie mature avec des solutions allant des outils gratuits aux suites commerciales complètes. Pour le reverse engineer, comprendre les techniques employées par chaque obfuscateur est essentiel pour choisir la bonne stratégie de déobfuscation.

Obfuscateur Type Techniques principales Difficulté RE
ConfuserEx Open-source Renaming, control flow, string encryption, anti-tamper, constants protection Moyenne
SmartAssembly Commercial (Red Gate) Renaming, string encoding, flow obfuscation, pruning, dependency merging Moyenne-Haute
.NET Reactor Commercial Native code generation, anti-ILDASM, NecroBit (IL encryption), code virtualization Haute
Dotfuscator Commercial (PreEmptive) Renaming, control flow, string encryption, tamper detection, watermarking Moyenne
Crypto Obfuscator Commercial String encryption, resource encryption, method call hiding, anti-debug Moyenne
Agile.NET (CliSecure) Commercial Code virtualization, IL encryption, cross-assembly obfuscation Très Haute

6.2 ConfuserEx en détail

ConfuserEx est l'obfuscateur le plus fréquemment rencontré dans les malwares .NET car il est open-source et puissant. Ses protections s'organisent en couches activables individuellement :

  • Renaming : remplacement des noms de types, méthodes et champs par des caractères non-imprimables ou des identifiants aléatoires. Utilise souvent des caractères Unicode invisibles ou RTL override.
  • Control Flow Obfuscation : transformation du graphe de contrôle en switch-dispatcher. Le code linéaire est découpé en blocs réarrangés aléatoirement et exécutés via un dispatcher switch(state).
  • String Encryption : les chaînes littérales sont remplacées par des appels à des méthodes de déchiffrement. Chaque chaîne est chiffrée avec une clé unique dérivée de son metadata token.
  • Constants Protection : les constantes numériques sont encodées via des opérations arithmétiques ou des appels à des méthodes de décodage.
  • Anti-Tamper : vérification de l'intégrité de l'assembly au runtime via un hash des métadonnées. Toute modification du binaire provoque un crash ou un comportement indéfini.
  • Anti-Debug : détection de debugger via Debugger.IsAttached, timing checks et hooks natifs.
  • Resource Protection : chiffrement et compression des ressources embarquées.
// Exemple de control flow obfuscation par ConfuserEx
// Code original :
public void ProcessData(byte[] data)
{
    var result = Decrypt(data);
    SendToC2(result);
    CleanUp();
}

// Après obfuscation ConfuserEx (control flow) :
public void ProcessData(byte[] data)
{
    int state = 1857302946;
    while (true)
    {
        switch (state ^ 0x7A3B2C1D)
        {
            case 0:
                return;
            case 1:
                CleanUp();
                state = (state * 0x1234 + 0x5678) ^ 0xABCD;
                continue;
            case 2:
                var result = Decrypt(data);
                state = (state >> 3) ^ 0x9E3779B9;
                continue;
            case 3:
                SendToC2(result);
                state = ~state & 0x7FFFFFFF;
                continue;
        }
        break;
    }
}
Couches d'Obfuscation .NET & Stratégies de Déobfuscation Couches de Protection Anti-Tamper / Anti-Debug Resource Encryption Control Flow Obfuscation String Encryption Renaming Code Original IL + Metadata Stratégies de Déobfuscation 1. Neutraliser Anti-Tamper Patcher le .cctor, désactiver les checks d'intégrité 2. Déchiffrer les Ressources Extraire et décrypter les assemblies embarquées 3. Restaurer le Control Flow de4dot ou scripts custom pour linéariser le switch-dispatcher 4. Déchiffrer les Chaînes Identifier la méthode de déchiffrement, exécuter ou émuler 5. Restaurer le Renaming Renommer manuellement basé sur le contexte et les patterns

7. Techniques de déobfuscation avancées

7.1 String Decryption : la clé de l'analyse

Le déchiffrement des chaînes est presque toujours la première étape de la déobfuscation car il révèle les URLs C2, les clés de registre, les chemins de fichiers et les configurations du malware. Les obfuscateurs utilisent plusieurs schémas de chiffrement des chaînes :

  • XOR simple : chaque chaîne est XOR-ée avec une clé statique ou dérivée du metadata token. Facilement réversible.
  • AES/DES : chiffrement symétrique avec une clé embarquée dans le binaire. La clé est souvent dérivée d'un hash du nom de la méthode.
  • Delegates et proxy methods : la méthode de déchiffrement est appelée indirectement via un delegate, compliquant l'identification statique.
  • Stack-based decryption : les octets de la chaîne sont poussés individuellement sur la pile IL et assemblés dynamiquement.
# Approche 1 : Déchiffrement dynamique avec dnSpy
# 1. Identifier la méthode de déchiffrement (souvent un seul paramètre string/int, retourne string)
# 2. Placer un breakpoint sur cette méthode
# 3. Lancer le debugger et capturer les retours

# Approche 2 : Script Python pour le déchiffrement XOR
import base64

def decrypt_strings(encrypted_b64, key):
    """Décrypter les chaînes obfusquées par XOR"""
    data = base64.b64decode(encrypted_b64)
    decrypted = bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
    return decrypted.decode('utf-8', errors='replace')

# Approche 3 : Utiliser de4dot avec les tokens spécifiques
# de4dot identifie automatiquement la plupart des schémas
de4dot malware.exe --strtyp delegate --strtok 0x06000042 -o clean.exe

# Approche 4 : Script dnlib (C#) pour le déchiffrement en masse
// using dnlib.DotNet;
// var module = ModuleDefMD.Load("malware.exe");
// foreach (var type in module.Types)
//     foreach (var method in type.Methods)
//         if (method.HasBody)
//             foreach (var instr in method.Body.Instructions)
//                 if (instr.OpCode == OpCodes.Ldstr)
//                     Console.WriteLine($"String: {instr.Operand}");

7.2 Control Flow Deobfuscation

La restauration du control flow est la tâche la plus complexe de la déobfuscation .NET. Le switch-dispatcher utilisé par ConfuserEx et d'autres obfuscateurs transforme un code linéaire en une machine à états où l'ordre d'exécution des blocs dépend de calculs arithmétiques sur une variable d'état.

Stratégies de restauration :

  • de4dot automatique : fonctionne bien contre ConfuserEx standard, mais échoue souvent contre les versions customisées.
  • Émulation symbolique : utiliser un émulateur IL (comme celui de de4dot) pour calculer les transitions d'état et reconstruire l'ordre linéaire.
  • Pattern matching : identifier les patterns du dispatcher (switch sur un état XOR-é) et les remplacer par le flux linéaire reconstitué.
  • Tracing dynamique : exécuter le code dans dnSpy avec tracing activé pour enregistrer l'ordre réel d'exécution des blocs.

7.3 Proxy Calls et Delegate Resolution

Les proxy calls (ou call hiding) remplacent les appels de méthodes directs par des appels indirects via des delegates. Au lieu d'un call System.Net.WebClient::DownloadString visible dans le IL, l'obfuscateur génère un delegate initialisé dynamiquement qui pointe vers la méthode cible. Cela cache les imports et empêche l'analyse statique de déterminer quelles APIs sont utilisées.

// Avant obfuscation (call direct visible)
IL_0010: callvirt instance string [System]System.Net.WebClient::DownloadString(string)

// Après proxy call obfuscation
// Un delegate est initialisé dans le .cctor avec la méthode cible
// L'appel devient indirect :
IL_0010: ldsfld class [mscorlib]System.Func`2<string,string> ProxyClass::delegate_42
IL_0015: ldarg.1
IL_0016: callvirt instance !1 class [mscorlib]System.Func`2<string,string>::Invoke(!0)

// Résolution : identifier le .cctor, extraire les initialisations de delegates
// de4dot résout la plupart des proxy calls automatiquement

Malwares avec obfuscation custom

Les malwares les plus sophistiqués (APT, ransomware enterprise) utilisent des forks custom de ConfuserEx ou des obfuscateurs internes non reconnus par de4dot. Dans ces cas, l'analyse manuelle avec dnSpy reste la seule option. Pour les techniques avancées d'anti-analyse, voir notre article sur les techniques anti-rétro-ingénierie des APT.

8. Analyse de malwares .NET : études de cas

8.1 AgentTesla : l'infostealer le plus prolifique

AgentTesla est le malware .NET le plus répandu selon les rapports ANY.RUN 2025, représentant plus de 15 % des échantillons .NET analysés quotidiennement. Vendu comme "logiciel de surveillance légitime" sur des forums souterrains, c'est en réalité un keylogger et infostealer complet qui cible les credentials des navigateurs, clients mail, clients FTP et wallets crypto. Ce type de menace est couvert en profondeur dans notre article sur les infostealers et la menace silencieuse du cybercrime.

Caractéristiques techniques pour le reverse engineering :

  • Obfuscation : utilise typiquement ConfuserEx, .NET Reactor ou des packers custom. Le renaming est systématique, le control flow rarement.
  • Delivery : souvent emballé dans un loader .NET qui déchiffre le payload depuis les ressources (AES-256 ou XOR multi-layer).
  • Exfiltration : SMTP (la méthode favorite), FTP, HTTP POST vers un panel PHP, ou Telegram Bot API.
  • Keylogging : hook clavier via SetWindowsHookEx (P/Invoke vers user32.dll) avec capture de screenshots périodiques.
  • Credential harvesting : lecture des bases SQLite des navigateurs Chromium, décryptage via DPAPI, parsing des fichiers de config des clients mail.
// Workflow d'analyse AgentTesla typique
// 1. Déobfuscation
de4dot agent_tesla_sample.exe -o stage1.exe

// 2. Ouvrir dans dnSpy, identifier le loader
// Chercher: Assembly.Load, Convert.FromBase64String, MemoryStream
// Le Main() contient généralement un appel à une méthode de déchiffrement

// 3. Extraire la configuration
// Chercher les champs statiques contenant:
// - Adresses email (SMTP exfil)
// - Mots de passe SMTP en clair ou base64
// - URLs de panels C2
// - Clés Telegram Bot

// 4. Indicateurs typiques dans le code décompilé
// Classes héritant de ApplicationSettingsBase
// Méthodes avec noms: GetChrome, GetFirefox, GetOutlook
// P/Invoke: GetAsyncKeyState, GetForegroundWindow
// Timers avec intervals de 20000-60000ms (capture screenshots)

8.2 AsyncRAT : le RAT open-source modulaire

AsyncRAT est un Remote Access Trojan open-source écrit en C# qui offre un contrôle complet sur la machine victime. Son architecture client-serveur utilise des connexions TCP chiffrées en TLS avec des certificats auto-signés. Sa modularité le rend particulièrement dangereux : les attaquants peuvent ajouter des plugins pour le keylogging, le screen recording, le ransomware ou le mining de cryptomonnaies.

Points d'analyse clés :

  • Configuration : stockée dans une classe Settings avec le host C2, le port, le mutex, le certificat TLS et la clé AES pour le chiffrement.
  • Persistance : clés de registre Run, tâches planifiées, ou copie dans le dossier Startup. Ces techniques rejoignent celles documentées dans notre article sur la persistence multi-plateforme.
  • Anti-Analysis : vérification de sandbox (nombre de CPU, RAM, présence de drivers VM), delayed execution (Thread.Sleep de 10-30 secondes).
  • Communication : protocole binaire custom sur TCP avec sérialisation MessagePack et chiffrement AES-256-CBC.

8.3 NjRAT (Bladabindi) : persistance et propagation

NjRAT est l'un des RAT .NET les plus anciens et les plus persistants dans le paysage des menaces, actif depuis 2013. Malgré son ancienneté, il reste largement utilisé, notamment au Moyen-Orient et en Afrique du Nord. Son code source est publiquement disponible, ce qui a engendré des centaines de variantes.

Signatures d'analyse pour NjRAT :

// Indicateurs typiques de NjRAT dans le code décompilé

// 1. Mutex format caractéristique
string mutex = "d3d9c3b2a1";  // Souvent un hash court

// 2. Registry keys de persistance
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true)
    .SetValue("WindowsService", Application.ExecutablePath);

// 3. Communication C2 avec séparateur pipe "|'|"
string packet = "inf" + "|'|" + computerName + "|'|" + userName + "|'|" + osVersion;

// 4. Keylogger basique avec GetAsyncKeyState
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(int vKey);

// 5. Spread via USB (copie + autorun.inf)
foreach (DriveInfo drive in DriveInfo.GetDrives())
    if (drive.DriveType == DriveType.Removable)
        File.Copy(Application.ExecutablePath, drive.Name + "\\system.exe");

Extraction automatique des IOCs

Pour les malwares .NET courants (AgentTesla, AsyncRAT, NjRAT, RedLine, Quasar), des outils d'extraction automatique de configuration existent : CAPE Sandbox (extraction auto via modules Python), MalwareConfig (parsers dédiés par famille) et les frameworks d'analyse assistés par IA. Ces outils extraient directement les IOCs (C2, credentials, clés crypto) sans nécessiter de reverse engineering manuel.

9. Protection du code .NET

9.1 Compilation AOT et NativeAOT

La compilation Ahead-of-Time (AOT) représente le changement de paradigme le plus significatif pour la protection du code .NET. Avec .NET NativeAOT (disponible depuis .NET 7, mature dans .NET 8+), le code C# est compilé directement en code natif sans inclure le runtime CLR ni le code IL dans le binaire final. Cela élimine fondamentalement le vecteur de décompilation IL.

# Compilation NativeAOT avec .NET 8
dotnet publish -c Release -r win-x64 --self-contained \
  /p:PublishAot=true \
  /p:StripSymbols=true \
  /p:OptimizationPreference=Size

# Le binaire résultant est du code natif x64 pur
# Plus de métadonnées .NET, plus de IL, plus de décompilation C#
# L'analyse requiert IDA Pro / Ghidra comme pour tout binaire natif

# Limitations NativeAOT :
# - Pas de reflection dynamique (Assembly.Load impossible)
# - Pas de dynamic code generation (Expression trees limités)  
# - Taille du binaire plus importante (runtime embarqué en natif)
# - Temps de compilation significativement plus long

9.2 Stratégies de protection multi-couches

Pour les applications qui ne peuvent pas utiliser NativeAOT (dépendances sur la reflection, plugins dynamiques, etc.), une approche de défense en profondeur combinant plusieurs techniques est recommandée :

  • Obfuscation commerciale : utiliser un obfuscateur de qualité (.NET Reactor avec NecroBit, Agile.NET avec virtualisation) comme première couche.
  • Code splitting : séparer la logique sensible dans des bibliothèques natives (C/C++ via P/Invoke ou C++/CLI) pour les algorithmes critiques.
  • Vérification d'intégrité : implémenter des checks de hash sur les assemblies au runtime, indépendamment de ceux de l'obfuscateur.
  • Licensing côté serveur : ne jamais embarquer les clés de licence ou la logique de validation dans le binaire. Utiliser une validation côté serveur.
  • Heartbeat et revocation : call-home périodique pour vérifier la validité de la licence et la possibilité de révoquer des instances compromises.
Workflow Complet d'Analyse Malware .NET 1. Triage Identification .NET Version framework Obfuscation detect Sandbox report 2. Déobfuscation de4dot automatique String decryption Control flow fix Proxy call resolve 3. Analyse Statique Décompilation C# Entry point analysis API mapping Config extraction 4. Debugging dnSpy breakpoints Runtime decryption Network capture Memory dump 5. Reporting IOC extraction YARA rules MITRE mapping CTI sharing Livrables de l'Analyse IOCs C2, hashes, mutex, registry keys, filenames YARA Rules Signatures basées sur les strings et patterns IL MITRE ATT&CK Mapping des TTPs observées dans le sample Rapport Technique Kill chain, capabilities, mitigations recommandées

10. Checklist d'analyse .NET

Cette checklist synthétise le workflow complet d'analyse d'un binaire .NET suspect. Elle est utilisable comme aide-mémoire lors d'investigations et complète notre guide général de reverse engineering et analyse malware.

Checklist complète d'analyse .NET

  • Phase 1 - Triage
    • Confirmer le format .NET (CLR Header, mscoree.dll import)
    • Identifier la version du framework (.NET Framework 4.x, .NET 6/7/8, Mono)
    • Scanner avec VirusTotal, ANY.RUN pour un rapport initial
    • Calculer les hashes (MD5, SHA1, SHA256) et les soumettre à la CTI
    • Exécuter en sandbox (CAPE, Joe Sandbox) pour les comportements réseau
  • Phase 2 - Déobfuscation
    • Détecter l'obfuscateur avec de4dot ou par inspection des attributs
    • Appliquer de4dot avec les options adaptées à l'obfuscateur détecté
    • Vérifier le résultat en ouvrant dans ILSpy -- le code doit être lisible
    • Si de4dot échoue, tenter une déobfuscation manuelle des chaînes
  • Phase 3 - Analyse statique
    • Ouvrir dans dnSpy, localiser le point d'entrée (Main ou .cctor)
    • Mapper les imports : réseau (WebClient, HttpClient), crypto (AES, RSA), fichiers, registre
    • Identifier les ressources embarquées (payloads chiffrés, configs)
    • Documenter les chaînes significatives (URLs, chemins, clés)
    • Tracer le flux d'exécution du Main vers les fonctions clés
  • Phase 4 - Analyse dynamique
    • Configurer dnSpy debugger avec anti-anti-debug activé
    • Placer des breakpoints sur Assembly.Load, WebClient, Process.Start
    • Capturer les chaînes déchiffrées au runtime via tracepoints
    • Extraire les payloads en mémoire (dump des byte[] après déchiffrement)
    • Capturer le trafic réseau avec Wireshark/Fiddler pendant l'exécution
  • Phase 5 - IOC extraction et reporting
    • Extraire tous les IOCs : C2 URLs, IPs, domains, hashes de payloads secondaires
    • Créer des règles YARA basées sur les chaînes uniques et les patterns de code
    • Mapper les TTPs observées sur le framework MITRE ATT&CK
    • Rédiger le rapport technique avec kill chain et recommandations de détection

Besoin d'expertise en reverse engineering .NET ?

Nos experts analysent vos binaires suspects, déobfusquent les malwares .NET et produisent des rapports actionables avec IOCs et règles de détection.

Demander une analyse

Références et ressources externes

Ayi NEDJIMI

Ayi NEDJIMI

Expert en Cybersécurité & Intelligence Artificielle

Consultant senior, certifié OSCP, CISSP et ISO 27001 Lead Auditor. Plus de 15 ans d'expérience en pentest, audit et solutions IA.

Besoin d'une expertise en cybersécurité ?

Analyse de malwares .NET, reverse engineering et protection de votre code managé

Nos Services