/*
 * avr-gcc -g -mmcu=atmega32 -O1 bufoverflow.c -o bufoverflow.atmega32
 * avr-objdump --disassemble bufoverflow.atmega32
 *
 * simulavr -g -d atmega32 -f bufoverflow.atmega32
 *  target remote localhost:1234
 *  break evil  -- shall never hit, but it does
 *  c
 * */


#include <string.h>
#include <avr/io.h>


// Ok for a demo, but we want to pass this to the compiler, i.e., through a
// cmake config
#define F_CPU 8000000UL

#include <util/delay.h>

// This function is never called, yet it is executed by a buffer overflow
// attack. In its payload it is toggeling PORT b pins.
//
// This function will be at byte address 0x82, which is word-address 0x41
void evil() {
    while (1) {
        PORTB ^= 0xff;
        _delay_ms(500);
    }
}

// The victim function contains a buffer overflow flaw. The memcpy() does not
// check array bounds and we can control the return address, which allows us to
// "return" to the function evil().
void victim(const char* src) {
    // 0x800840:  buf
    // buf[12..13]: return address
    char buf[10];
    memcpy(buf, src, 14);

    // Hinder optimizer to optimize everyting away.
    if (buf[0] == 0x00)
        PORTB = 0xf0;

    return;
}

void main() {
    // buf[12..13]: overwrite return address to 0x41
    char src[20] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x00\x41";
    victim(src);
    return;
}
