Affichage des articles dont le libellé est electronic. Afficher tous les articles
Affichage des articles dont le libellé est electronic. Afficher tous les articles

mercredi 6 juillet 2011

[EN] NDH 2011 badge hacking part 3 : Let's code!

Hello folks!

Here is the final part of my NDH 2011 Badge Hacking serie.
We know how to plug it, read it ... how about we write in it now?

Pre-requisites

As you could see from the first post about the pinout, there are PORTA, PORTB and PORTD.
These are defines in AVR C headers that allows you to set those corresponding ports.
Setting one of the bits of a PORT would set the corresponding PIN to high or 1. Basically if you set bit 6 (we are counting from 0), you will switch on LED 5.

On tixlegeek's blog, you should also have seen DDRB and DDRD. These sets the pins as inputs or outputs. Setting a bit to 1 set the corresponding pin as an output and 0 as an input.

LED stand for "Light Emiting Diode" for those who do not know. And Diodes are component that allow the current to flow in only one direction (not speaking about the Zener diode though).

And last thing but not the least, do not forget that we are coding on a micro-controller so we have a limited amount of space (either in RAM, ROM, etc), limited amount of processing power, well limited resources.
Taking that into account, you will see some "ugly hacks" to go around problems such as RAM exhaustion like you will see in my example program.

So what can you do with such a small micro-controller?

To be simple, a micro-controller is a chip with very limited resources or a component integrating multiple functionnalities in one chip: video, audio, CPU, image processing, etc.

A micro-controller can be used as a control device, smalls robotics or mapping LEDs to boards, etc.

In this case, the badge only have 7 LEDs for outputs and not inputs but the programming of the badge.
You are only limited by your creativity (and resources).

You could do those for example:
- small animations from right to left, left to right, etc
- counting
- sending data (you would need a receiver though)
- showing a dump from a network capture for example
- etc
Yeah pretty much anything you can represent with 7 LEDs, 7 bits, etc.
But to tell the truth, yeah you can't code much stuffs on it :p.

I decided to code a morse code emitter :).
But first, let's see the original code.

Original firmware

Here what the original firmware is:

//B1 B0 D6 D5 D4 D3 D2
/*
** Compiler Include Directives
*/
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

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

 }
}

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(5):0);
  PORTD |= (((value^42)&_BV(4))?_BV(4):0);
  PORTD |= (((value^42)&_BV(5))?_BV(3):0);
  PORTD |= (((value^42)&_BV(6))?_BV(2):0);
}

For the most attentive people, you must have spotted the buggy code:
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(5):0);
  PORTD |= (((value^42)&_BV(4))?_BV(4):0);
  PORTD |= (((value^42)&_BV(5))?_BV(3):0);
  PORTD |= (((value^42)&_BV(6))?_BV(2):0);
}

If you recall the full pinout:
-------------------------
|          PORTD        |
-------------------------
|   PIND0   |   RX      |
|   PIND1   |   TX      |
|   PIND2   |   D4      |
|   PIND3   |   D3      |
|   PIND4   |   D2      |
|   PIND5   |   D1      |
|   PIND6   |   D5      |
-------------------------
|          PORTB        |
-------------------------
|   PINB0   |   D6      |
|   PINB1   |   D7      |
|   PINB2   |   NC      |
|   PINB3   |   NC      |
|   PINB4   |   NC      |
|   PINB5   |   MOSI    |
|   PINB6   |   MISO    |
|   PINB7   |   SCK     |
-------------------------
|          PORTA        |
-------------------------
|   PINA0   |   NC      |
|   PINA1   |   NC      |
|   PINA2   |   RESET   |
-------------------------

Then after fixing the code you get this:
void copy2array(char value)
{
 char byte=0;
  PORTB=0;
  PORTD=0;
  PORTD |= (((value^42)&_BV(0))?_BV(5):0);
  PORTD |= (((value^42)&_BV(1))?_BV(4):0);
  PORTD |= (((value^42)&_BV(2))?_BV(3):0);
  PORTD |= (((value^42)&_BV(3))?_BV(2):0);
  PORTD |= (((value^42)&_BV(4))?_BV(6):0);
  PORTB |= (((value^42)&_BV(5))?_BV(0):0);
  PORTB |= (((value^42)&_BV(6))?_BV(1):0);
}

Ok now, let's go on with Morse code :).

Let's code: Morse code

Here is my "firmware" to do morse code:

// @author  : m_101
// @license : beerware
// @year    : 2011
// @program : Do morse code on leds of NDH 2011 badge

// standard libraries
#include <ctype.h>
#include <string.h>

// avr specific libraries
#define F_CPU 1000000
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

// defines for turning on a single led at a time
#define D1_ON()     PORTD |= _BV(5)
#define D2_ON()     PORTD |= _BV(4)
#define D3_ON()     PORTD |= _BV(3)
#define D4_ON()     PORTD |= _BV(2)
#define D5_ON()     PORTD |= _BV(6)
#define D6_ON()     PORTB |= _BV(0)
#define D7_ON()     PORTB |= _BV(1)

// defines for turning off a single led at a time
#define D1_OFF()    PORTD &= ~_BV(5)
#define D2_OFF()    PORTD &= ~_BV(4)
#define D3_OFF()    PORTD &= ~_BV(3)
#define D4_OFF()    PORTD &= ~_BV(2)
#define D5_OFF()    PORTD &= ~_BV(6)
#define D6_OFF()    PORTB &= ~_BV(0)
#define D7_OFF()    PORTB &= ~_BV(1)

// morse code duration (international standard)
#define DOT_DURATION        200
#define DASH_DURATION       3*DOT_DURATION
#define INTERGAP_DURATION   DOT_DURATION
#define GAP_LETTERS         3*DOT_DURATION
#define GAP_WORDS           7*DOT_DURATION

void leds_morse(char value);

// turn off the leds
#define leds_off()      \
            PORTB = 0;  \
            PORTD = 0

// put morse table in program space (not enough RAM)
// international morse code
// letters
char morse_A[] PROGMEM = ".-";
char morse_B[] PROGMEM = "-...";
char morse_C[] PROGMEM = "-.-.";
char morse_D[] PROGMEM = "-..";
char morse_E[] PROGMEM = ".";
char morse_F[] PROGMEM = "..-.";
char morse_G[] PROGMEM = "--.";
char morse_H[] PROGMEM = "....";
char morse_I[] PROGMEM = "..";
char morse_J[] PROGMEM = ".---";
char morse_K[] PROGMEM = "-.-";
char morse_L[] PROGMEM = ".-..";
char morse_M[] PROGMEM = "--";
char morse_N[] PROGMEM = "-.";
char morse_O[] PROGMEM = "---";
char morse_P[] PROGMEM = ".--.";
char morse_Q[] PROGMEM = "--.-";
char morse_R[] PROGMEM = ".-.";
char morse_S[] PROGMEM = "...";
char morse_T[] PROGMEM = "-";
char morse_U[] PROGMEM = "..-";
char morse_V[] PROGMEM = "...-";
char morse_W[] PROGMEM = ".--";
char morse_X[] PROGMEM = "-..-";
char morse_Y[] PROGMEM = "-.--";
char morse_Z[] PROGMEM = "--..";
// digits
char morse_0[] PROGMEM = "-----";
char morse_1[] PROGMEM = ".----";
char morse_2[] PROGMEM = "..---";
char morse_3[] PROGMEM = "...--";
char morse_4[] PROGMEM = "....-";
char morse_5[] PROGMEM = ".....";
char morse_6[] PROGMEM = "-....";
char morse_7[] PROGMEM = "--...";
char morse_8[] PROGMEM = "---..";
char morse_9[] PROGMEM = "----.";
// conversion table
PGM_P code[] PROGMEM = {
    // A ... M
    morse_A, morse_B, morse_C, morse_D, morse_E, morse_F, morse_G, morse_H,
    morse_I, morse_J, morse_K, morse_L, morse_M, 
    // N ... Z
    morse_N, morse_O, morse_P, morse_Q, morse_R, morse_S, morse_T, morse_U,
    morse_V, morse_W, morse_X, morse_Y, morse_Z,
    // 0 .. 9
    morse_0, morse_1, morse_2, morse_3, morse_4, morse_5, morse_6, morse_7,
    morse_8, morse_9 
};

// get index in morse code table
int tomorse_idx (char value) {
    int idx = -1;

    if (isalpha(value))
        idx = (toupper(value) - 'A') % 26;
    else if (isdigit(value))
        idx = (value - '0') % 10 + 26;

    return idx;
}

int main (void) {
    // message to show and its index
    char idxMsg;
    char msg[] = "Hello World For NDH 2011";
    // morse code and its index
    char idxMorse;
    char morse[8] = {0};
    // index in morse conversion table
    char idxCode;    

    // init port B and D data direction as outputs
    DDRD = 0xff;
    DDRB = 0xff;

    // init PORTS
    PORTB = 0;
    PORTD = 0;

    // repeat message
    while(1) {
        idxMsg = 0;

        // print string while not ended
        while(*(msg+idxMsg)) {
            idxMorse = 0;

            // morse code index
            idxCode = tomorse_idx(*(msg+idxMsg));

            // ensure cleaning of the local buffer
            memset(morse, 0, sizeof(morse));

            // put code in RAM if got a correct idx
            if (idxCode >= 0 && idxCode < 36)                
                strcpy_P(morse, (PGM_P)pgm_read_word(&(code[idxCode])));

            // parse morse code
            while(*(morse+idxMorse)) {
                // led show morse code
                leds_morse(*(morse+idxMorse));

                // inter-gap between dots and dashes
                leds_off();
                _delay_ms(INTERGAP_DURATION);

                // next morse symbol
                idxMorse++;
            }

            // blank
            leds_off();
            // gap between letters
            if (isalnum(*(msg+idxMsg)))
                _delay_ms(GAP_LETTERS);
            // gap between words
            else
                _delay_ms(GAP_WORDS);

            idxMsg++;
        }
    }
}

// turn on leds for morse code
void leds_morse(char value) {
    // init PORTS
    PORTB = 0;
    PORTD = 0;

    // "long press"
    if (value == '-') {
        D1_ON();
        D2_ON();
        D3_ON();
        D4_ON();
        D5_ON();
        D6_ON();
        D7_ON();
        _delay_ms(DASH_DURATION);
    }
    // "short press"
    else if (value == '.') {
        D3_ON();
        D4_ON();
        D5_ON();
        _delay_ms(DOT_DURATION);
    }
}

The AVR chip is set to work at 1Mhz :).

I guess it is a bit more readable concerning switching ON or OFF a specific LED.

You must have seen the weird way of creating the string table and using it. We basically only have 128 bytes of RAM, the string tables would thus obviously not fit in it completely (with other local variables in a function). We thus force the compiler to put our string table in program space and copy the corresponding morse sequence to a local buffer before using it.

The code is well commented (too much commented? :)) so you would not have any problems reading it. If you were to spot any bugs, do not hesitate to send me a patch ;).

As an exercise to the reader, I let you modify the code so that it directly turns on the LED given a morse code sequence.

Here is a small utility to convert an ASCII string to morse code:

// @author  : m_101
// @license : beerware
// @year    : 2011
// @program : Convert ASCII string to Morse code sequence

#include <stdio.h>
#include <stdlib.h>

char* tomorse (char value) {
    char *code[] = {
        // A ... M
        ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
        // N ... Z
        "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..",
        // 0 .. 9
        "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."
    };
    int idx;

    if (isalpha(value)) {
        idx = (toupper(value) - 'A') % 26;
        return code[idx];
    }
    else if (isdigit(value)) {
        idx = (value - '0') % 10 + 26;
        return code[idx];
    }

    return " ";
}

int main (int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s str\n", argv[0]);
        return 0;
    }

    while (*argv[1]) {
        printf("%s ", tomorse(*argv[1]));
        argv[1]++;
    }
    putchar('\n');

    return 0;
}

Play with it,


$ avr-gcc -Os -g -Wall -I.  -mmcu=attiny2313 -c -o badge_morse.o badge_morse.c
badge_morse.c: In function 'main':
badge_morse.c:145: warning: array subscript has type 'char'
$ avr-gcc -g -mmcu=attiny2313 -o badge_morse.elf badge_morse.o
$ avr-objcopy -j .text -j .data -O ihex badge_morse.elf badge_morse.hex
$ sudo avrdude -c usbasp -p attiny2313 -U flash:w:badge_morse.hex -v

avrdude: Version 5.10, compiled on Jun 29 2010 at 21:09:48
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/home/kurapix/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/parport0
         Using Programmer              : usbasp
         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

         Programmer Type : usbasp
         Description     : USBasp, http://www.fischl.de/usbasp/

avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e910a
avrdude: safemode: lfuse reads as 64
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FF
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: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: reading input file "badge_morse.hex"
avrdude: input file badge_morse.hex auto detected as Intel Hex
avrdude: writing flash (898 bytes):

Writing | ################################################## | 100% 0.63s



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

Reading | ################################################## | 100% 0.48s



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

avrdude: safemode: lfuse reads as 64
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Conclusion

As you could see, with little imagination and work, you can achieve interesting and fun stuffs. We now know how to plug it, read it, write in/program it, hell yeah we mastered it ;).

Just a last message for those who got a NDH Badge 2011: Do you know that not all speakers/challengers/etc got to have one (I got really lucky, I almost did not get one)? By the way, a looot of people will not even play with it. Damn, if you take it, play with it! It is not just to look pretty (people put work into making them).

Hope you enjoyed it,

Have fun,

Cheers,

m_101

Resources: 
Morse code
[NDH2K11] Badges hackable!
NDH2K11's Badge: Spec. & hackz
NDH2K11's Badge: PROGRAMMATIONNNNNN!!!!
- Manual of avrdude

- AVR 8-bit Instruction Set
- AVR Programming
- AVR GCC Tutorial (1) – Basic I/O Operations
AVR : Tutorial 2 : AVR – Input / Output
- AVR GCC FAQ
Program Space

[EN] NDH 2011 badge hacking part 2 : What is the message?

Hello!

Now you should have a nice working cable.
Today we are going to get the message.

Dumping the flash

We can look into the chip memory using avrdude terminal mode:
$ sudo avrdude -c usbasp -p attiny2313 -t

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

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e910a
avrdude> dump flash 0 512
>>> dump flash 0 512 
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...............|
0180  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
0190  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
01a0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
01b0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
01c0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
01d0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
01e0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
01f0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude>

We don't see any "clear" interesting string for our purpose. Maybe it is obfuscated.

We are going to dump it to a file for backup purposes:

$ sudo avrdude -c usbasp -p attiny2313 -n -U flash:r:dump.hex:i -v

avrdude: Version 5.10, compiled on Jun 29 2010 at 21:09:48
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/home/m_101/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/parport0
         Using Programmer              : usbasp
         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

         Programmer Type : usbasp
         Description     : USBasp, http://www.fischl.de/usbasp/

avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e910a
avrdude: safemode: lfuse reads as 64
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FF
avrdude: reading flash memory:

Reading | ################################################## | 100% 1.10s



avrdude: writing output file "dump.hex"

avrdude: safemode: lfuse reads as 64
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Now we dumped the flash.

Getting the message

In the previous dumped firmware we could see the following strings:
- "Nothing there N00b!"
- "bOFFE }EXFN LEX dnb\x18a\x1b\x1b"

I wrote a quick hack to see if we got any "usual" obfuscation scheme such as caesar or XOR were used:
// @author  : m_101
// @license : beerware
// @year    : 2011
// @program : "Bruteforce" caesar and XOR
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// caesar
char *caesar (char *str, const int len, const unsigned int key) {
    int idxStr, rkey, c;
    char *cryptext;

    // allocate cryptext
    cryptext = calloc(len, sizeof(*cryptext));
    if (!cryptext)
        return NULL;

    //
    rkey = key % 26;

    for (idxStr = 0; idxStr < len; idxStr++) {
        /*
        if (!isalpha(str[idxStr])) {
            free(cryptext);
            return NULL;
        }
        //*/
        c = toupper(str[idxStr]) + key;
        /*
        if (c > 'Z')
            c -= 26;
        else if (c < 'A')
            c += 26;
        //*/
        cryptext[idxStr] = c;
    }

    return cryptext;
}

#define BUFSIZE     1024

void bf_caesar (char *str, const int len) {
    int key;
    char *cryptext;
    //
    char filename[1024];
    FILE *fp = NULL;

    if (!str || !len) {
        printf("Bad string\n");
        return;
    }

    if (strlen(str) != len) {
        printf("Bad length\n");
        return;
    }

    for (key = 1; key <= 255; key++) {
        cryptext = caesar(str, len, key);
        if (cryptext) {
            // generate filename
            snprintf(filename, BUFSIZE, "%s-%02d", "caesar", key);
            // write to file
            /*
            fp = fopen(filename, "w");
            if (fp) {
                fwrite(cryptext, sizeof(*cryptext), len, fp);
                fclose(fp);
            }
            //*/
            
            // print to console
            printf("%02d : %s\n\n", key,  cryptext);
            free(cryptext);
        }
    }
}

void bf_xor (char *str, const int len) {
    int key;
    int c;
    int idxStr;
    //
    char filename[1024];
    FILE *fp = NULL;

    if (!str || !len) {
        printf("Bad string\n");
        return;
    }

    if (strlen(str) != len) {
        printf("Bad length\n");
        return;
    }

    for (key = 1; key <= 255; key++) {
        printf("%02d : ", key);
        // generate filename
        snprintf(filename, BUFSIZE, "%s-%02d", "xor", key);
        // fp = fopen(filename, "w");
        for (idxStr = 0; idxStr < len; idxStr++) {
            c = str[idxStr] ^ key;
            putchar(c);
            // write to file
            /*
            if (fp)
                fwrite(&c, sizeof(*str), 1, fp);
            //*/
        }
        putchar('\n');

        if (fp)            
            fclose(fp);
    }
}

int main (int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s str\n", argv[0]);
        return 1;
    }

    printf("Bruteforce Caesar:\n");
    bf_caesar(argv[1], strlen(argv[1]));

    printf("\nBruteforce XOR:\n");
    bf_xor(argv[1], strlen(argv[1])); 

    return 0;
}

As you could see, for caesar I did not bother to do a rotating scheme as usual but a stupid and simple shifting.

I managed to get 2 messages:
Hello\nWorld\nFor\nNDH
hELLO*wORLD*FOR*ndh
Done.

There was another way to get the message using a video camera to capture the leds sequence and decode it manually of using image processing techniques.
I did not want to do that so I did not do it ... have fun for the courageous ones ;).

You could also use IDA Pro (or any compatible disassembler) to reverse the ASM code from the dumped firmware. I did not want to spend too much time on it so I skipped it. If you want to do it, here is the documentation: AVR 8-bit Instruction Set

Next I will show you an example of programming the chip.

Cheers,

m_101

Resources:
[NDH2K11] Badges hackable!
NDH2K11's Badge: Spec. & hackz
NDH2K11's Badge: PROGRAMMATIONNNNNN!!!!
- Manual of avrdude
- AVR 8-bit Instruction Set

jeudi 30 juin 2011

[EN] NDH 2011 badge hacking part 1 : Pinout reversing

* UPDATED (6 July 2011) *:
- Fixed links (ATMEL documentation)
- Added section on full pinout


Hello!

Today we are going to do some "hardware" hacking (if we can call it like that ...). Yes, NDH badge hacking :D.
I do not have any real knowledge in electronics but it should be enough to pawn it.

The thing I am the most amazed with is that nobody wrote an article about it but the creator of the badge (tixlegeek) ...

Let's fix that!

The situation

First of all, I could not not find the pinout on Tix's Le Geek blog so I had to "reverse" it.
It is because I have the following programmer (a version of USBasp):



So the cable is a 2x5 pin ICSP AVR.

We want to have something clean so we are going to use a BUS cable:


As well as small clips:



To plug it into a small socket:


To set up the clips, you need to use a flat-nosed plier like this:


For reversing the pinout you could also use wires and a breadboard (I don't have a breadboard ... or any electronic stuffs ^^"):


Don't forget your NDH badge!


In the end you should have all those:


Reversing the pinout

Ok for the pinout you could try to find VCC and GND first with a multimeter and then the other ports. As I do not have any electronic equipment I haven't tried that.

But here what was my idea with the wires :


Yeah, try to craft kind of a hook or something and plug the other part to a breadboard and test it.


 luckily there is another way to find out about the pinout:



Yes just looking at the chip documentation you could find the pinout.
Anyway for the chip, looking close enough you could see its reference:
ATMEL 1114
ATTINY2313V-10SU

Done we have the pinout.
Just have to make the cable ;).

The pinout

Badge NDH
-------------------------------------------------
    |       |       |       |       |       |
   RST    MOSI    MISO     SCK     VCC      GND


Port 2x5 ping AVR ICSP

    1           3         5           7          9
---------------------------------------------------------
|   MOSI    |   NC  |   RESET   |   SCK     |   MISO    |
---------------------------------------------------------
|   VCC     |   GND |   GND     |   GND     |   GND     |
---------------------------------------------------------
    2           4         6           8          10

Do the pinout and then we're in business :).

Full pinout

Just in case people might find this useful:
-------------------------
|          PORTD        |
-------------------------
|   PIND0   |   RX      |
|   PIND1   |   TX      |
|   PIND2   |   D4      |
|   PIND3   |   D3      |
|   PIND4   |   D2      |
|   PIND5   |   D1      |
|   PIND6   |   D5      |
-------------------------
|          PORTB        |
-------------------------
|   PINB0   |   D6      |
|   PINB1   |   D7      |
|   PINB2   |   NC      |
|   PINB3   |   NC      |
|   PINB4   |   NC      |
|   PINB5   |   MOSI    |
|   PINB6   |   MISO    |
|   PINB7   |   SCK     |
-------------------------
|          PORTA        |
-------------------------
|   PINA0   |   NC      |
|   PINA1   |   NC      |
|   PINA2   |   RESET   |
-------------------------

It is evident that you need to read the documentation to understand that table: the chip documentation.

Conclusion

With a bit of curiosity, it was possible to find out about the pinout fairly easily.
As I miscounted  the AVR ICSP pinout ... my cable is not right, so the software part is going to be for another day ;).

Cheers,

m_101

Resources:
[NDH2K11] Badges hackable!
NDH2K11's Badge: Spec. & hackz
NDH2K11's Badge: PROGRAMMATIONNNNNN!!!!
- ATTiny2313 documentation