Bare-metal ARM firmware reverse engineering with Ghidra and SVD-Loader

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey in this video I'd like to give you an introduction into reverse engineering a bare-metal our microcontroller firmware using Hydra and the script called SVD loader now before we start let's quickly talk about what bare metal is on a computer or in smartphone an application runs on top of an operating system this operating system will then use drivers to communicate with the actual hardware in the case of a bare metal system our application runs directly on the hardware without any operating system or so in between in the wild you will find that a lot of smaller embedded and IOT devices will be bare metal systems such as for example the Amazon - buttons smart light bulbs electric door locks and so on in this video we will look at a firmware running on top of an ARM Cortex and micro controller more specifically we will look at something that runs on an STMicroelectronics stm32 which is a widely used ARM based microcontroller family the microcontroller has a lot of integrated peripherals such as general purpose input outputs you are I sweat see SPI and so on the specific controller are used today is the stm32f4 46 re and on the STMicroelectronics website you can get a nice overview of all the features it contains such as 4 times I squared C a camera interface HDMI and so on in the datasheet of the microcontroller you can find the pin out which depends on the specific package you use but basically the programmable inputs and outputs are organized in ports here I've highlighted port 8 consisting of 16 GPS GPS or general purpose input outputs can be used to connect all kinds of stuff such as LEDs switches and more complex things such as displays and so on the hardware support for I squared C and so on can be mapped to certain pins by configuring the chip peripherals now without an operating system that provides us with syscalls and drivers how do we actually talk to all of these features this is done using something called memory map peripherals or memory mapped i/o cortex and processors have a flat memory map without any memory management unit or so and our flash our RAM and all of the peripherals will be available by accessing their respective memory addresses for example on the stm32 the flash which also contains our code will be mapped at hex 800 the RAM at hex 2000 and all the peripherals start at hex 4000 to configure these peripherals all we have to do is write the write data to the right addresses in memory an overview over the memory map can be found in the datasheet of the processor if we zoom into the lower part we can see our flash starting at hex 0 800 the integrated room at hex 2000 and also a big block for peripherals this block is extended on the right and indicates the address ranges for peripherals on different in chip buses such as a HB 1 & 2 & a PB 1 @ you we don't care about these buses specifically we do however care about what's on them a few pages down in the datasheet we can see that on a HP one all the GPIO was a mapped and that for example the port a we saw earlier starts at hex 4002 but what does this actually mean it means that all the registers that we need to configure the input/output port are mapped to that specific address and if we go into the reference manual to the section about gpo's we can see that there's a full section on all the different registers that are available to configure a GPIO the first register is called the GPIO port mode register or GPIO mode R which is mapped at offset zero combining the address for GPIO a we just got from the datasheet with the offset tells us that the GPIO a mode R register will be at address hex 4002 we can also see the bit fields for the register in this case we have 2 bits for each of the 16 pins filling the full 32 bit register the values for these two bits are listed below zero zero to configure the pin as an input 0 1 to configure it as an output 1 0 for alternative function mode which is the mode required to use I squared Z and SPI and so on and 11 for analog mode now let's say we want to configure pin a 0 as an output all we have to do is to set the first bit of the register for example by just writing one dvd address hex 4002 now to enable the output for example to turn on an LED we need to look at the GPIO port output data register or GPIO ODR in this register we have a single bit for each pin we can also see that the offset for the peripheral 6:14 so we can access the output data register for Part A and address four thousand two and fourteen let's say we want to turn on pin zero and one all we have to do is to set bits zero and one in the register for example by writing three to the register address I've set up a new Cleo f4 for sixth eff board with a firmware that simply blinks an LED let's load that firmware into a goodra and see how exactly it works and how we can reverse engineer it I've exported my firmware to a binary file you can find it in the description if you want to follow along I simply drag it into an empty key drop project and you will see that get ready tected the format as raw binary which means that it's not able to detect the information about the files such as the architecture and so on we have to fill these details in ourselves let's start with the language we know this is a cortex-m processor so we can simply search for cortex and get two hits little-endian and big-endian in most cases cortex-m will be little-endian I'll show you some tricks on how to detect that in a future video next we also have to configure some options on the stm32 code normally starts executing from flash and the flash is located at address hex 0 800 so we have to tell get route to load our file to that address let's it okay and double-click the file to start the code browser before we can analyze the file let's finish configuring our memory map if we check the data sheet you will find something interesting address 0 will be alias to flash SRAM or system memory depending on some factors in the wild it will almost always be mapped to flash you can check the STM application notes on the details of this having our flash alias to address zero means that our flash will be in memory twice once at hack zero 800 and once at zero to tell this to get raw we need to create a new memory block let's call it flash mirror leave the start address at 0 and use the same length as our main flash we also need to make sure we set this flash to executable so Hedra knows that it may contain code and we want to initialize the memory block with the contents of our file we also want to create a second memory region for our RAM which starts at hex 2000 this will help us avoid having invalid references feel free to try this on your own machine you will see that setting up the memory map correctly can drastically help you improve the D compilation results once that is all done we can start the analysis one great feature for unstructured firmware is the armed aggressive instruction finder which will allow you to find code even if no direct references to it could be found after analysis is finished let's jump to address 0 and start reversing you can see that gear are marked a couple of things here such as the master stack pointer reset nmi and so on this is called the vector table on boot the CPU loads the stack pointer from here and puts it into the stack pointer register and you can see that the stack pointer indeed points into our RAM region and then it jumps to wherever the reset vector points the nmi hart fold and so on vectors are the addresses of interrupt handlers for example if you do an envelope memory access the cpu will jump into the heart fold handler let's start the same way the CPU would by jumping to the reset vector in most cases the reset vector contains some simple setup code similar to what you would see in the entry part of the C program before then jumping into the actual main function the same is true here we can see some loops that are used to set up some things we don't yet care about and then a function call this will be our main function let's jump into that function the first thing that the eye jumps to you is something red in the listing view a pointer that points to hex 4000 2 and hex 4000 2 and 14 that's where GPIO a is said but let's not get ahead of ourselves and instead giving to the first function which simply calls another function 3 times with different parameters going into that function we see again a strange address that sounds like some peripheral address but going back to the reference manual each time and checking what a specific address is gets all really quickly and can burn a lot of time which is why I built a simple script foggy drug called SVD loader SVD loader uses SVD or system view description files SVD is a standardized format to describe the peripherals of cortex and processors so they contain all the register addresses and so on they are normally used by development and debugging tools but in our case also contain all the information we need to make reverse engineering or fair method from where much easier you can find as we D loader a link in the description and also links to collections of SVD files for all kinds of processors generally I currently have over 800 SVG's on my machine I'm just gonna double click the script and select the SVG file for the stm32f4 for 6 and hit OK after a couple of seconds SVD loader will be finished if we take a look at the memory map now we can see that as we deal other generated a lot of new memory blocks for the different peripherals and in the namespaces there is now a peripheral entry containing all the different peripherals that were loaded and the ones that are actually used in the code are marked in blue going back to our D compilation window we can see that the strange offset turned into our CC dot C R so this function does something with the reset and clock control registers which I used to turn on and off certain prefers and closed let's just call this our CC something and the parent function a CC set up and go back to our suspected main function here we can see that our previously ret reference is now blue and points to peripherals GPIO a if we double click the pointer in the D compilation we can simply convert the undefined data to be a pointer and get Rahul give it a nice name based on what points to you let's also set the type of the pointer to you in 32 as we know it's writing to the 32-bit register we can also see some other constants being used in a loop let's double click it and convert it to an integer and we can see that we just have two loops that count to you 1 million let's start walking through the code we skip the RCC set up and then see that the GPIO a mode our register is being configured as we saw earlier each pin has two bits in this register so let's show it as binary and start counting bits and we can see that this sets pin 5 as an output next we see a right to the GPIO a output data register that's also converted to binary and we see that this turns on pin 5 then we have a white loop that counts to 1 million then a right of 0 to the odr which will turn off all the outputs another weight and we start over again so this is how our LED blinks sweet to make things a bit more challenging I've built a simple bare metal correctly we have the device and the firmware and need to get the device to give us the flag that has been programmed into it we get the output from the device using a serial console and if we start the device we can see that it expects us to do and then press the button if we just press the button it tells us to try again so let's jump into goodra the initial setup is identical to before though this time before hitting analysis we will also load the SVD file we again see some simple setup code in the resultant line and then the call to our main function let's rename it to main to make our code a bit more clear immediately you can see the strings that we saw on the serial console being passed into a function so let's blindly assume this is the serial print function and name it accordingly next let's jump into the first function now this looks familiar just as before this is the RCC setup code so let's name it accordingly and jump back to me in this second function we see a couple of function calls all taking a GPIO a parameter when I'm trying to get an overview over firmware I will just give things high-level names and then investigate later if required so let's call this GPIO something in GPIO is something to and call the function GPIO a is set up in the next function we see a lot of calls with us AR T being given as an argument so this probably sets up the serial console if we convert the parameter passed into the first function to decimal we can see that it's 11 5 200 which is a very common bout rate let's name all of these functions yours add something and the function itself is out set up and jump back to main we can see a reference to GPIO a so let's start by fixing the pointer type of this to you and 32 next we see a pointer that was not correctly detected by Deidra so let's double click it and hit P to set it to a pointer which will show that this accesses GPIO apu PDR register before we figure out what exactly that all means let's clean up the rest of the code first by adjusting some types and also fixing up the loop variables now that we have a nice and clean D compilation we can start figuring out what this does first the GPIO C mode R register is set to 0 which will set all pins on it to input next the pew PDR register is set to 0xaa which will enable so-called pull downs on pin 0 1 2 & 3 this basically just gives the pins a defined state of 0 while nothing is connected I've linked a video describing them in the description next we go into an endless loop which wait until GPIO seep in 13-0 checking the schematic of the development port we can see that this is where the button is connected to so this simply waits for a button press the next line is the if clause that is interesting to us if we manage to make this true we jump out of the endless loop and get the flag we can see that it reads the input register of GPIO SC and then masks the lower four bits these lower four bits are then compared to binary one zero one zero so all we have to do is to set pins one and three too high aka apply some voltage to it and we are good to go to do this I've set up a breadboard and I check the documentation of the dev board to figure out where GPIO is C pins one and three are now all I have to do is to hook this up using some jumper wires and press the button and we have the flag now this is obviously a very simple example that I've used similar methods on a ton of other devices to understand how they work being able to quickly determine which peripherals are used where helps you drastically in identifying functions and so on I hope you like this video and to see you on this channel again soon thank you you
Info
Channel: stacksmashing
Views: 95,095
Rating: undefined out of 5
Keywords: IDA Pro, Hacking, Reverse Engineering, Ghidra, Radare2, Malware, WannaCry, Security, Virus, Ransomware, Reversing, Computersecurity, Computer, Embedded Security, IoT, Bare metal, ARM, Cortex-M
Id: q4CxE5P6RUE
Channel Id: undefined
Length: 14min 39sec (879 seconds)
Published: Thu Feb 27 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.