Sunday, January 6, 2013

Retrieving ST-Link/V2 Firmware from Update Utility

Introduction

The STM32F3DISCOVERY is a small circuit board with a great microcontroller. The ARM Cortex-M4 chip has 256 KB of flash memory, 48 KB of RAM, USB and more. The board has huge amounts of header pins connected to the microcontroller and has a gyroscope, accelerometer and compass on board. For the 11 USD that this board costs, you definitely get a lot of functionality.

ST-Link/V2 chip is next to Crystal

The board also has 2 USB ports, one which is connected directly to the microcontroller, and the other connected to the smaller microcontroller pictured above (STM32F1) and is used for programming and debugging the device. STMicroelectronics calls the programming solution ST-Link/V2. When used with the proper software, it works quite well. However Linux support was initially lacking, but texane and OpenOCD were able to create working drivers. My goal was to dump the firmware.



So why get the firmware?

While ST-Link/V2 has many great features, there are a few features lacking. The STM32F1 microcontroller has a pair of USART lines running to the STM32F3 which are unconnected by default. STMicroelectronics however was kind enough to provide solder bridges on the reverse side of the board (SB13 and SB15 in the picture below) that should be simple for even an amateur to solder.

SB15 and SB13 (on the right) can be soldered to connect USART lines

The problem is that even if these lines are connected, it is not clear whether the firmware will support talking to the STM32F3 over USART or not. So by analyzing the firmware, we can find out if there is a built in ST-Link/V2 command for talking through USART or not. Additionally, it would be nice to modify the firmware so that the board shows up as a USB-to-serial device also, so that no development drivers or software are needed to interact with the STM32F3.

Sniffing USB

So how do you go about getting the firmware for the ST-Link/V2 anyway? The chip is designed to send and receive firmware from the STM32F3, not itself. However, looking at the STMicroelectronics website, you can find a ST-Link/V2 firmware update file. When you extract it there is a readme, a dll and an executable, no firmware file. So my solution for getting the firmware is to sniff USB while the firmware update is taking place. 

There are a number of USB sniffing programs out there, but many are designed specifically for Linux, others are very out of date and designed for Windows XP, and still others are not widely known and may contain malware or might not provide the functionality I need. My solution is to hook the bulk send and receive requests in the firmware update utility.

Detours

While I have written programs that manually hook functions before, that approach is very cumbersome and messy. I decided to look at hooking libraries and came across a free library by Microsoft called Detours. This library was very easy to use and took about 30 lines of coding on my part.

To use the library, you create your own function with the same calling convention and arguments as the one you want to hook and place your code in it. You can optionally call the original function from inside your function. Then in DllMain, you call DetoursAttach() to specify your hook function and the original function and that is basically it!

Detours works good for functions that are part of the Win32 library, however if you are trying to hook a function that is not part of Win32, or one that you do not have a .lib file for, Detours also works great in that situation! For instance I wanted to hook the functions WinUsb_WritePipe() and WinUsb_ReadPipe(), which are part of the Windows Driver Kit, which I did not have. Luckily, the names were exported in the WinUsb.dll file, so I was able to use DetoursFindFunction() to get the address of the function.

To inject the dll file into the executable is also made simple by Detours. One of the example programs in the Detours library is called "withdll" and basically it launches an executable of your choosing with a dll of your choosing. Using this method is wonderful because it makes my hook dll very portable. The next time I want to hook something from the WinUsb library, I can use the exact same dll with the program "withdll".

The firmware

Once the functions were hooked, I had their buffers dumped to a file that I could read in a hex editor. Below is an image of the result. The format of the file is the word "ReadPipe" or "WritePipe", followed by the 1 byte endpoint number, followed by 4 bytes describing the length of the data, then the data itself. In the image below, the last WritePipe contains the start of the firmware. However at first glance the data does not appear as it should.

Dump file from hooked USB calls

Decrypting the firmware

If I tried to run the firmware image captured above though a disassembler, I would get a bunch of garbage. I ran the USB dump file through a program I wrote in order to concatenate all of the firmware together. It was simple to recognize the firmware in the dump file because it was always sent in 1 KB chunks. While the image was begin concatenated together, I ran statistics and found that there was about 100 bytes of each character 0x00 through 0xFF. This typically means that the file is encrypted or compressed, otherwise there would be a higher concentration of values like 0x00 and 0xFF than any other value. 

My first guess was that it was encryption rather than compression because the file length was a multiple of 1 KB exactly. More than likely a compressed file would not be a multiple of 1 KB chunks because the whole point of compression is to make things smaller! 

So then I needed to figure out how the firmware was encrypted and if I could decrypt it. I knew that the firmware was stored in the firmware update utility (because where else would it be?) so I tried looking at the file with a hex editor with no luck. From all of the firmware images I have examined, STMicroelectronics always puts their name in unicode in the firmware file near the end. That did not exist in this executable, so it was likely that it was encrypted within the file.

Disassembling and debugging

Knowing that the firmware image was most likely encrypted, my instinct was to look for the encryption function in the executable file, if it existed at all. So I opened up the executable in IDA Pro and got something  that looked like the image below. All of the function and variable names are my own, but the identification of the start and end of the function were the work of IDA Pro. At the top of the image IDA Pro shows all of the functions which it has identified in blue. The light blue are functions are functions which it has found names for. The dark blue functions are functions IDA Pro does not have names for. These are most likely the meat and potatoes of the program.


After looking at the light blue functions, it looked like the majority were Windows MCF functions, not encryption functions, so they were ignored. I then started at the beginning of the program looking for some dark blue functions that looked like they might be encryption functions. The very first function at address 0x401000 turned out looking very suspicious. It looked suspicious because it had a lot of bit logic in it, particularly exclusive-or operations (in yellow) which seem to be very common in encryption algorithms.

So I opened up the firmware updater in the OllyDbg debugger and placed a break point on 0x401000 and a few other functions. As soon as I tried to send the firmware, the breakpoints were going off left and right. In the function 0x401000, one of the arguments that was passed to it was "I am a key, wawawa". So thank you STMicroelectronics for making it very obvious what the key is and what function uses it.

Identifying the encryption method

While it is not necessary to identify the encryption method to get the unencrypted firmware from memory, it is necessary if I want to upload my own firmware to the ST-Link/V2 chip. I am not an expert in encryption and it would definitely be difficult for me to identify the algorithm just by looking at it, so I had to figure out a way to identify the algorithm in a simpler manner.

Having worked briefly with Blowfish and some open source implementations, I knew that Blowfish used an array of bytes called an S-Box. I have no idea what a S-Box is, but I know the bytes are standardized, not just random digits. I also know that changing them to something else could weaken the algorithm, so the majority of the time they are not changed. So I wondered if whatever this encryption was also had S-Box's, which, again, are a large array of unchanging bytes.

So I looked at the disassembly of the function at 0x401000 (which I named genkey) and noticed a lot of references to an array starting at 0x435000. I looked at the the contents of the array and saw the following bytes: 52 09 6a d5 30 36 a5 38 bf 40 a3 9e 81 f3 d7 fb. When I googled those numbers, I found a Wikipedia entry confirming that this function was used for AES-128 encryption.

Getting the decrypted firmware

To get the decrypted firmware was simple. Once I identified the encryption key, I simply put a breakpoint on that data in order to identify any encryption functions that used the key. I then monitored what data came in and what data went out of the functions which caused to breakpoints to trigger in order to find the function that actually decrypted data. Once I found the decryption function, I simply copied the decrypted data out of memory after the function executed.

Analysis

So I now have the decrypted firmware, but an interesting question is why the firmware was ever decrypted in the first place. It turns out that the firmware uploader stores the firmware in encrypted state, decrypts it and send re-encrypts it with a different key before sending it to the ST-Link/V2 chip. Why they do this, I have no idea. The firmware would be much more secure if it was encrypted with the key that the ST-Link/V2 used in the first place and put that image in the firmware uploader executable.

The re-encryption key

The key which is used to encrypt the firmware again is actually (possibly) dynamic. When the firmware updater first starts, it communicates with the ST-Link/V2 chip and sends the command 0xF3 0x08. The chip then responds back with 20 bytes of data. The first 4 and last 12 bytes are then encrypted with the key "best performance". These 16 encrypted bytes are then used as the encryption key for sending the firmware.

Firmware sending protocol

Before sending the actual firmware image, the firmware updater tells the ST-Link/V2 chip where it wants to upload the data. In the USB long pictured above, this starts at 0x03BB. 0xF3 is a byte that means that this is a Device Firmware Update (DFU) command. 0x01 most likely tells the chip that it will be sending a firmware image next. 0x0002 I believe is a transaction number. 0x752F is sort of a simple checksum, it is the summation of all of the bytes being sent. Finally 0x0400 is the size of the chunk of firmware being sent.

None of these actually tell the ST-Link/V2 the location to upload the firmware. I believe these occur in earlier requests. One request contains the 5 bytes 21 00 40 00 08, with 0x08004000 being the location the firmware is most likely uploaded to. I do not know what the 0x21 means, however this byte is sometimes also 0x41. This will need to by analyzed further. 

It is interesting that data is uploaded to 0x08004000 and each upload is spaced 1 KB after the last until it reaches 0x0800AC00. Then the last 1 KB of the file is uploaded to 0x08003C00. 0x08000000 and up is all flash memory, however it is interesting that the code is not uploaded to the beginning of the flash memory. This could be because code is possibly executing in the earlier portion of the flash and should not be overwritten. Maybe at some point the code will be copied over to the beginning of the flash? Or maybe the beginning of the flash is supposed to be a failsafe in case the firmware arrives corrupted. Or maybe it is just a boot loader for the uploaded flash. It will be interesting to see what the flash memory looks like when I get access.


Upcoming work

Now that I actually have a copy of the firmware, I will need to analyze it. I have taken some initial glances at the firmware, but will need to study it more in depth. I am familiar with x86 assembly, but ARM assembly is completely new to me. Also, I am not quite sure how to work IDA Pro with ARM firmware. It will not automatically identify the beginning and ends of the functions, I must identify individual bytes as code, then IDA Pro will be able to tell me more. So right now I am just making guesses at which parts are code and seeing what IDA Pro does with it. It seems to be working, but since I can't yet understand ARM assembly, I don't know if the data is being interpreted properly or not. If anybody has a more methodical way of marking functions in IDA Pro, I would love to hear it. Particularly if somebody knows how to locate the main routine.

I did look around in the firmware and saw that it contained the same AES-128 S-Box array. It also contained the string "USBC", something that was used in the ST-Link/V1 firmware based on texane's code. Using that, it should be easier to identify the AES-128 functions and other functions in the firmware.

So my goal now is to analyze the firmware and eventually add functionality to it. Eventually I would like to modify it so that it will use the USART on the STM32F3DISCOVERY that is currently unconnected. Or maybe identify code in the firmware that already uses the the USART, and I just need to know the command. The firmware image is 28 KB and the STM32F1 chip which is used for the ST-Link/V2  has a 64 KB flash, so there should be more than enough room to add a few routines.

18 comments:

  1. Nice read, thanks for blogging.

    A thing you could do is write an IDA Python script that searching for function prologues/epilogues and creates functions based on that.

    Rebasing the program is quite important to get a clean disassembly. Good luck!

    ReplyDelete
  2. Firmware for Cortex M3 chips usually start with reset vectors. First word is used to set the stack, next one is the address of the first instruction to be executed, and following this are other addresses for the various interrupts (hard fault, etc.).
    Maybe this isn't included in your part of the firmware, but it likely is. A hint to locate the reset vector is that it starts with a pointer to RAM, then a pointer to near the beginning of the flash (where the reset vector is), and likely many pointers to a B . endless loop instruction (unless the firmware does something fancier with all these interrupts).

    ReplyDelete
  3. The "i am a key, wawawa" and "best performance" keys are discussed in this forum posting: http://forum.easyelectronics.ru/viewtopic.php?f=17&t=6620&start=25

    ReplyDelete
  4. Great work with decryption! There is a chance that you can add some functionality without analyzing all the firmware. Probably you can easily find:
    - USB descriptors (stored as they are visible via lsusb -v)
    - USB hardware related code with reads/writes to proper registers, i.e. endpoint enabling in main program and USB dispatch interrupt

    First you can try to extend the configuration descriptor by adding 2 bulk endpoints (probably changing its memory location and proper address/size in procedure sending it to host). Next you have to add some calls in existing code:
    - in main program - to configure UART, additional endpoints
    - in USB dispatch interrupt - to call your code if interrupt is related to new endpoints
    If you will have working USB-UART implementation using only interrupts and link it to use flash/ram unused by main program, it could probably be mixed without analyzing the rest of main firmware.

    ReplyDelete
  5. This is some seriously good sleuth work. Awesome write up! When I read about this kind of stuff I think, "Man, this guy needs to work for the CIA or something!"

    ReplyDelete
  6. Hi, thanks for this! Please help me understand, are you also trying to use the st-link on the eval board as USB-UART? If yes, this would be great!

    I tried to approach ST with this, but they were silent:
    https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fSTM32Discovery%2fST-Link%20also%20serves%20as%20USB-USART%20when%20not%20debugging&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=1326

    Also, as I can read Russian, guys here discuss not only keys, but they managed to flash chips on VL-Discovery with ST-Link firmware so it works with both STM32 and STM8
    http://forum.easyelectronics.ru/viewtopic.php?f=17&t=6620&sid=e620ffa3653f6f4e44df3ab11556500f&start=50

    ReplyDelete
  7. You can do some soldering and get access to the SL-Link STM32F1 CPU. Then you can adapt Blackmagic and load the bootloader and finally blackmagic. Then you have a debugger, uart access and ITM access (magictps)

    ReplyDelete
  8. Great work! Inspiring!

    Taylor, please take a look at Versaloon firmware, it has support to STM32VLDISCOVER as you can see here:

    http://takenapart.com/?p=82

    and at my blog:
    https://acassis.wordpress.com/2012/02/21/getting-stlink-with-versalon-firmware-working-with-openocd/

    Using it you could include many features to STM32F3DISCOVERY and support to OpenOCD.

    ReplyDelete
    Replies
    1. You use the payload of the board as programmer, but the target here is to reprogram the on-board programmer.

      Delete
  9. Would it be possible to decrypt the lpcxpresso firmware the same way? There is a very powerful debug board on that one. It has minimal flash and the driver uploads the driver when plugged in.

    ReplyDelete
    Replies
    1. To my knowledge, the LPC Link has encrytion irreversible enabled. So without knowledge of the key, no chance...

      Delete
  10. Loving your work, having done some work on STM32's I can probably hazard a guess on a few of the things you're unsure of.
    Firstly the flash pages in the device are 1k long. Unlike eeprom with flash you erase a page at a time(to FF FF......) Then writing flips bits low. Erasing a page takes time, then you write some and then wait for write before continuing.
    Quite an old example that they had was a dfu, device firmware upgrader (I imagine they still have one) which for USB devices is great, its essentially a boot loader loaded where program execution starts and then you can store a USB stack ready to communicate upload some firmware and then execute it. I think one of their examples stored a flag later in flash so that the boot loader could run straight into application if it had a valid flag (I reckon that's the bit at 0803c00 which is probably the last page on the device). They might enumerate the boot loader application and check firmware version before writing new firmware or just restarting the program counter to the actual application.
    Applications are easy to compile further up flash just by changing the linker file and the benefits of field upgradeability without debuggers attached are unarguable!

    ReplyDelete
  11. Taylor,

    do you have a real firmware file of the stlink?

    After achieving access to the ST32F103
    (http://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe)
    and flashing a modified blackmagic debug bootloader
    https://github.com/UweBonnes/blackmagic
    compiled with "make PROBEHOST=stlink" I can now DFU upload a user program (like blackmagic.bin).Programm entry is at 0x8002000, so if the STM stlink firmware has the same entry, I could try to reload the original firmware.


    ReplyDelete
  12. how is it going?
    did you made some progress in getting an application uart running?
    would be nice to hear from you!

    ReplyDelete
    Replies
    1. This project has fallen by the wayside. Currently I am working with Software Defined Radios. I may pick up this project again if I get board though and will post it on the blog if I get some interesting results.

      Delete
  13. Hi Taylor,

    I also wanted to use the serial link (SB13 and SB15) on STM32F3-Discovery to use printf for debug. But it did not work. With the help of STM support I could run the ITM which provides a serial link through the JTAG. See explanations here (SB10 soldered): https://my.st.com/ce634d35

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. The source code is in git:

    https://github.com/texane/stlink/archive/master.zip

    HOWTO
    =====

    First, you have to know there are several boards supported by the software.
    Those boards use a chip to translate from USB to JTAG commands. The chip is
    called stlink and there are 2 versions:
    . STLINKv1, present on STM32VL discovery kits,
    . STLINKv2, present on STM32L discovery and later kits.

    2 different transport layers are used:
    . STLINKv1 uses SCSI passthru commands over USB,
    . STLINKv2 uses raw USB commands.

    Common requirements
    ~~~~~~~~~~~~~~~~~~~

    . libusb-1.0 (You probably already have this, but you'll need the
    development version to compile)
    . pkg-config

    IF YOU HAVE AN STLINKv1
    ~~~~~~~~~~~~~~~~~~~~~~~
    The STLINKv1's SCSI emulation is very broken, so the best thing to do
    is tell your operating system to completely ignore it.

    Options (do one of these before you plug it in)
    *) modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i
    or *)1. add "options usb-storage quirks=483:3744:i" to /etc/modprobe.conf
    *)2. modprobe -r usb-storage && modprobe usb-storage
    or *)1. cp stlink_v1.modprobe.conf /etc/modprobe.d
    *)2. modprobe -r usb-storage && modprobe usb-storage

    IF YOU HAVE AN STLINKv2
    ~~~~~~~~~~~~~~~~~~~~~~~

    You're ready to go :)

    COMPILING
    ~~~~~~~~~
    This project was converted to Autotools by a well meaning individual. The
    following steps will build the project for you.

    $ ./autogen.sh
    $ ./configure
    $ make

    USING THE GDBSERVER
    ~~~~~~~~~~~~~~~~~~~
    To run the gdb server: (you do not need sudo if you have set up
    permissions correctly)

    $ make && [sudo] ./st-util

    There are a few options:

    ./st-util - usage:

    -h, --help Print this help
    -vXX, --verbose=XX Specify a specific verbosity level (0..99)
    -v, --verbose Specify generally verbose logging
    -s X, --stlink_version=X
    Choose what version of stlink to use, (defaults to 2)
    -1, --stlinkv1 Force stlink version 1
    -p 4242, --listen_port=1234
    Set the gdb server listen port. (default port: 4242)
    -m, --multi
    Set gdb server to extended mode.
    st-util will continue listening for connections after disconnect.
    -n, --no-reset
    Do not reset board on connection.

    The STLINKv2 device to use can be specified in the environment
    variable STLINK_DEVICE on the format :.

    Then, in your project directory, someting like this...
    (remember, you need to run an _ARM_ gdb, not an x86 gdb)

    $ arm-none-eabi-gdb fancyblink.elf
    ...
    (gdb) tar extended-remote :4242
    ...
    (gdb) load
    Loading section .text, size 0x458 lma 0x8000000
    Loading section .data, size 0x8 lma 0x8000458
    Start address 0x80001c1, load size 1120
    Transfer rate: 1 KB/sec, 560 bytes/write.
    (gdb)
    ...
    (gdb) continue

    Have fun!

    ReplyDelete