You read the contents of flash and save it to a file. It can then be re-flashed if your need is not to edit, but duplicate.
- This reads all flash, including the bootloader, and also PROGMEM data.
Use avr-objdump (or similar) to disassemble the instructions.
Again, PROGMEM data is going to be interpreted as opcodes, and may not be valid opcodes.
You may want to dump the fuses as well, for redirected vectors and such.
Use pattern analysis to recognise source patterns as compiled. Then iteratively compile and compare fragments.
This is harder than is looks, whilst most Arduino code is very simple, the libraries can be be wild and woolly. At least the hex file is human readable, but little endian.
It might be easier to "walk through" the assembly and perform a translation of the perceived behaviour. OK for 10 instructions, but harder for 16K of them.
You will also need the Atmel/Microchip *def.inc files for the MPU component enumerations so that you know your DDRB from you DDRC a good disasembler should know.
You can do this well enough for Blink, and recognise stack pointer initialization.
It is much easier without a bootloader, as booting should jump to main and main can start at 0 other than after the vectors.
Of course lock bits will ruin your day, and it may just be better for character to code it again.