Chaînes de pile et chaînes décodées dans les malwares
Pourquoi les malwares cachent leurs chaînes, comment fonctionnent stack strings, tight strings et chaînes décodées, et comment l’émulation les récupère sans exécution.
En bref. L’extraction de chaînes classique ne trouve que le texte présent tel quel dans le fichier. Les malwares cachent souvent leurs chaînes intéressantes — adresses C2, noms de mutex, commandes — en les construisant sur la pile ou en les décodant à l’exécution. Émuler le code qui les construit en récupère l’essentiel sans exécuter l’échantillon. Le PE Parser le fait dans son onglet Analyse du code, dans l’esprit de FLOSS de Mandiant.
Ce que strings voit, et ce qu’il ne voit pas
Une extraction de chaînes parcourt le fichier à la recherche de suites de caractères imprimables (ASCII, UTF-16). C’est rapide et cela trouve beaucoup : noms d’imports, messages d’erreur, chemins, URL laissées en clair. C’est précisément pour cela que les auteurs cachent les chaînes qui comptent. Trois techniques couvrent l’essentiel :
- Stack strings (chaînes de pile). Le code écrit les caractères un par un dans un tampon local :
mov byte [ebp-0x20], 'h',mov byte [ebp-0x1f], 't'… Le texte n’existe qu’en mémoire, le temps de la fonction. Dans le fichier, on voit une suite d’instructions, pas une chaîne. - Tight strings. Une stack string elle-même encodée, puis décodée par une courte boucle dans la même fonction — typiquement un XOR avec une clé constante — juste avant usage.
- Chaînes décodées. Les chaînes sont stockées chiffrées dans la section de données, et une fonction de décodage les remet en clair à la demande. Elle est appelée depuis de nombreux endroits, chaque fois avec un bloc chiffré différent, et renvoie ou écrit le texte en clair.
Les trois mettent en échec l’extraction statique, et les trois sont visibles pour qui suit ce que fait le code.
Comment l’émulation les récupère
Un émulateur est un processeur logiciel : il lit chaque instruction, met à jour des registres et une mémoire simulés, et passe à la suivante. Rien n’atteint le vrai processeur ni le système d’exploitation — les appels aux fonctions Windows reçoivent des réponses de bouchons qui renvoient des valeurs plausibles (un tampon neuf pour une allocation, un code de succès pour le reste). L’analyse du PE Parser procède en trois passes :
- Trouver les fonctions. À partir du point d’entrée, des exports, des callbacks TLS et de chaque appel direct, elle suit le code pour découvrir les fonctions et leurs appels.
- Stack et tight strings. Chaque fonction est émulée depuis son début pendant un nombre limité d’instructions ; le texte imprimable qui apparaît dans son cadre de pile est collecté, avant et après une éventuelle boucle de décodage.
- Chaînes décodées. Les fonctions qui ressemblent à des décodeurs — un XOR dans une boucle, petites, appelées depuis plusieurs endroits — sont émulées depuis chaque site d’appel, avec les arguments préparés par l’appelant. Le texte écrit en mémoire par le décodeur est collecté, avec l’adresse du décodeur.
Seul le texte qu’une extraction classique ne pouvait pas voir est rapporté : la liste reste courte et pertinente.
Dans le PE Parser
- Ouvrez un fichier natif 32 ou 64 bits et allez dans l’onglet Analyse du code. L’analyse tourne dans le navigateur en quelques centaines de millisecondes pour la plupart des fichiers.
- Les chaînes récupérées sont listées avec leur type (décodée, pile, boucle serrée) et la fonction qui les a construites. Cliquez l’adresse pour ouvrir le désassemblage à cet endroit.
- Les chaînes qui semblent encore encodées (surtout des symboles) sont masquées par défaut ; une case les affiche.
- Les indicateurs réseau parmi les chaînes récupérées — URL, domaines, adresses IP — rejoignent l’onglet IOC et ses exports (exporter les IOC).
- Pour analyser toute une collecte, utilisez Analyse du code dans la barre d’outils : chaque fichier natif est traité et une colonne Code indique combien de capacités et de chaînes chacun contient.
Le même onglet liste les capacités trouvées dans le code : vérifications anti-débogage, injection de processus, hachage d’API, constantes cryptographiques (MD5, SHA, CRC32, TEA, RC4, AES), hooks de keylogging et plus, chacune rattachée à MITRE ATT&CK et au Malware Behavior Catalog, avec les fonctions où elle a été trouvée.
Limites
- Fichiers packés. Si le code est packé, on émule le stub de dépaquetage, pas le programme. Dépaquetez d’abord — le PE Parser gère UPX lui-même (détecter les exécutables packés).
- Couverture des instructions. L’émulateur gère le code x86 / x64 entier ordinaire. Les décodeurs qui reposent sur des instructions flottantes ou SIMD sont ignorés.
- Clés venues de l’extérieur. Un décodeur dont la clé vient du réseau, du registre ou d’un fichier lu à l’exécution ne peut pas être résolu statiquement.
- Budgets. Chaque émulation est plafonnée pour qu’un fichier hostile ne bloque pas la page ; les très gros programmes peuvent être analysés partiellement, et l’onglet le signale.
Quand ces limites gênent, l’étape suivante est le bac à sable : exécuter l’échantillon dans un environnement isolé et vider sa mémoire. Pour la grande majorité des malwares courants, l’émulation récupère pourtant les chaînes utiles en quelques secondes — sans que l’échantillon ne s’exécute jamais.