This firmware is the one used by Thomas Roth (stacksmashing) in his YouTube video Bare-metal ARM firmware reverse engineering with Ghidra and SVD-Loader. The binary is originally available at ghidraninja/arm-bare-metal-1, but is included in this repository for convenience: blink.bin
-
Start Ghidra and create a new non-shared project "Blinky" (
File→New Project...) -
Import the ELF file
blink.bin(File→Import File...) withARM:LE:32:Cortex:defaultas Language. Keep the remaining settings as their default: -
Open the binary in CodeBrowser (double-click) and click
Noin theAnalyze?dialog -
Open the ARMify plugin via
Window→ARMify Pluginand clickYesin theARMify initializationdialog: -
After a short initialization, ARMify is opened in the MMIO Accesses view:
-
A quick look into the Candidate Groups view reveals that ARMify found only two register accesses, resulting in 94 possible candidate groups — far too many. We need to narrow down the candidates by manually adding register accesses.
-
Switch back to the MMIO Accesses view. ARMify identified the register accesses
40020000,40020014(twice), and40023800(twice), but only the first two with a high Confidence. Let us check out why ARMify identified40023800with a low Confidence. To do so, click on the Instruction Address0800232or080023a. The cursor in the Listing (disassembly) jumps to this address in functionFUN_08000224. Let's have a look at the decompiled code: -
As you can see, there is a memory-write to the register address
40023800 + param1andparam1is passed to the function. In the decompile window, right-click theFUN_08000224function name and selectReferences→Find References to FUN_08000224: -
There are three references, all from
FUN_08000224. Click on any of the three entries to jump to the function: -
In function
FUN_080001acfunctionFUN_08000224is called three times with the values0x600,0x603, and0x811. Therefore, we can calculate the memory write inFUN_08000224:40023800 + param1=40023800 + (0x600 >> 5)=40023800 + 0x30=4002383040023800 + param1=40023800 + (0x603 >> 5)=40023800 + 0x30=4002383040023800 + param1=40023800 + (0x811 >> 5)=40023800 + 0x40=40023840
-
Let us now delete the wrongly identified register access
40023800: In ARMify's MMIO Accesses view, select the two entries with the Register Address40023800(press Ctrl + Left-click to select multiple entries) and click the delete icon
. Confirm the Delete Entries from Tabledialog. -
Now we are going to add the above calculated addresses
40023830and40023840: Click the add button
and enter the following values in the dialog. Since there is no concrete
Instruction Address we could either leave it empty or we can enter the first instruction address of function
FUN_08000224to be able to jump to the function from the table in the MMIO Accesses view. For convenience, you can select the beginning of the function in the Listing (disassembly) window and press the pipette button
to copy the address into the textbox: -
Do the same for the address
40023840 -
The MMIO Accesses view table should look like this afterward:
-
Check out the Candidate Groups view. By simply adding
40023830and40023840, we reduced the number of candidate groups from 94 to 16. -
Step through the candidate groups (select index 0, then 1 and so on) and inspect the identified register and peripheral names in the table at the top of the Candidate Groups view. You may recognize that for all groups, except the sixth group (
xmc7100, xmc7200, tviic2d6m), the addresses40020000and40020014are identified as peripheralGPIOAand addresses40023830and40023840are identified as peripheralRCC(Reset & Clock Control),RCM(Reset & Clock Management), orRCU(Reset & Clock Unit). -
A closer look at
FUN_080001acandFUN_08000224shows that they set bits0and3of register0x40023830, and bit17of register0x40023840:*0x40023830 |= (1 << 0) | (1 << 3); // 0x600 and 0x603 *0x40023840 |= (1 << 17); // 0x811 -
In the Candidate Groups view, select the sixth candidate group (
xmc7100, xmc7200, tviic2d6m) and afterward select the register address40023840in the register address table at the top. Press the view fields information
button and inspect the register layout. As
you can see, the SL_ADDRregister has theADDR30field with MSB32and LSB2. Therefore, this candidate group is a false positive and can be ignored: -
All other candidate groups have the same layout for our four register addresses (
40020000,40020014,40023830, and40023840). We can check this either with the Compare functionality or view the fields information next to each other:-
Compare functionality: Select the group with index
0(STM32F765, STM32F779, STM32F768, ...) and (press Ctrl + Left-click to select multiple entries) with index13(STM32F446) and press the Compare button. A new dialog informs you that the layouts in registers40023830and40023840differ. You can select one of the entries in the table and get a detailed explanation about the differences: -
View fields information next to each other: First select the group with index
0(STM32F765, STM32F779, STM32F768, ...) and press the view fields information
button for register 40023830. Keep the newly opened dialog open and do the same for the group with index13(STM32F446). You now can compare the fields of the two groups next to each other. TheSTM32F765, STM32F779, STM32F768, ...has more GPIO ports, but for both groups, the fieldsGPIOAENandGPIODENare the same:
-
-
Normally, you now would have to analyze the field layout of all candidate groups to identify the appropriate groups. Since we know that the
STM32F446device is the right one, we can select it and press the Apply button. -
Now that we've applied the
STM32F446device, let's analyzeFUN_080001cc. ARMify identified writes to the register addresses40020000and40020014in this function. However, we can't see them in the decompiled code: -
Double-click on
DAT_08000218in the Decompile view. The Listing (disassembly) jumps to the address08000218. The data type is currently identified asundefined4. We can change it topointerby right-click and selectingData→pointeror by simply pressingp. Do the same forDAT_0800021c. Afterward, the decompiled code should look like this:
That concludes the advanced usage of ARMify.













