Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Howto Protect your Arduino Code and Secure the Bootloader
#1
First, lets see how to read AVR code - using external programmer, e.g USBASP:

Code:
avrdude -p m328p -P usb -c usbasp -U flash:r:flash.hex:i

Or using bootloader read back that exists for program verification:

Code:
avrdude -p m328p -P COM6 -c arduino -U flash:r:flash.hex:i


Securing first one is simple, just set the LB0 and LB1 to zero (e.g. avrdude ... -U lock:w:0x3C:m). No external programmer will be able to read this anymore.

If you need bootloader, you are going to have to secure it. Yes, recompile Wink Because the new bootloader is over 512 bytes, you will need to locate it lower (usually at 0x7E00, now 0x7C00)

avrdude and most programmers allow reading back flash content to verify that programming went through properly. This feature is convenient but also an open door for anyone to download the firmware and clone the device at the cost of blank hardware. In order to maintain the bootloader functionality, I have modified bootloader based on Optiboot 6.x, that only allows reading back section of flash written since last reset. Because bootloader is proprietary, I will only show relevant pieces.

1. define new variables that specify unlocked flash region. Optiboot does not use regular global variables, but beginning of the RAM is used as buffer for flashing, so we will just take two locations above that. Place this before int main(void) {

Code:
#define myUnlckFlashLo (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+16))
#define myUnlckFlashHi (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+18))

2. initialize these two variables right after int main(void) {

Code:
  myUnlckFlashLo = 0;
  myUnlckFlashHi = 0;

3. We need to expand unlocked region whenever the programmer writes. At the same time we need to make sure we wont expand by more than one page (avrdude writes by pages) and also that we won't unlock entire flash just by writing one page at the beginning and one at the end, so the written pages will have to be adjanced.

Find the in writebuffer right after __boot_page_erase_short((uint16_t)(void*)address); ... boot_spm_busy_wait(); paste following:

Code:
        if(len > SPM_PAGESIZE)
            len = SPM_PAGESIZE;
        uint16_t addrEnd = addrPtr + len;
        if(!myUnlckFlashHi) {
            myUnlckFlashLo = addrPtr;
            myUnlckFlashHi = addrEnd;
        } else {
            if(addrPtr < myUnlckFlashLo && addrEnd >= myUnlckFlashLo)
                myUnlckFlashLo = addrPtr;
            if(addrEnd > myUnlckFlashHi && addrPtr <= myUnlckFlashHi)
                myUnlckFlashHi = addrEnd;
        }

4. Finally we need to ensure that anything outside of unlocked region is read as FF.

In read_mem right after __asm__ ("lpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address)); paste this:

Code:
        if(address <= myUnlckFlashLo || address >= myUnlckFlashHi)
            ch = 0xff;


That's it. Now you can still flash and verify your arduino code from Arduino IDE, but right after the reset, the unlocked region of flash will be reset and attacker won't be able to read anything he did not write himself.
Reply
#2
Wow, very nice Roman.
I only wish I had code this valuable Tongue 
Maybe some day...
Bob D
Reply
#3
Hey Roman, you know more details about this than me, but wouldn't you be able to reflash the boot loader alone to gain access to the user code ? (or is that possible without blanking the rest ?)
--------------- ---- --- -- -  -
If things weren't meant to be modified, they would not come with wires attached.
Reply
#4
Not possible

Longer answer: perhaps by etching the chip and extracting data from the die
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)