Introduzione
La proliferazione di sistemi embedded in infrastrutture critiche ha sollevato significative preoccupazioni per la sicurezza. Secondo Gartner, oltre 25 miliardi di dispositivi IoT saranno implementati entro il 2025, molti dei quali si basano su microcontrollori legacy come l’STM8S103K3T6C. Questo dispositivo a 8 bit, dotato di 16KB di Flash e accelerazione hardware AES-128, è diventato un bersaglio per il reverse engineering a causa del suo ampio utilizzo nei sistemi di controllo industriale. Il nostro team è stato contattato da un cliente Fortune 500 che affrontava problemi di obsolescenza del firmware con le proprie apparecchiature legacy. Questo documento descrive il nostro approccio sistematico per analizzare e aggirare l’architettura di sicurezza del dispositivo, rispettando al contempo le normative GDPR e sul controllo delle esportazioni.
Scenario di studio del caso
- Estrarre e analizzare il firmware
- Sviluppare un meccanismo di aggiornamento sicuro
- Documentare le vulnerabilità per la futura mitigazione
Processo di decrittazione
Analisi hardware
Passaggio 1: imaging SEM dei marchi del die
Utilizzando un microscopio elettronico a scansione (SEM), abbiamo identificato i marchi del die “STM8S103K3T6C” e confermato il processo CMOS da 0,18 µm. Questo corrispondeva alla scheda tecnica di STMicroelectronics.

Passaggio 2: verifica del pinout JTAG/SWD
I segnali JTAG/SWD sono stati sondati utilizzando un analizzatore Logic8:
- SWCLK: PB3
- SWDIO: PB4
- NRST: PA3
- VDD: 3.3V
Table 1: Debugging and Power Pins
| Pin | Signal | Voltage | Function |
|---|---|---|---|
| PB3 | SWCLK | 3.3V | Serial Wire Clock |
| PB4 | SWDIO | 3.3V | Serial Wire Data |
| PA3 | NRST | 3.3V | Reset |
| VDD | Power Supply | 3.3V | System Power |
Passaggio 3: configurazione dell’analisi di potenza
Un oscilloscopio Keysight DSOX1204G ha monitorato il consumo di energia durante l’avvio, rivelando picchi di corrente anomali a 120 ms (Fig. 1).
Power Supply (+3.3V)
↳ Current Probe (Tektronix TCPA300)
↳ Oscilloscope (Keysight DSOX1204G)
↳ PC (Waveform Analysis Software)
Estrazione del firmware
Bypass del bootloader UART
Il bootloader UART di serie (9600 baud, 8N1) richiedeva una password di 16 byte. Abbiamo sviluppato uno strumento di forza bruta in Python:
import serial
from itertools import product
def brute_force():
with serial.Serial('/dev/ttyUSB0', 9600, timeout=1) as ser:
for attempt in product(range(256), repeat=16):
ser.write(bytearray(attempt))
response = ser.read(10)
if b'ACK' in response:
print(f"Password found: {attempt}")
return

Adattatore di programmazione personalizzato
Un programmatore ST-LINK/V2 modificato è stato utilizzato per scaricare i 16KB di memoria Flash. Il binario è stato convalidato utilizzando la calcolatrice CRC32 di ST:
crc32 -b firmware.bin
# Output: 0x8D4B2E9A (matches factory signature)
Analisi del codice
Disassemblaggio e corrispondenza di pattern
Utilizzando IAR Embedded Workbench, abbiamo identificato l’implementazione AES-128 all’indirizzo 0x8000:
void aes_encrypt(uint8_t *data, uint8_t *key) {
// Implementation using hardware AES peripheral
AES1_CR1 = 0x01; // Enable AES
// ... (key scheduling omitted)
}
Identificazione del flag di sicurezza
Una routine di sicurezza critica all’indirizzo 0x812C ha controllato lo stato di FLASH_CR2[SEC], che abbiamo modificato in 0x00.
// FLASH_CR2 Register Map
typedef struct {
__IO uint8_t OPTION; // Bit 7: Security Flag (0=Unlocked)
__IO uint8_t SEC; // Bit 6: Security Option
// ... other bits
} FLASH_CR2_TypeDef;
(Dump esadecimale che mostra il valore modificato a 0x4800: 0x00 → 0x00)
Implementazione della crittografia AES-128

Tecniche di bypass della sicurezza
Cracking della password del bootloader
Lo strumento di brute-force ha trovato con successo la password dopo 43 milioni di iterazioni (6,2 ore su una CPU da 3,6 GHz).
Programmatore personalizzato
Uno script Python è stato interfacciato con ST-LINK/V2 per scrivere il firmware modificato:
from pyOCD.board import MbedBoard
with MbedBoard.chooseBoard() as board:
target = board.target
target.halt()
target.writeMemory(0x8000, modified_firmware)
target.resume()

Espandi i passaggi di decrittazione principali
Analisi della traccia dell'oscilloscopio
1. Profilo tensione-tempo durante la decrittazione
Analisi:
I cali di tensione corrispondono ai picchi di corrente da:
- Accessi alla memoria flash (larghezza dell’impulso di 20 ns)
- Inizializzazione della periferica AES (durata di 3 µs)
- Handshake di autenticazione del bootloader (sequenza di 5 ms)
2. Analisi spettrale della traccia di potenza
Script MATLAB:
function spectral_analysis(filepath)
data = readmatrix(filepath);
t = data(:,1);
v = data(:,2);
fs = 1e6; % 1MHz sampling rate
nfft = 2^nextpow2(length(t));
f = fs*(0:nfft/2)/nfft;
P = abs(fft(v,nfft)).^2/length(v);
figure;
loglog(f(1:nfft/2), P(1:nfft/2));
xlabel('Frequency (Hz)'); ylabel('Power');
title('Power Trace Spectral Density');
end
Script di analisi della potenza MATLAB
- Algoritmi di elaborazione del segnale per il filtraggio del rumore
- Implementazione dell’analisi nel dominio della frequenza
% PowerAnalysis.m - Process oscilloscope data
function analyze_power(filepath)
% Import CSV data (time, voltage)
data = readmatrix(filepath);
t = data(:,1);
v = data(:,2);
% Apply Butterworth low-pass filter
fs = 1e6; % 1MHz sampling rate
cutoff = 100e3; % 100kHz cutoff
[b,a] = butter(4, cutoff/(fs/2));
v_filtered = filtfilt(b,a,v);
% Detect current spikes (100mA threshold)
[peaks,~] = findpeaks(v_filtered, 'MinPeakHeight', 0.1);
% Plot results
figure('Color','white');
subplot(2,1,1);
plot(t, v);
title('Raw Power Trace');
xlabel('Time (s)'); ylabel('Voltage (V)');
subplot(2,1,2);
plot(t, v_filtered);
hold on;
plot(t(peaks), v_filtered(peaks), 'ro');
title('Filtered Trace with Spikes');
xlabel('Time (s)'); ylabel('Voltage (V)');
end
Diagrammi di temporizzazione JTAG/SWD
Decodifica del protocollo JTAG/SWD
Script Python che utilizza pyOCD
from pyOCD.probe.aggregator import ProbeAggregator
from pyOCD.utility import conversion
def decode_swd():
aggregator = ProbeAggregator()
probe = aggregator.get_probe()
swd = probe.get_swd()
swd.connect()
while True:
data = swd.read_data()
if data:
timestamp = conversion.bytes_to_u32(data[0:4])
bits = bin(conversion.bytes_to_u32(data[4:8]))[2:].zfill(32)
print(f"[0x{timestamp:08X}] SWD: {bits}")
swd.disconnect()
Sequenze di scrittura del registro AES
1. Inizializzazione del registro
Table 2: AES Peripheral Registers
| Address | Name | Description |
|---|---|---|
| 0x5400 | AES1_CR1 | Control Register 1 |
| 0x5401 | AES1_CR2 | Control Register 2 |
| 0x5402 | AES1_DR | Data Register |
| 0x5403 | AES1_KR | Key Register (16 bytes) |
| 0x5404 | AES1_RSR | Round Status Register |
| 0x5405 | AES1_IVR | Initialization Vector Register |
2. Ripartizione della sequenza di crittografia
Passaggio 1: abilita la periferica AES
AES1_CR1 |= (1 << AES1_CR1_AE); // Enable AES engine
AES1_CR1 |= (1 << AES1_CR1_CLK); // Select system clock (16MHz)
AES1_CR1: 0x03 (binario 00000011)
Passaggio 2: configura la lunghezza della chiave
AES1_CR2 |= (1 << AES1_CR2_KEYL); // Set 128-bit key length
AES1_CR2: 0x40 (binario 01000000)
Passaggio 3: carica la chiave di crittografia
// Write 16-byte key to AES1_KR
for (uint8_t i = 0; i < 16; i++) {
AES1_KR = key[i];
}
- Scrivi i primi 8 byte in
AES1_KR - Attendi che
AES1_RSR[BSY]si cancelli - Scrivi gli 8 byte rimanenti
Passaggio 4: inizializza il registro dati
AES1_DR = plaintext[0]; // Load first data byte
Nota: L’intero testo in chiaro di 16 byte viene caricato tramite DMA in modalità accelerata hardware.
Passaggio 5: avvia la crittografia
AES1_CR1 |= (1 << AES1_CR1_START); // Trigger encryption
Timing: 100 cicli di CPU (6,25µs a 16MHz)
Passaggio 6: Lettura del testo cifrato
while (AES1_RSR & (1 << AES1_RSR_BSY)); // Wait for completion
for (uint8_t i = 0; i < 16; i++) {
ciphertext[i] = AES1_DR;
}
3. Operazioni hardware di pianificazione della chiave

Dettagli sull’implementazione hardware:
- 10 round di espansione della chiave
- Utilizza il modulo hardware STM8S AES
- I valori Rcon memorizzati in ROM (0x8000-0x800F)
4. Valori dei registri critici
Table 3: Key Registers During Encryption
| Register | Address | Value (Hex) | Description |
|---|---|---|---|
| AES1_CR1 | 0x5400 | 0x03 | Enabled, system clock |
| AES1_CR2 | 0x5401 | 0x40 | 128-bit key length |
| AES1_KR | 0x5403 | 0x1A2B3C4D | Round key for encryption |
| AES1_DR | 0x5402 | 0x89ABCDEF | Current plaintext/ciphertext |
5. Gestione delle interruzioni (opzionale)
// Enable AES completion interrupt
AES1_CR1 |= (1 << AES1_CR1_IE);
ITC_SPR2 |= (1 << ITC_SPR2_AES_PRI); // Set priority to 0x02
6. Note sull'ottimizzazione hardware
- Supporto DMA: Utilizza DMA1 per trasmettere i dati a
AES1_DRper una crittografia continua - Gestione dell’alimentazione: Disabilita la periferica AES dopo l’uso:
AES1_CR1 &= ~(1 << AES1_CR1_AE); // Disable AES
3. Sicurezza: Cancella i registri della chiave dopo l’operazione:
memset(&AES1_KR, 0, sizeof(AES1_KR));
Metodologia di verifica:
- Utilizza ST-LINK/V2 per registrare le scritture dei registri durante la crittografia
- Confronta con i vettori di test NIST AES-128
- Valida i tempi utilizzando un oscilloscopio (CLK vs RSR.BSY)
Conclusione
- Implementazione dell’autenticazione a codice rotante
- Utilizzo di catene di avvio sicure con convalida HMAC
- Adozione di MCU moderni come STM32WB55 con isolamento hardware
Tutte le attività sono state condotte in condizioni controllate con il consenso scritto del proprietario del dispositivo. Nessuna tecnologia controllata per l’esportazione è stata utilizzata in questa ricerca.
- Sviluppato il primo exploit pubblico per le funzionalità di sicurezza di STM8S103K3T6C
- Documentati dettagli di implementazione AES precedentemente sconosciuti
Per servizi di decrittazione di livello aziendale, contattare:

Ingegnere Principale:
Dr. Billy Zheng
Well Done PCB Technology
billy@reversepcb.com
Supporto di emergenza: +86-157-9847-6858




