Loader un binaire Arduino dans IDA

Bon, maintenant que l’on sait comment prendre un dump d’un Arduino, Il ne faut pas croire qu’on peut juste ouvrir le binaire dans IDA.

Ca n’est pas aisé de faire manger ce binaire à IDA. Pour ma part déjà, j’ai un IDA qui ne connait pas le cpu atmel AVR ATmega328 que l’on retrouve sur le Arduino Uno.

Heureusement il suffit d’indiquer les spécifications de ce contrôleur dans le fichier /cfg/avr.cfg et IDA retrouve miraculeusement ses petits. On trouve tous ces paramètres dans la documentation de référence ATmega48A/PA/88A/PA/168A/PA/328/P chez Atmel.

J’ai donc recopié et modifié la configuration du 168p et ca semble aller. Voici ma conf, j’espère que je n’ai pas fait d’erreurs. Si qqun en trouve merci de me le dire.

Mais c’est pas tout. Ca serait trop simple. Si on charge un binaire on se retrouve avec des access à des variable qui sont non initialisées. C’est donc fortement pénalisant pour comprendre le code. D’autant que pour une simple led, il est de bon ton sur arduino de faire comme l’exemple et d’utiliser des variables :)

Même si on a identifié la procédure setup et la procédure pinmode, la valeur de LED mise dans r24 restera un mystère.
avrnoref

Pour comprendre ce qui nous arrive, il faut un peut s’intéresser à comment marchent les cpu AVR. Ces CPUs sont basés sur une architecture Harvard, ca veut dire qu’il y a une mémoire pour le programme (la ROM) qui est complètement séparée de la RAM où sont les variables. La rom subsiste en cas de coupure d’électricité, mais évidemment pas la ram. Dans cette architecture, les programmes peuvent utiliser des variables en RAM, la ROM étant Read Only (ou presque, car cela se flash tout de même.)

Donc, la lecture/écriture c’est dans la ram. A coté de cela en plus il y a un espace mémoire nommé EEPROM qui permet d’écrire et de lire des data qui survivrons en cas de coupure électrique, un genre de disque dur quoi. Ici je ne m’en sert pas.

Grosso modo, pour ne pas perdre les quelques uns d’entre nous qui comprennent le x86 et qui ont connus le code en 16 Bits. c’est comme ca : Il y a 3 Segments. Un “CS” la Rom, Un “DS” la RAM, et un Extra “ES” l’eeprom. Ces segments ne se chevauchent pas, et celui de la RAM est remplis de 0 à chaque power on.

Dans le cas du AtMega328 on a 2k de Ram, 32k de Rom et 1K d’eeprom.

AVR_memory_01_lrg

Mais pour désassembler le code AVR c’est «chiant». Tous les programmes utilisent des références à des variables en RAM, mais la ram n’est pas initialisée chez nous, on n’a que un dump de la ROM. Alors dans la vrai vie, comment ca fonctionne;

Si on utilise l’environnement de développement Arduino ou simplement GCC pour avr, il y à une procédure nommée “__do_copy_data” qui au démarrage du programme s’occupe de recopier les variables initialisée de la ROM vers la RAM.

La ram est organisée de cette façons sur le AtMega328 :

Ouais je sais c’est chelou, Les 32 registres du CPU (R0 à R31) Sont en fait de la ram, après cela de 0x20 à 0x100 il y a les registres d’entrée sortie. C’est tous des registres un peu spéciaux par exemple en 0x5F c’est SREG que l’on connait nous sur x86 sous le nom de FLAGS.

C’est Seulement à partir de 0x100 on à de la vrai ram ou l’on peut faire ce que l’on veut. Mais voila, comment faire pour initialiser cette ram dans IDA et pouvoir reverser tranquille. GCC à la compilation pose les variables initialisées au cul du code, et donc pour chaque programme l’emplacement en ROM des variables change de place.

Et bien il faut “simplement” reverser “__do_copy_data” pour trouver l’emplacement des variables et leur taille. Si j’ai le courage, je pondrais un jour un python automatique.

Tout commence dans la fonction __RESET qu’IDA connait grace à notre cfg custom. (Sinon, elle est pointée par un saut au tout début de la rom). La première étape est de reseter les flags, et d’initialiser l’offset de la stack. La stack est sur 16 bits, et son pointeur est découpé en 2 registres 8 bits. SPH pour la partie haute du stack pointeur partie haute et SPL pour la partie basse. On retrouve ces deux pointeurs en RAM dans la partie I/0 Register 0x3D pour SPH et 0x3E pour SPH, mais ici aussi notre cfg fait un miracle.

Alors c’est un truc auquel il va falloir s’habituer les enfants, les CPUs AVR aiment les couples de registres 8 Bits. Il y a même 3 couples célèbres qui font des registres 16 Bits. Le couple r26,r27 qui est nommé le registre X. r28,29 qui est Y et r30,r31 qui est Z. Ils appellent ca les registres indirects.

Nous voila enfin dans la partie juteuse. le couple r26,r27 est l’adresse de destination en RAM, le couple R30,31 est l’adresse sources de nos variables. Dans cet exemple c’est en 0x9a8.

A partir de là c’est partis pour recopier byte à byte jusqu’a ce que X pointe 0x122.

On a donc bien compris, l’initialisation copie 0x22 Bytes depuis ROM:0x9a8 vers RAM:0x100. Et bien on va se créer un fichier “RAM” identique au programme qui se serait déjà fait “initialiser” et on l’utilisera darns IDA.

Etape 1 on crée un pad de bytes à 0 qui à une taille de 0x100 (256 en décimal).

Ensuite on extrait de la rom nos 0x22 bytes tant convoités et on les colle au cul de la ram.

Et enfin on pad le reste de cette ram avec du 0. ( 2Ko – (256 + 34)) = 1758

Et on se retrouve alors avec un joli fichier représentant une ram initialisée.

Ne reste plus qu’a la mettre en place dans IDA en lieu et place de cette ram non initialisée. Pour cela dans IDA on fait : View/Open Subview/Segment. On delete le segment nommé RAM.

delram

On fait FILE/Load File/Load additionnal File et on sélectionne notre RAM.bin. On charge le segment en 0x10000 tout le reste à 0 et on décoche “Code Segment”

Il ne reste plus qu’a éditer les attributs du segment pour faire joli et changer le segment name en RAM et le segment class en DATA et désormais, les variables sont initialisée !! Tous est vachement plus clair.

after

Voila, il n’y a plus qu’a désosser maintenant. le grand fichier des opcodes est là.

Have Fun !

This entry was posted in Reverse and tagged , , , . Bookmark the permalink.

One Response to Loader un binaire Arduino dans IDA

  1. Pingback: Riscure RHme2: FridgeJIT – Reverse Engineering Challenge – Capture the Swag

Leave a Reply

Your email address will not be published. Required fields are marked *

Please Do the Math