Nuit Du Hack
Creative Commons License
.

Aller au contenu | Aller au menu | Aller à la recherche | Voir les modalités d'utilisation des travaux de l'auteur

Page d'accueil rss Sélection Geekstories.fr La Boite à Vomi

jeudi 23 juin 2011

NDH2K11's Badge: PROGRAMMATIONNNNNN!!!!

[ Partager : Partager sur Digg ]
Salutations!

Deuxième article de la série "Bidouiller le badge de la NDH2K11". Ce soir, on va... Programmer!!!!!

Comme le veut la tradition, nous allons coder un "HelloWorld", en utilisant le principe de base du badge: Afficher une série de caractères sur une ligne de 7bits.

Pourquoi 7bits? Le code ASCII, dans sa version non-étendue, est codé sur 7bits. --> Moins de LEDs, moins cher.

Alors tout d'abord, quelque explications. Ceux qui ont déjà reversé son simplissime schéma l'auront remarqué, le mappage des leds est obscure:

Il n'est pas question ici de vous filer un cours de programmation/électronique... D'autre le font déjà ailleurs. C'est pourquoi je vous encourage à aller faire un tour sur le net!

On voit sur le schéma que les LEDs ne sont pas mappées sur un seul port (comme on l'aurait fait le plus simplement...) mais sur deux port. Pourquoi? Bien, pour pouvoir sortir l'USART et l'ICSP de l'AVR facilement. Et voilà, c'est aussi simple que ça!
Nous devrons donc créer une fonction qui re-mappera un octet (paramètre) sur les deux ports.

Notre fonction d'écriture...

C'est à ce moment que je dois remercier le mystérieux ste7an, qui à mis en lumière LE bug du badge. Raison? --> Mauvaise fonction de re-mappage. Je prendrai compte de sa correction dans la suite de l'article. Merci encore à lui!

La fonction de mappage utilisée dans les badges (fonction corrigée, hein) peut sembler un peu ésotérique. Mais il n'en est rien! Je ferai mon possible pour dégrossir le truc.

#define _BV(bit) (1 << (bit)) 

void copy2array(char value)
{
	char byte=0;
		PORTB=0;
		PORTD=0;
		PORTB |= (((value^42)&_BV(0))?_BV(1):0);
		PORTB |= (((value^42)&_BV(1))?_BV(0):0);
		PORTD |= (((value^42)&_BV(2))?_BV(6):0);
		PORTD |= (((value^42)&_BV(3))?_BV(2):0);
		PORTD |= (((value^42)&_BV(4))?_BV(3):0);
		PORTD |= (((value^42)&_BV(5))?_BV(4):0);
		PORTD |= (((value^42)&_BV(6))?_BV(5):0); 
}

Vous remarquerez sans doutes le "value^42" qui traine au milieu du code. En fait, le code n'est pas stoqué "en claire" dans la mémoire du composant (ce qui évite aux petits malins de dumper simplement le code, pour en extraire la solus du chall). C'est un faible cryptage (XOR) permettant de décrypter "à la volée" les données présentes en mémoire. On l'utilisera aussi dans l'exemple de cet article.

La macro _BV(), très utilisée dans pleins de fonctions diverses et variées, à tous les niveaux, dans tous les programmes, permet de "sélectionner" un bit. Ici, on reprend chaque bit (suivant son mappage) et on lui affecte la valeur d'un bit de l'octet "value". Une petite analyse de la fonction devrait vous faire comprendre le cheminement.

Notre fonction principale...

Notre fonction principale, ici encore, dérivée du firmware "officiel" du badge, est suffisamment simple pour qu'on ne s'y attarde pas trop.

int main(void)
{
	char EasterMSG[20]="Nothing there N00b!";
	char CHALL[23]={0x62,0x4f,0x46,0x46,0x45,0xa,0x7d,0x45,0x58,0x46,0x4e,0xa,0x4c,0x45,0x58,0xa,0x64,0x6e,0x62,0x18,0x61,0x1b,0x1b}, i=0;
	
	DDRD=0xff;
	DDRB=0xff;
	PORTB=EasterMSG[2];
	while(1==1)
	{
		i=0;
		EasterMSG[0]=*(CHALL+i);
		while(*(CHALL+i))
		{
			copy2array(*(CHALL+i));
			_delay_ms(40);
			i++;
		}

	}
	return 0;
}

La variable "EasterMSG" est un petit message à l'attention de ceux qui auraient essayé de chopper le code en dumpant la flash du composant. Comme il n'est pas utilisé par le programme, il devrait etre scratché par le précompilateur. En effet, une des principales mission des pré-compilateur, c'est de faire le ménage (variables statiques, macros, defines...) en remplaçant chaque expression par son équivalent le plus astucieux. C'est pourquoi on voit la ligne "PORTB=EasterMSG[2];" qui sert à faire entrer la chaine de caractère dans la flash de l'AVR. En fait, ça reviens à faire un "volatile" (Je vulgarise pas mal, mais, vous devriez comprendre)

Élaboration du code.

Bigre! Passons à la pratique. Déjà, on va virer tout ce qui ne nous sert pas --> cryptage, message d'accueil des dumperz, etc...


#define F_CPU 1000000 // Suivant le prescaling de l'oscillateur
#include <avr/io.h>
#include <util/delay.h>

void copy2array(char value);
int main(void)
{
   char Hello[]="Hello World!", i=0;
   // Initialisation des ports B et D en entrées ou sorties.
   DDRD=0xff;
   DDRB=0xff;
   // Boucle infinie --> Répetition du message.
   while(1==1)
   {
      i=0;
      // Tant que *CHALL + i tappe dans le bon segment, ça roule
      while(*(Hello+i))
      {
         copy2array(*(Hello+i));
         // On attends un peut (base de temps fausse)
         _delay_ms(1000);
         // Caractère suivant!
         i++;
      }

   }
}

void copy2array(char value)
{
      // Initialise les ports
      PORTB=0;
      PORTD=0;
      PORTB |= ((value&_BV(0))?_BV(1):0);
      PORTB |= ((value&_BV(1))?_BV(0):0);
      PORTD |= ((value&_BV(2))?_BV(6):0);
      PORTD |= ((value&_BV(3))?_BV(5):0);
      PORTD |= ((value&_BV(4))?_BV(4):0);
      PORTD |= ((value&_BV(5))?_BV(3):0);
      PORTD |= ((value&_BV(6))?_BV(2):0);
      //                   ^       ^
      // Bit         "MÉMOIRE"    "PHYSIQUE"
}

Voilà notre code!

Compilation

La compilation se fait avec AVR-Gcc. Excellente toolchain libre, et extrêmement fonctionnelle. Pour flasher le firmware de tous les badges (il y en avait 120, que les mecs de la NDH ont soudés A LA MAIN O___O), j'ai utilisé un makefile qui réduisait le temps de flashage à 2/3s par badge. Il est disponible dans l'archive complète, en bas de page.

Premièrement, vous avez besoin des programmes suivants:

  • gcc-avr
  • binutils-avr
  • gdb-avr
  • avr-libc
  • avrdude
Sur une Debian/Ubuntu, tapez simplement:
sudo apt-get install gcc-avr binutils-avr gdb-avr avr-libc avrdude

Tout d'abord, copiez le code source dans un fichier, ouvrez une console, et placez vous dans le bon dossier. Ceci fait, on peut alors appeler avr-gcc, comme un gcc normal, tout en lui fournissant des informations sur le type de binaire à générer, le type de composant, etc...

La liste des options d'avr-gcc est longue comme le bras. Je vous encourage à lire le man pour en avoir un avant-goût, et faire les choses dans les règles de l'art (pas comme moi, donc).

avr-gcc -Os -g -Wall -I.  -mmcu=attiny2313 -c -o main.o main.c
avr-gcc -g -mmcu=attiny2313 -o main.elf main.o
avr-objcopy -j .text -j .data -O ihex main.elf main.hex

avr-gcc, c'est le compilo. Pour le reste:

    Première ligne : avr-gcc -Os -g -Wall -I. -mmcu=attiny2313 -c -o main.o main.c
  • -Os : Optimisation de la taille
  • -g : Inclure les données de debug
  • -Wall : Afficher tous les avertissements.
  • -mmcu : Type de composant (jeu d'instruction)
  • -I : Dossier à inclure pour les headers
  • -o : Fichier de sortie (obj)
  • Deuxième ligne : avr-gcc -g -mmcu=attiny2313 -o main.elf main.o
  • -g : Inclure les données de debug
  • -mmcu : Type de composant (jeu d'instruction)
  • -o : Fichier de sortie (elf)
  • Troisième ligne : avr-objcopy -j .text -j .data -O ihex main.elf main.hex (avr-objcopy permet de mixer la ratatouille, et, par conséquent, de récupérer des bouts des "bin" compilés, pour les incorporer au ".hex" final.)
  • -j : Section(s) à importer -->
  • -mmcu : Type de composant (jeu d'instruction)
  • -O : Type de binaire généré.

Flashââââge de badge

Et c'est tout.... Concernant la compilation. Pour faire tourner notre code sur le badge, il faut le flasher! Le flashage consiste à écrire le code compilé (.hex) dans la flash. Ainsi, le composant exécutera les premières instructions qu'il aura sous la dent, et notre badge clignotera. Pour se faire, on va utiliser avrdude:

# avrdude -p t2313 -c usbasp -U flash:w:main.hex

Si vous utilisez un programmateur USB, et que vous n'avez pas bien réglé votre udev, il vous faudra exécuter cette commande en root. En théorie, vous devriez voir un truc dans ce genre:

avrdude -p t2313 -c usbasp -U flash:w:main.hex

avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e910a
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (336 bytes):

Writing | ################################################## | 100% 0.28s



avrdude: 336 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as Intel Hex
avrdude: input file main.hex contains 336 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.17s



avrdude: verifying ...
avrdude: 336 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Et voilà! Vous avez codé votre premier HelloWorld sur un badge de la NDH2k11 (ou tout autre support AVR... Question d'addaptation!) Mais, ce n'est pas fini. En effet, la programmation d'un AVR induit la configuration de plein de choses... comme les fuses, que l'on verra dans la prochaine partie, ainsi que la partie "makefile" du badge :)

Place à la joie simple qui déchire les yeux:

Youpppiiii!
++ Tixlegeek.

mardi 21 juin 2011

NDH2K11's Badge: Spec. & hackz

[ Partager : Partager sur Digg ]
Salut!

Voilà enfin un petit article expliquant comment bidouiller le badge de la nuit du hack 2011.

Les spécifications techniques du badge sont les suivantes:

  • µC: ATtiny2313V :Micro contrôleur 8bit de chez ATMEL. Dispose d'un UART
    • 2K Bytes of In-System Self Programmable Flash
    • 128 Bytes In-System Programmable EEPROM
    • 128 Bytes Internal SRAM
    • 1 x 8-bit Timer/Counter with Separate Prescaler and Compare Mode
    • 1 x 16-bit Timer/Counter with Separate Prescaler, Compare and Capture Modes
    • 4 x PWM Channels
    • On-chip Analog Comparator
    • USI – Universal Serial Interface
    • Full Duplex USART
  • 7 LEDs rouges
  • USART accessible sur pads
  • Port ICSP Six broches

Le circuit est on ne peut plus simple. On utilise l'oscillateur RC interne du µC: "Calibrated internal RC Oscillator 8MHz" pour ne pas avoir à câbler de quartz (et ne pas avoir à le payer, par la même occasion :p). Les 7 LEDs n'utilisent pas un port complet de l'µC. C'est pas tres pratique à programmer, mais, ça a permis de sortir l'USART sur trois pads dédiés. (schéma à venir)

Pour le programmer, on peut utiliser tout type de programmateur... Perso, j'utilise un compatible "USBasp", qu'on trouve sur ebay pour une bouchée de pain. Le tout est de bien relier les lignes MISO, MOSI, SCK, RST, Vcc, GND. Juste en bas, vous avez une photo du programmateur que j'utilise (un de ses frères tout du moins), son PINOUT, ainsi que celui du badge.

Une fois cablé, vous pouvez commencer à bidouiller. Pour ça, on va utiliser avr-dude (dispo sur pas mal de plateformes, tres bien foutu). On peut alors faire pas mal de choses, comme ouvrir un terminal "de debug":

tixlegeek@crippledvorticon:~$ sudo avrdude -c usbasp -p attiny2313 -t
[sudo] password for tixlegeek: 

avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e910a
avrdude> 

Là, on vient d'ouvrir un terminal de "debug" avec AVRdude. Celui çi nous permet de faire pas mal de choses, comme écrire dans le µC, voir ce qui se passe dans toute les mémoires, récupérer des informations.... tout est disponible là:

avrdude> h
>>> h 
Valid commands:

  dump   : dump memory  : dump   
  read   : alias for dump
  write  : write memory : write     ... 
  erase  : perform a chip erase
  sig    : display device signature bytes
  part   : display the current part information
  send   : send a raw command : send    
  parms  : display adjustable parameters (STK500 only)
  vtarg  : set  (STK500 only)
  varef  : set  (STK500 only)
  fosc   : set  (STK500 only)
  sck    : set  (STK500 only)
  spi    : enter direct SPI mode
  pgm    : return to programming mode
  help   : help
  ?      : help
  quit   : quit

Use the 'part' command to display valid memory types for use with the
'dump' and 'write' commands.

avrdude>

Première étape: récupérer des infos sur le device. Un bon petit compte rendu de ce qui se passe sur notre badge:

avrdude> part
>>> part 

AVR Part                      : ATtiny2313
Chip Erase delay              : 9000 us
PAGEL                         : PD4
BS2                           : PD6
RESET disposition             : possible i/o
RETRY pulse                   : SCK
serial program mode           : yes
parallel program mode         : yes
Timeout                       : 200
StabDelay                     : 100
CmdexeDelay                   : 25
SyncLoops                     : 32
ByteDelay                     : 0
PollIndex                     : 3
PollValue                     : 0x53
Memory Detail                 :

                         Block Poll               Page                       Polled
  Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
  ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
  eeprom        65     6     4    0 no        128    4      0  4000  4500 0xff 0xff
  flash         65     6    32    0 yes      2048   32     64  4500  4500 0xff 0xff
  signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00
  lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
  lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
  hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
  efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
  calibration    0     0     0    0 no          2    0      0     0     0 0x00 0x00

avrdude>

On peut alors commencer à dumper la flash, qui contient le programme du badge:

avrdude> dump flash 0x00 0x180
>>> dump flash 0x00 0x180
0000  12 c0 22 c0 21 c0 20 c0  1f c0 1e c0 1d c0 1c c0  |..".!. .........|
0010  1b c0 1a c0 19 c0 18 c0  17 c0 16 c0 15 c0 14 c0  |................|
0020  13 c0 12 c0 11 c0 11 24  1f be cf ed cd bf 10 e0  |.......$........|
0030  a0 e6 b0 e0 e8 e4 f1 e0  02 c0 05 90 0d 92 ac 38  |............ ..8|
0040  b1 07 d9 f7 3c d0 7e c0  db cf 18 ba 12 ba 98 b3  |....<.~.........|
0050  3a e2 38 27 43 2f 50 e0  30 fd 02 c0 80 e0 01 c0  |:.8'C/P.0.......|
0060  82 e0 89 2b 88 bb 28 b3  ca 01 96 95 87 95 81 70  |...+..(........p|
0070  82 2b 88 bb 92 b3 42 fd  02 c0 80 e0 01 c0 80 e4  |.+....B.........|
0080  89 2b 82 bb 92 b3 43 fd  02 c0 80 e0 01 c0 80 e2  |.+....C.........|
0090  89 2b 82 bb 82 b3 30 71  38 2b 32 bb 92 b3 45 fd  |.+....0q8+2...E.|
00a0  02 c0 80 e0 01 c0 88 e0  89 2b 82 bb 92 b3 46 fd  |.........+....F.|
00b0  02 c0 80 e0 01 c0 84 e0  89 2b 82 bb 08 95 cf 92  |.........+......|
00c0  df 92 ef 92 ff 92 1f 93  df 93 cf 93 cd b7 de b7  |................|
00d0  ab 97 0f b6 f8 94 de bf  0f be cd bf de 01 11 96  |................|
00e0  e0 e6 f0 e0 84 e1 01 90  0d 92 81 50 e1 f7 9b 81  |........ ..P....|
00f0  de 01 55 96 e4 e7 f0 e0  87 e1 01 90 0d 92 81 50  |..U......... ..P|
0100  e1 f7 8f ef 81 bb 87 bb  98 bb 90 e0 75 e1 c7 2e  |............u...|
0110  d1 2c cc 0e dd 1e 68 ec  e6 2e f1 2c 0a c0 95 df  |.,....h...., ...|
0120  80 e9 91 e0 f7 01 31 97  f1 f7 01 97 d9 f7 91 2f  |......1......../|
0130  9f 5f f6 01 e9 0f f1 1d  80 81 19 2f 90 e0 88 23  |._........./...#|
0140  c1 f3 ed cf f8 94 ff cf  4e 6f 74 68 69 6e 67 20  |........Nothing |
0150  74 68 65 72 65 20 4e 30  30 62 21 00 62 4f 46 46  |there N00b!.bOFF|
0160  45 0a 7d 45 58 46 4e 0a  4c 45 58 0a 64 6e 62 18  |E }EXFN LEX dnb.|
0170  61 1b 1b 00 ff ff ff ff  ff ff ff ff ff ff ff ff  |a...............|

avrdude>

Si vous suivez, vous verrez que le code du chall n'est pas disponible en claire dans la mémoire. Mais, les plus vifs d'entre nous trouverons vite ou se trouve cette info.

La suite dans un prochain article :D On verra comment faire des programmes sur notre badge, on utilisera l'USART, et on ajoutera le Bluetooth à notre badge, pour pouvoir le commander à distance.

Plusplus, Tixlegeek.

Creative Commons License
Les travaux signés "Tixlegeek" by DUBIEF Gery sont mis à disposition selon les termes de la licence Creative Commons Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique 2.0 France.

Pour toute modifications apportées, ou diffusion, merci de mentionner l'auteur d'origine, et l'adresse de ce blog.