Ghidra is great for ELF-esque executable files. But what about a full firmware blob you pulled off an EEPROM? Some notes on decompiling ArduPilot.
Theoretical exercise with known outcomes
To do this, I’ve compiled ArduCopter locally on my machine and am simply analyzing the binary it produced. This also gives me the advantage of knowing the target architecture, debugging symbols, knowing what offsets to start looking at (no need for binwalk analysis), etc etc etc.
This would probably be somewhat harder simply analyzing an unknown blob.
Reading the binary
Language selection
I already know that I built this firmware for a ProfiCNC Cube Orange, which is an STM32H7 - an ARMv7 architecture. When you import the file into Ghidra, it should prompt you for a language — find ARM:LE:32:v7:default (ARMv7, little endian, 32bit, default compiler unless you happened to build with Visual Studio for some reason).
Executable offsets
From the STM32H7 datasheet, the flash memory section is mapped into the memory space at 0x0800_0000. In the import dialog, select “Options”, and add a new block, setting the name to “flash” and base address to 0x08000000. Do not adjust file offset or length.
Why not file offsets?
Leaving the file offset at zero and length as (the full file length) works for blobs where the entire flash memory is executable, and assumes no filesystem carving needs to take place (or it has already been done).
In my contrived example, I am not actually analyzing a “dead-bug rip from an EEPROM / SPI flash IC” blob, but rather a
.binflash image fresh off the compiler, so I already know the full file is the executable image.
Continue the import and run the default analyzers.