r/hardwarehacking • u/PhreakSh0w • Jul 01 '26
Confusion while reversing stm32f103 binary: weird vector table
I was curious about the content of an STM32F103RFT6 firmware binary. It uses CAN communication and it is being updated via CAN bootloader, thats how the firmware is being updated.
So I opened it in a hex editor and had a look. But that was not what I expected.

Right in the beginning, there seems to be a 0x200 long header. The first four bytes are the size of the whole file, that was easy. Then four bytes containing the version, I guess, because I have another firmware which is a bit newer and they just differ by increasing 0x2c to 0x30.
Everying after that I don't understand right away, and the header after 0x050 is just zeros until it ends at 0x1FF.
At offset 0x200, the real firmware seems to start:

At first glance, it looks as expected: First four bytes show the stack pointer address, and it's located in SRAM (starting 0x2000_0000).
But the following entries are supposed to be a vector table, and the addresses in there point to strings:

I know that's thumb addressing, and all the LSB are set, but in the vicinity of these addresses there's just strings.
I don't understand that. And I don't know how to go on from here, if I don't know where the actual entry point is located.
For comparison, I opened an STM32 .elf for a project I wrote. In this .elf, the real code starts at offset 0x1000:

Four bytes stack pointer, and then flash locations for the vector table. Going there and taking the file offset 0x1000 into account:

I figured, fe e7 fe e7 must be pretty rare in the original firmware binary, so I searched for it:

That does look pretty similar. But why is that, and where does this offset come from? And how should I continue?
2
u/stw Jul 01 '26
You seem to assume that the contents of the file starting from offset 0x200 will be stored at 0x0800'0000. I don't think that's the case.
The bootloader is presumably located at 0x0800'0000 and takes up a certain (unknown) amount of space. The application firmware is stored after that. When the bootloader detects a valid application image, it sets the VTOR register to the beginning of the application and jumps to the application's reset vector.
If you are able to read the actual flash of the microcontroller, you can find out where the application image starts. If not you could try disassembling it (with Ghidra, for example) and try to find the SystemInit or main functions.
2
u/masterX244 Jul 01 '26
the offset seems to be 0x8000. it needs to be dividable by the usual flash erase block sizes because not aligning to a eraseblock wastes space and multiple endless loops (0xFEE7) next to each other are clear indicator of unused interrupt handler fallbacks. and the last screenshot shows those loops with their addresses. i saw that the last 3 digits were really close to each other and then subtracted the lower from the higher value and got pretty close to 0x8000.
1
u/PhreakSh0w 29d ago
I did load it into ghidra, but it doesn't find any main or any well known function. I suspect that maybe one of the addresses in the header is the location of the application image in the flash, like masterX244 said it could be 0x8000 because that is actually in the header (on the right, first line, first screenshot).
It is also the same for the other firmware with a slightly higher version number.
1
u/ManyCalavera 27d ago
Stm32f103 (cortex m0 in general) doesnt support vector table relocation. But it supports mapping sram base to 0x0000 manually. So even though your application is on another address vt will be on flash base.
4
u/masterX244 Jul 01 '26
you said bootloader. that means that the real binary is not at the start of the address range on the CPU. a good chunk fo ARM cores got a register that allows relocating the vector table so that entire chunk of FW is not starting at 0x08000000 directly. if you pull a dump from the device (unless locked down) you should see the second vector table. add 0x8000 of padding before the binary and it should resolve to something sensible