Introduction
Quand on entend le mot "nanomite", on pense souvent à de la science-fiction, à des nanorobots microscopiques qui dévorent du métal ou réparent des cellules. Mais dans le monde du reverse engineering, c'est un terme qui a longtemps donné des sueurs froides aux analystes.
Clarifions tout de suite : par "nanomites d’Armadillo", on ne parle pas de nanotechnologie au sens scientifique. Il s'agit du nom (très marketing) donné à une technique redoutable d'anti-debug et d'anti-reverse-engineering utilisée par le célèbre protecteur Windows Armadillo.
Armadillo utilisait une combinaison ingénieuse de self-debugging (le programme se débogue lui-même) et de ces fameuses nanomites pour rendre un binaire extrêmement hostile à l'analyse statique et dynamique.
1. L'architecture d'Armadillo : Le Debug Blocker
Pour comprendre les nanomites, il faut d'abord comprendre l'environnement dans lequel elles évoluent. Armadillo repose sur un concept fondamental appelé le Debug Blocker.
L'idée est diaboliquement simple : sous Windows, un processus ne peut être débogué que par un seul débogueur à la fois.
Quand un programme protégé par Armadillo se lance, il ne lance pas directement le code utile. À la place :
- Le processus original démarre (on l'appelle le Parent).
- Ce Parent lance une seconde instance de lui-même (l'Enfant) en utilisant l'API Windows
CreateProcessavec le flagDEBUG_PROCESS. - Le Parent agit désormais comme le débogueur légitime de l'Enfant.

Pourquoi c'est fort ? Parce que si vous essayez d'attacher votre x64dbg ou OllyDbg au processus Enfant (qui contient le vrai code), Windows vous dira gentiment d'aller voir ailleurs : le processus est déjà en cours de débogage !
2. Le mécanisme exact des Nanomites
Maintenant que le Parent tient l'Enfant en laisse, il peut interagir avec lui via les événements de débogage. C'est ici qu'entrent en scène les nanomites. Le but est de casser l'analyse statique en détruisant le graphe de flot de contrôle.
2.1. La mutation du code (ASM)
Lors de la protection, Armadillo repère des instructions de saut conditionnel et les remplace par des instructions INT 3 (opcode 0xCC).
Voyons la différence dans un désassembleur comme IDA Pro :
Avant protection (Code classique, lisible) :
; Vérification d'une licence (EAX = 1 si OK)
test eax, eax
jnz licence_valide ; Si EAX != 0, on saute au code de succès (75 05)
call message_erreur ; Sinon, on affiche l'erreur
exit
Après protection via Armadillo (Graphe cassé) :
; Le saut JNZ a disparu au profit d'une interruption
test eax, eax
int 3 ; 0xCC - Déclenche une exception de debug
db 0x90 ; Octet de remplissage (NOP)
call message_erreur ; IDA pense que le code continue ici quoi qu'il arrive
exit
Pour un reverse engineer, le code ne ressemble plus à rien. Le flux logique est interrompu par des exceptions et IDA affiche souvent des "Jumpouts" car il ne sait plus où va le code.
2.2. L'exécution à la volée
À l'exécution, voici ce qu'il se passe à chaque fois que l'Enfant rencontre une nanomite :

- L'Enfant exécute l'instruction
INT 3. - Cela déclenche une exception matérielle :
EXCEPTION_BREAKPOINT. - Le flux d'exécution de l'Enfant est suspendu par Windows.
- Windows notifie le Parent (le débogueur) via l'API
WaitForDebugEvent. - Le Parent récupère l'état des registres de l'Enfant via
GetThreadContext. - Le Parent consulte sa table secrète : "À cette adresse, c'était un JNZ. Est-ce que le flag Zero est activé ?"
- Le Parent modifie le registre
EIPde l'Enfant viaSetThreadContextpour le faire pointer vers la bonne destination. - Le Parent relance l'Enfant.
C'est une symbiose parfaite : le programme "cassé" ne peut pas fonctionner sans son Parent pour recoller les morceaux à la volée.
3. Analyse et contournement
Évidemment, ce n'est pas une protection infaillible. Au fil du temps, les analystes ont développé des méthodes pour vaincre cette armure.
3.1. La reconstruction (Nanomite Fixing)
L'objectif est de trouver l'adresse de la table des nanomites en mémoire du Parent, de la déchiffrer, puis d'écrire un script pour patcher l'Enfant en remplaçant les 0xCC par les bons opcodes de saut originaux (74 pour JZ, 75 pour JNZ, etc.).
3.2. Le piège des "Fausses Nanomites"
Pour compliquer la tâche, Armadillo utilisait des leurres. Un octet 0xCC peut apparaître légitimement dans une instruction, et il ne faut surtout pas le patcher !
; Une instruction parfaitement légitime avec CC dans l'adresse
mov eax, dword ptr [0x0040CC00] ; L'adresse contient CC !
; Si votre script remplace bêtement TOUS les CC par des sauts :
; Vous corrompez le programme et il crash immédiatement.
Conclusion
Les nanomites d'Armadillo sont un exemple fascinant de détournement des mécanismes de l'OS (le debugging) pour en faire une arme de protection. En déplaçant la logique décisionnelle hors du flux d'instructions, Armadillo a forcé les reverse engineers à changer de paradigme.
Aujourd'hui, cette technique a évolué vers l'obfuscation par virtualisation, où ce n'est plus juste un saut qui est caché, mais l'intégralité du code, comme nous l'avons vu dans notre précédent dossier.
Le jeu du chat et de la souris continue !
