Un désobfuscateur ConfuserEx2 prenant en charge l'anti-tamper, le compresseur, les constantes, le flux de contrôle et la récupération de ressources.
Fork amélioré d'UnconfuserEx avec une prise en charge améliorée des variantes modernes de ConfuserEx2, récupération anti‑altération, suppression du compresseur, restauration du flux de contrôle et reconstruction des ressources.
https://github.com/user-attachments/assets/de2c7fd9-6736-4f39-83c0-3c25aa9c1f24
Si tu as déjà joué avec des échantillons de malwares, certains sont obfusqués avec ConfuserEx, et j'ai testé quelques déobfusqueurs publics contre la dernière version mais ça ne fonctionnait pas, alors j'ai décidé de forker un déobfusqueur public qui fonctionnait contre cette dernière version et de le modifier selon mes besoins.
Ce dépôt est un fork de MadMin3r/UnconfuserEx. Le crédit lui revient également. Le projet original a fait le travail difficile en créant un déobfusqueur ConfuserEx2 ciblé capable de réellement supprimer les protections.
C'est ce que fait ce projet. Il exécute une liste de suppresseurs dans un ordre fixe, réécrit les corps de méthodes/ressources/métadonnées là où c'est possible, et écrit un nouvel assembly en sortie. La partie importante est l'ordre. Le compresseur et l'anti‑altération doivent intervenir tôt car le reste du module pourrait ne pas être encore du vrai IL.
La version amont était déjà utile, mais quelques cas continuaient de se présenter.
L'un d'eux est le chemin LZMA. Certains échantillons fournissent des octets qui ressemblent à la charge utile des constantes/ressources, mais les propriétés LZMA sont absurdes. Si tu passes cela directement dans le décodeur, tu obtiens des tailles de dictionnaire stupides et finalement des exceptions comme des dimensions de tableau dépassant la plage prise en charge. Cette version vérifie donc les propriétés, plafonne la taille du dictionnaire, plafonne la taille décompressée, et abandonne avant que le décodeur n'alloue quelque chose de ridicule.
LZMA properties => CE FD 62 5F 9F
Invalid LZMA properties byte 0xCE or unreasonable dictionary size
Les constantes avaient un autre problème bête mais réel. Une grande partie du code de résolution veut que l'ID situé avant l'appel au getter soit un ldc.i4. Parfois ce n'est plus une seule instruction. C'est une petite expression arithmétique.
ldc.i4 0x1234
ldc.i4 0x55
xor
call string <const getter>(int32)
Le fork original voit xor, appelle GetLdcI4Value(), et meurt parce que xor n'est évidemment pas un chargement d'entier. Cette version remonte la petite séquence arithmétique, émule la pile, la réduit à un seul ldc.i4, puis laisse le résolveur normal continuer.
Ainsi, au lieu de traiter cela comme une protection de constantes totalement différente, cela devient :
ldc.i4 0x1261
call string <const getter>(int32)
Ensuite, le chemin normal du résolveur de constantes (normal/x86) peut faire son travail.
Le flux de contrôle, c'était moyen
Le suppresseur de switch peut gérer la forme normale du répartiteur de switch de ConfuserEx. Il parcourt les blocs, récupère la cible suivante, supprime les blocs morts et émet un corps de méthode sain. Mais il existe des échantillons où seule une partie de la méthode est comprise. Si tu modifies la moitié d'une méthode et découvres ensuite qu'elle est toujours obfusquée, la sortie est pire qu'inutile car tu as maintenant un IL cassé et aucun moyen propre de comprendre ce qui s'est passé.
Cette version fait donc un instantané du corps de la méthode avant de le toucher :
instructions
gestionnaires d'exceptions
Si la déobfuscation échoue, ou si la méthode semble encore obfusquée après, le corps original est restauré. Le log peut toujours dire « cette méthode n'a pas été résolue », mais l'assembly n'est pas silencieusement corrompu simplement parce qu'une méthode avait un répartiteur étrange.
Le flux de contrôle par sauts/trampolines a également reçu sa propre passe. Certaines méthodes ne sont pas des répartiteurs de switch. Ce sont de petits trampolines de branche enchaînés jusqu'à atteindre le bloc réel. Ceux‑ci sont maintenant détectés et repliés au lieu d'être ignorés par le seul chemin de switch.
Le suppresseur de compresseur est la partie qui doit s'exécuter avant tout le monde.
Les stubs de compresseur ConfuserEx conservent généralement l'assembly réel compressé, lancent un petit chargeur, décompressent la charge utile et la chargent à l'exécution.
Le suppresseur trouve la forme du chargeur, extrait la charge utile compressée intégrée, la décompresse et remplace le module par l'assembly réel. Les deux formats de compresseur (normal et compact) sont pris en charge.
[+] Compressor detected
[+] Extracted compressed module payload
[+] Decompressed real module
[+] Continuing pipeline on unpacked assembly
L'anti‑altération dispose maintenant de deux chemins.
L'anti‑altération normal/dynamique déchiffre les corps de méthodes à partir des sections protégées et réécrit les corps restaurés dans le module. L'anti‑altération JIT est plus ennuyeuse car les corps sont censés être matérialisés lorsque le runtime les demande.
La forme générale est :
find init
extract keys
find encrypted JIT body section
derive per method key
read body
write CilBody back
C'est toujours basé sur des motifs. Si le stub a suffisamment changé, cela manquera évidemment.
Les ressources sont traitées de manière similaire aux constantes : trouver le blob de ressources chiffré, récupérer la clé/la forme du déchiffreur, déchiffrer, décompresser si nécessaire, puis remettre les ressources là où les outils .NET normaux les attendent.
Il existe également un chemin optionnel de reconstruction d'un PE intégré. Certains échantillons protégés transportent un PE managé à l'intérieur d'une ressource. Avec la reconstruction activée, le suppresseur tente d'analyser et de réécrire cette charge utile aussi, au lieu de laisser un assembly externe déobfusqué avec un assembly interne intact.
UnConfuserEx.exe sample.exe sample.clean.exe --rebuild-embedded-pe
Utilise cela quand tu sais que l'échantillon cache un autre assembly managé dans les ressources. Si la charge utile n'est pas un PE managé, le chemin de reconstruction devrait la laisser tranquille.
Construis‑le :
dotnet build .\UnConfuserEx.sln -c Release
Exécute‑le :
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe
Ou donne un chemin de sortie explicite :
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe
Si tu ne donnes pas de chemin de sortie, il en écrit un à côté de l'entrée avec -deobfuscated ajouté au nom.
Pour les charges utiles managées intégrées :
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe --rebuild-embedded-pe
Voici la liste de prise en charge actuelle. Cela ne signifie pas que tous les forks possibles de ConfuserEx fonctionnent. Cela signifie que ce sont les formes que le pipeline sait rechercher.
Il y a probablement plus de choses cachées dans le code que j'ai oublié de lister xD.
Les logs utiles sont ceux qui te disent quelle étape a échoué, pas seulement que la sortie n'a pas fonctionné.
Exemple d'un chemin de constantes qui a été corrigé :
Constants detected, attempting to remove
Found 3 constant getter(s)
Detected constant decryption type is Dynamic
Decompressed constants blob to 18492 byte(s)
Resolving getter <Module>::???????? as String with 41 call site method(s)
Removed all instances of getter <Module>::????????
Exemple d'une méthode de flux de contrôle intentionnellement laissée tranquille :
Removing obfuscation from method System.Void Example::Run()
Method System.Void Example::Run() still appears obfuscated after deobfuscation -- left original body intact
Removed obfuscation from 42 methods. Failed to remove from 0 methods. 1 methods left untouched
Ce second log n'est pas parfait, mais il est AU MOINS honnête.
Un fork personnalisé de ConfuserEx qui change chaque forme d'assistant.
Un getter de constantes qui calcule son ID via un bordel complet de flux de contrôle au lieu d'une petite expression de pile.
Un graphe de flux de contrôle où le répartiteur dépend de valeurs runtime que l'émulateur statique ne connaît pas.
Des assistants natifs qui nécessitent une exécution runtime réelle au lieu d'une émulation IL.
Des assemblies déjà cassés avant d'être obfusqués.
Des variantes d'anti‑tamper JIT avec une disposition différente du corps chiffré.
Si tu veux qu'un problème soit utile, inclue suffisamment de données pour le reproduire.
Supprime les extensions de fichier des échantillons avant de les télécharger.
Archive tout ensemble et inclue ceci :
Commande :
UnConfuserEx.exe <cible> <sortie optionnelle>
Étape d'échec :
- compressor
- anti tamper
- constants
- control flow
- resources
- writing output
- runtime after deobfuscation
Résultat attendu :
Résultat réel :
Sortie console :
Lien de l'archive :
Notes / investigation :
Si tu envoies seulement « ça ne marche pas », la réponse sera probablement « ouais ».




Les petites corrections ciblées sont meilleures que les réécritures massives.
Si tu ajoutes la prise en charge d'une nouvelle forme de protection, garde‑la isolée dans le suppresseur qui la possède. Si tu ajoutes un comportement de repli, assure‑toi que l'échec ne corrompt pas l'assembly de sortie. Si tu touches au flux de contrôle, suppose que l'échantillon étrange que tu as corrigé n'est pas le seul échantillon étrange qui existe :DDD.
Ne rends surtout pas l'outil plus difficile à déboguer.
Ce projet est basé sur MadMin3r/UnconfuserEx.
Le projet original a fourni les fondations et la majeure partie du pipeline de déobfuscation. Ce fork se concentre sur l'amélioration de la fiabilité, l'ajout de la prise en charge de variantes de protection supplémentaires, et la gestion des cas limites observés sur des échantillons du monde réel.
Ce projet a commencé comme un outil pratique de rétro‑ingénierie plutôt que comme un exercice de génie logiciel. L'accent a toujours été mis sur la récupération fiable des assemblies protégés plutôt que sur une qualité de code parfaite.
Cet outil est destiné à l'analyse autorisée de malwares, à la rétro‑ingénierie, à la récupération de logiciels, à l'interopérabilité et à la recherche éducative.
Les utilisateurs sont responsables du respect des lois applicables et de l'obtention de toute autorisation requise avant d'analyser, d'accéder ou de traiter des logiciels ou des systèmes.
Zypherion Technologies n'autorise pas l'utilisation illicite de cet outil et décline toute responsabilité en cas d'usage abusif par des tiers.
Rien dans ce dépôt ni sur www.zypherion.tech ne constitue un conseil juridique.