the minipro program to interact with the chip programmer. The following command writes the firmware to a file. ``` minipro -p "W25Q16JV@SOIC8" -r flash.bin ```
I can verify that this is the firmware by running strings
and examining the output.
The MCU is a rpi2040 which makes use of the “execute in place” feature. This is a feature that improves performance by enabling execution directly in flash storage rather than execution in the MCU’s limited memory area. It is important that we keep this in mind before starting to analyze the firmware. Firmware has no entry point and instead has a defined address at which program execution begins. We can find this base address by viewing the rpi2040 datasheet and navigating to the “Address Map” page from the table of contents. The base address will be the XIP address (execute in place). We need to specify this address as the base address in whatever we use to analyze the firmware to load the correct segment.
Using Binaryninja I can specify the base address when creating a new project. Binja automatically detects the thumb2 ARM architecture.
I start to try and identify useful symbols and organize the code by searching through strings and going to their code references.
Some areas have been incorrectly loaded as symbols so I undefine them.
I also rename symbols that have obvious functions for clarity.
Identifying and following the code reference of the interesting string, “YOU DID IT!” leads to what seems to be the function that is called when a correct key combination is entered.
The only code reference leads to the following function. The first thing I noted when initially examining it was the comparison inside the loop to 0x2d. This conditional is equal to if(r3_1 == 0x2d(which is 46))
since the if-statement ends in a break. Examining the note count on my own badge and noting the number of badges with different variations, we know the total number of piano keys that make-up the passing combo is 46, since all badge’s music sheets will be used.
The decompilation process complicated this loop a bit, so for sanity’s sake lets simplify it a bit in our heads. The while loop iterates over the length of the correct combo, once it reaches 46 (the length of the combo) it succeeds. The second if-statement is most important, it compares every key (it gets the key by referencing the location of the key presses in memory with the offset of the current index) with the given character at string[index] if it is not equal, it breaks ending the while loop early and never reaching the success block, else it increments combo_length. So the string in the second conditional is what we need to pay attention too.
C@><>@C@><>@C@CE@EC@><C@><>@C@><>@>@C@CE@EGDB@
Since each key press is being compared with this string, it is safe to assume that each character in this string is mapped to a physical key on the badge. We should find another function which identifies this mapping. This would likely be the keypress code blobs directly.
Some things to note before continuing:
checkwin has a lot of code references. Each call is likely in a blob for a key press. I’ll pin the references window and tag them all to keep everything organized and visible on the pane.
Examining the very first reference we can take note that a pointer is being passed as the argument. The value at this pointer is being assigned above. For this instance that value is 0x3c, whose ascii representation is “<”.
Each blob that assigns a mapping is sequential in the code block, so I can safely assume that these are the keyboard mappings assigned in the order as they appear on the physical keyboard.
Proceeding to the next checkwin call will reveal the mapping for the C# key (the little black key) which comes next.
Proceeding through every checkwin call will reveal the character mappings for the entire keyboard.
With these mappings we can decipher the string compared in the checkwin function to the equivalent keys on the keyboard.
key_map = {"<":"C","=":"C#",">":"D","?":"D#","@":"E","A":"F",
"B":"F#","C":"G","D":"G#","E":"A","F":"A#","G":"B"}
key_combo = ""
for c in "C@><>@C@><>@C@CE@EC@><C@><>@C@><>@>@C@CE@EGDB@":
key_combo += key_map.get(c)+" "
print(key_combo)
The following is the correct key-combination/tune we need to play on the badge keyboard in order to pass the first challenge.
G E D C D E G E D C D E G E G A E A G E D C G E D C D E G E D C D E D E G E G A E A B G# F# E
FaultPoint.com is a personal blog maintained by elbee.
Cracking the DEFCON 30 Badge Firmware
By Dylan, 2022-11-22