I have an Arduino Uno Rev3. I would like to extract and find out what code is burned on the ROM of the micro-controller board.

  1. How do I extract the code from the board?
  2. How do I figure out the original source code that went into the hex file?
  • In order to improve the answer below - do you have any more details on what you're looking for out of the original source code? – mborowczak Mar 21 '13 at 19:00
  • 1
    @borowcm Basic functioning. Your answer covers that. I havent selected that as the best answer, as others could answer/add to it. – asheeshr Mar 22 '13 at 1:23
up vote 34 down vote accepted

I'll answer this in two parts, #1 is relatively easy, #2 impossible to the level which I'm assuming you want.

1. Extracting the hex code from the Uno:

While the specifics will depend on the revision of the Uno that you have, you'll want to use avrdude (available for linux, bundled with the OS X Arduino software) and a command similar to the following that would extract the information from an ATmega168:

avrdude -F -v -pm168 -cstk500v1 -P/dev/ttyUSB0 -b19200 -D -Uflash:r:program.bin:r

Look at the avrdude documentation to match the part parameter -p specific to your device (or post them and we can go from there).

Since it appears that you have the Uno Rev3, that board has an ATmega328 (-pm328). The programmer "communicates using the original STK500 protocol" thus the communication protocol flag -c should be -cstk500v1 the command you would need (assuming the Uno is connected to /dev/ttyUSB0) follows:

avrdude -F -v -pm328p -cstk500v1 -P/dev/ttyUSB0 -b19200 -D -Uflash:r:program.bin:r

Next up your second question.

2. Converting Hex code to original source:

Sorry, but that's not possible. While you can get some hex to c "decompilers" the gibberish returned, while functionally correct, will not be human readable (some commercial ones, like Hex-Rays, might give you some level of human-readability).

With that said, you're best bet would be a hex to assembly translator/converter - which will still only give you a better picture of what's happening, but will still be (by definition) very low level. All variable names, comments etc would be stripped and you're still going to be left with not knowing the original source program contents - just the compiled result.

Since you're dealing with an Atmel device you could try to use the avr specific gcc toolchain avr-gcc. Specifically, you'll need avr-objdump using the needed MCU type flag -m atmega328 (avr5) architecture (Full List of Available Architectures, MCU types)

avr-objdump -s -m atmega328 program.hex > program.dump

It is also possible, depending on your configuration, that providing the architecture type itself (avr5) would be sufficient:

avr-objdump -s -m avr5 program.hex > program.dump

On windows for an arduino nano, you do this:

cd "C:\Program Files (x86)\Arduino\hardware\tools\avr\bin"

followed by this:

"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude" -F "-CC:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -v -patmega328p -carduino -PCOM14 -b57600 -D-Uflash:r:c:\keep\program.bin:r

Here's the output from the above grabbing code:

avrdude2.exe: Version 6.0.1, compiled on Mar 30 2015 at 14:56:06
              Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
              Copyright (c) 2007-2009 Joerg Wunsch

              System wide configuration file is "C:\Program Files (x86)\Arduino\
hardware\tools\avr/etc/avrdude.conf"

              Using Port                    : COM14
              Using Programmer              : arduino
              Overriding Baud Rate          : 57600
              AVR Part                      : ATmega328P
              Chip Erase delay              : 9000 us
              PAGEL                         : PD7
              BS2                           : PC2
              RESET disposition             : dedicated
              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    20     4    0 no       1024    4      0  360
0  3600 0xff 0xff
                flash         65     6   128    0 yes     32768  128    256  450
0  4500 0xff 0xff
                lfuse          0     0     0    0 no          1    0      0  450
0  4500 0x00 0x00
                hfuse          0     0     0    0 no          1    0      0  450
0  4500 0x00 0x00
                efuse          0     0     0    0 no          1    0      0  450
0  4500 0x00 0x00
                lock           0     0     0    0 no          1    0      0  450
0  4500 0x00 0x00
                calibration    0     0     0    0 no          1    0      0
0     0 0x00 0x00
                signature      0     0     0    0 no          3    0      0
0     0 0x00 0x00

              Programmer Type : Arduino
              Description     : Arduino
              Hardware Version: 2
              Firmware Version: 1.16
              Vtarget         : 0.0 V
              Varef           : 0.0 V
              Oscillator      : Off
              SCK period      : 0.1 us

avrdude2.exe: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude2.exe: Device signature = 0x1e950f
avrdude2.exe: safemode: lfuse reads as 0
avrdude2.exe: safemode: hfuse reads as 0
avrdude2.exe: safemode: efuse reads as 0
avrdude2.exe: reading flash memory:

Reading | ################################################## | 100% 9.49s

avrdude2.exe: writing output file "c:\keep\program.bin"

avrdude2.exe: safemode: lfuse reads as 0
avrdude2.exe: safemode: hfuse reads as 0
avrdude2.exe: safemode: efuse reads as 0
avrdude2.exe: safemode: Fuses OK (H:00, E:00, L:00)

avrdude2.exe done.  Thank you.

and this is the resulting file:-

C:\Program Files (x86)\Arduino\hardware\tools\avr\bin>dir c:\keep\program.bin
 Volume in drive C has no label.
 Volume Serial Number is EE8C-DFB9

 Directory of c:\keep

19/02/2016  07:00 PM            32,670 program.bin
               1 File(s)         32,670 bytes
               0 Dir(s)  41,416,818,688 bytes free

I renamed my "avrdude.exe" to "avrdude2.exe" and wrote a shim named "avrdude.exe" which calls the real one after outputting what the arduino does to build to my target device.

The original command my system used to build was:-

C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude "-CC:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -v -patmega328p -carduino -PCOM14 -b57600 -D -Uflash:w:C:\Users\user\AppData\Local\Temp\build4588201597642272956.tmp/TFT_Baja2.cpp.hex:i

Interesting fact: the hex dump included fragments of other code I'd written... this suggests some very interesting privacy and security problems for anyone shipping arduinos which have been previously used for other things...

If you're using boards other than a nano, my shim was:

#!perl

use strict;

foreach(@ARGV){$_=qq("$_") if(/\s/)};   # DOS Wants quotes around space-embedded paramaters!

foreach(@ARGV){$_='-v' if($_ eq '-q');} # go verbose instead of silent

my $parms=join(" ",@ARGV);
open(OUT,">>","C:\\keep\\avrdude.log") || warn "Cannot write: $!"; 
print OUT "\n" . &db_now() . " $0 $parms\n"; close(OUT);

my $rc=`avrdude2.exe $parms`;

open(OUT,">>","C:\\keep\\avrdude.log"); print OUT $rc; close(OUT);
print $rc;

# Return "now()" in mysql default format.
sub db_now {
     my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
     return sprintf("%04d-%02d-%02d %02d:%02d:%02d",1900+$year,$mon+1,$mday,$hour,$min,$sec);
}

compiled to a windows .exe using:

perlapp avrdude.pl

enjoy!

There is a way to recompile with this opensource app, called RetDec:

https://github.com/avast-tl/retdec

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.