Hackujeme PY32: pokus dostat firmware z levné LED hračky z AliExpressu

Stručně: Pokus o vyčtení firmwaru z čipu PY32F403C1 v levné LED hračce z AliExpressu skončil neúspěchem – čip má aktivní RDP (Read-Out Protection), která čtení flash přes SWD blokuje. Připojení přes ST-Link a OpenOCD funguje, jádro Cortex-M4 se detekuje i zastaví, ale paměť nevydá ani bajt. Celé ladění přitom řídil AI agent – navrhoval příkazy, diagnostikoval chybové hlášky (záhadu s VTREF napětím i RDP) a vedl strategii, zatímco já jsem zapojoval hardware a reportoval výstupy. Cesta ukázala typické chyby při ladění SWD i to, že s dobrým AI agentem se do reverse engineeringu hardwaru pustí i ne-expert.

Koupil jsem na AliExpressu blikací hračku LED Fluid Simulation – takovou tu desku plnou LED, co simuluje přelévání tekutiny podle náklonu. Po rozebrání mě ale začalo zajímat něco jiného než to, co dělá. Jde to hacknout a vyčíst program a poté ho dekódovat?

Zdroj: aliexpress

Spoiler hned na začátku: firmware jsem nedostal. Tak se o to podělím – ať vám to ušetří pár hodin, až narazíte na to samé. Teda spíš na obdobný hardware.

Uvnitř hračky je PY32F403C1 (datasheet) – levný 32bitový ARM Cortex-M4 od čínské Puyi. Tyhle čipy stojí pakatel.

Reverse engineering pro vlastní studium.

Co jsem měl po ruce

  • Nucleo se zabudovaným ST-Linkem (konkrétně NUCLEO-C031C6)
  • programátor WCH-LinkE
  • multimetr, drátky, trochu trpělivosti
  • Windows

Plán byl jednoduchý: připojit se přes SWD, vyčíst flash, hotovo. A třeba zkusit dekódovat program.

Realita byla o něco pestřejší.

Hledání SWD

Na desce jsem proměřil a našel tři kontakty – SWDIO, SWCLK a reset. V datasheetu jsem si našel, kam jsou připojené a pak jen propípal testpady na desce.

To je základ. Přes SWD (Serial Wire Debug) se k ARM jádru dostanete dvěma vodiči plus zem.

První pokus byl s WCH-LinkE. A tady přišel první kámen úrazu.

WCH-LinkE a věčný boj s ovladači

WCH-LinkE je šikovný a levný programátor, umí ARM i RISC-V. Jenže na Windows ho rozchodit s PyOCD nebo OpenOCD chce mít správný ovladač – a ten Windows samy od sebe nenasadí. Zkoušel jsem Zadig, instaloval WinUSB ovladač, a stejně ho systém pořád neviděl.

Na Linuxu jsem přitom problém neměl (jak jsem programoval mikra CH32). Asi problém mezi židlí a klávesnicí.

Po chvíli jsem to vzdal. Když máte po ruce ST-Link na Nucleu, který má v PyOCD i OpenOCD mnohem lepší podporu.

Na příkaz

pyocd list --probes

Vždy odpověděl

No available debug probes

ST-Link z Nucleo

Integrovaný ST-Link na Nucleu jde použít i na externí čip. Stačí sundat oba jumpery CN2 (tím odpojíte ST-Link od STM32 na samotném Nucleu) a vyvést SWD signály na externí desku.

Jenže STM32CubeProgrammer hlásil „Cannot identify the device“. A tady začala detektivka.

Detektivka jménem „proč to nekomunikuje“

Prošel jsem klasicky:

  • Napájení? Deska měla vlastní LiPol a měnič na 3,3 V, multimetrem jsem ověřil, že na čipu reálně 3,3 V je.
  • Společná zem? Propojená.
  • Jumpery CN2? Sundané.
  • Zapojení SWDIO/SWCLK? Proměřené, sedělo.

Tady stojí za to zmínit chování CubeProgrammeru, které mě chvíli mátlo. Se správně zapojenými datovými (SWDIO) a hodinovými vodiči (SWCLK) hlásil „Cannot identify the device“. Když jsem SWDIO/SWCLK odpojil, hláška se změnila na „No STM32 target found“.

Působilo to nelogicky (byla skoro půlnoc), ale dává to smysl (teď ráno). Bez datového vodiče ST-Link nedostane žádnou odpověď, a tak hlásí, že nenašel cíl. Se správným zapojením naopak komunikace běží – jenže CubeProgrammer hledá konkrétně STMkový čip a PY32 podle ID nepozná.

A to je celé jádro problému: CubeProgrammer je dělaný na STMka, PY32 mu nic neřekne. I když je PY32F403 klon STM32 🫣.

CubeProgrammer tedy nedopadl. Přešel jsem na OpenOCD, který umí pracovat i s generickým Cortex-M targetem bez kontroly, že je to zrovna STMko.

OpenOCD a záhada nulového napětí

Tady jsem narazil na věc, která mě taky vypálila.

OpenOCD hlásil:

Info : Target voltage: 0.000000
Error: target voltage may be too low for reliable debugging

Nula voltů? Vždyť na čipu mám změřené 3,3 V!

Jenže ST-Link to napětí měří na svém pinu VTREF (target reference voltage) – na tom, který má být propojený s napájením cílové desky. ST-Link potřebuje vědět, na jakou napěťovou úroveň má nastavit SWD signály. A když na VTREF nevidí napětí, odmítne komunikovat. I kdyby čip sám byl napájený jak chce.

Řešení: propojit VTREF s 3,3 V. Protože jsem nechtěl míchat dva zdroje napájení, vyřešil jsem to napájením desky přímo z Nucleo (s odpojenou baterií). Najednou:

Info : Target voltage: 3.231373

A je to tady – jádro chyceno

Po doladění konečně:

Info : SWD DPIDR 0x2ba01477
Info : [py32.cpu] Cortex-M4 r0p1 processor detected
Info : [py32.cpu] target has 6 breakpoints, 4 watchpoints
Info : [py32.cpu] Examination succeed
xPSR: 0x61000000 pc: 0x080091d8 msp: 0x20009818

Nádhera. Jádro detekováno, zastaveno, program counter ukazuje do flash, stack pointer do RAM. Všechno sedí. Čip žije, komunikuje, jsem dovnitř.

Teď už jen vyčíst flash:

dump_image firmware.bin 0x08000000 0xC000

A pak to přišlo…

RDP ochrana: zavřená cesta

Error: Failed to read memory at 0x08000004

Jakýkoli pokus o čtení paměti skončil chybou. Jádro se detekuje, dá se zastavit – ale flash nevydá ani bajt.

To je učebnicový příznak aktivní RDP (Read-Out Protection) – čtecí ochrany. Vyzkoušel jsem připojení pod resetem (connect_assert_srst), reset halt, snížení rychlosti až na 15 kHz, čtení po jednotlivých slovech. Jádro se i čistě zastavilo na reset vektoru. A flash pořád mlčela.

Takže je to jasný je: firmware je za čtecí ochranou a ven ho nedostanu.

Čínská hračka za pár korun má zamčenou paměť…

Proč to nejde obejít

RDP je hardwarová bariéra – ochrana. Je přesně od toho, aby zabránila vyčtení flash přes debug rozhraní – to, co jsem chtěl udělat já. A smazání není řešení – zablokoval by se tím (nejspíš) JTAG, takže by se k němu nešlo poté připojit.

Tady je otázka, jaký level RDP PY32F403 používá respektive byl aktivován.

Existují i pokročilejší metody – dekapsulace čipu, glitching, voltage fault injection. Ale to je obří kapitola sama o sobě, vyžaduje speciální vybavení, čas a expertízu. Pro blikající hračku za pár korun to absolutně nedává smysl.

Doplnění: šlo by RDP přece jen obejít?

Po publikaci mi dorazil tip od MarSika (https://witter.cz/@marsik) na zajímavou práci, která ukazuje, že RDP není úplně neprůstřelná zeď.

Dvojice výzkumníků popsala, jak na čipu STM32F4 obešli ochranu RDP1 pomocí takzvaného voltage glitchingu – tedy fault injection útoku.

Princip je prostý na papíře, brutální v praxi: do napájení čipu se v přesně načasovaný okamžik uměle vytvoří krátký napěťový pokles, který procesor donutí přeskočit zrovna tu instrukci, co kontroluje, jestli je čtecí ochrana aktivní. Když se to trefí, bootloader vydá data, která by jinak zamkl.

K tomu použili desku Teensy jako glitcher, vlastní injektážní obvod s MOSFETy a kondenzátory napájený přes pin VCAP, osciloskop na ladění a hlavně hromadu trpělivosti – celý firmware vytáhli po zhruba 22 hodinách a 1024 úspěšných glitchích z víc než 600 tisíc pokusů.

Je to velmi zajímavé čtení, ale zároveň ukázka, že tahle cesta je úplně jiná liga než připojit ST-Link: nevratný zásah do hardwaru, speciální vybavení a dny ladění.

A pozor – tahle práce cílí konkrétně na STM32F4. PY32F403 je sice klon, který se chová podobně, ale není zaručeně identický. Power management, umístění VCAP pinů i chování bootloaderu se můžou lišit, takže celou charakterizaci by bylo nutné dělat pro PY32 od nuly a není jisté, že by stejný postup vůbec zabral.

Pro firmware blikací hračky to rozhodně nestojí za to, ale jako důkaz, že RDP má své meze, je to skvělé. Zdroj: https://jerinsunny.github.io/stm32_vglitch/

Celý postup řídil AI agent

A teď to nejzajímavější, k čemu se musím přiznat. Celé tohle ladění jsem neřešil sám. Strategii vedl AI agent (Claude Opus 4.8 High) – já byl k ruce u hardwaru a oči na obrazovce. Cvičená opička? 😀

Fungovalo to jako dialog. Popsal jsem, co mám a co chci. Agent navrhl postup, já zapojil drátky a spustil příkaz, zkopíroval výstup zpět. Agent ho přečetl, určil další krok. A tak pořád dokola. Jo, cvičená opička. 🫣

Konkrétně mi agent:

  • navrhl celou strategii – od prvního pokusu přes WCH-LinkE až po přechod na OpenOCD,
  • diagnostikoval chybové hlášky a říkal, co znamenají,
  • psal konkrétní příkazy pro OpenOCD a obsah konfiguračního souboru py32.cfg pro generický Cortex-M target,
  • správně určil, že mlčící flash při funkčním připojení k jádru je příznak RDP – a ne chyba zapojení.

Není to o tom, že by AI „hackovala za mě“. Ale držela strukturu, pamatovala si kontext napříč desítkami pokusů a hlavně – každá chybová hláška pro ni byla informace, ne slepá ulička.

A tady je pointa, kterou si z toho odnáším: s dobrým AI agentem se do reverse engineeringu hardwaru může pustit i člověk, který není expert na SWD ani na OpenOCD (já 😀). Agent zná syntaxi příkazů, zná typické chyby, zná paměťovou mapu Cortex-M. Vy dodáte ruce, trpělivost a ochotu zkoušet. Jak z AI dostat takhle použitelné odpovědi – správně zadat hardware, cíl i omezení – rozebírám podrobně v článku Jak programovat Arduino, ESP32 a Raspberry Pi s pomocí AI.

Co jsem si odnesl

Firmware jsem nedostal. Ale to je vlastně dobrá zpráva o jiné věci: i ten nejlevnější čip z nejlevnější hračky může mít zapnutou čtecí ochranu. Počkat , vždyť to není dobrá zpráva! 😩

Puya RDP funguje. Spousta lidí automaticky předpokládá, že čínský no-name hardware je otevřený dokořán – a tady vidíte, že ne vždy. Bohužel.

A hlavně ta cesta. Většina problémů, na které jsem narazil, nemá nic společného s tím konkrétním čipem, ale s obecným laděním SWD:

  • Nelpěte na jednom programátoru. Když WCH-LinkE nejde rozchodit, ST-Link to možná zvládne (a naopak).
  • VTREF musí vidět napětí. Čip může být napájený, a stejně to nepojede, dokud ST-Link nevidí referenční napětí. To jsem nevěděl 😐 nebo AI agent kecal.
  • Pozor na chování CubeProgrammeru. „Cannot identify the device“ u PY32 neznamená nutně špatné zapojení – CubeProgrammer prostě nepozná ne-STM čip podle ID. Nenechte se tím poslat na špatnou stopu.
  • OpenOCD je univerzálnější. Pro cizí Cortex-M je s generickým targetem mnohem flexibilnější než CubeProgrammer.

Takže ano, neúspěch. Ale takový ten poučný. Z pohledu levných mikrokontrolérů a využití AI agenta.

Poznámka k produktu: Zapíná se jediným tlačítkem na desce z boku. Krabička je 3D tištěná.
Vypíná se tak, že jej položíte LEDkama dolů a cca 10 sekund se toho nebudete dotýkat – vypne se to samo.

Odkaz na LED Fluid Simulation

Použité nástroje: OpenOCD (xPack build), ST-Link na NUCLEO-C031C6, Zadig (WinUSB ovladač), multimetr a hodně trpělivosti.

PY32, které lze jednoduše programovat

Pokud vás PY32 zaujal, ale chcete hladší vstup než boj s F403, sáhněte po levných čipech řady PY32F002, PY32F003 nebo PY32F030 – to jsou ty nejrozšířenější kousky za pár korun, na kterých stojí celá komunitní podpora.

Na rozdíl od F403 (Cortex-M4) jde o jednodušší jádra Cortex-M0+, ale právě pro ně existuje hotová „stáhni a piš“ infrastruktura: komunitní Arduino core (py32duino/Arduino-PY32) umožňuje programovat je rovnou z Arduino IDE ve známém stylu, PlatformIO má pro F003/F030 připravené board definice a hotové GCC/CMake šablony (IOsetting/py32f0-template, decaday/py32f0-cmake) zvládnou build během pár minut.

Nahrávat je můžete tím samým ST-Linkem, co už máte rozchozený, nebo levným DAPLinkem. Pro učení a první blikání LED je tahle řada mnohem příjemnější vstup – F403 si necháte na chvíli, až budete mít chuť bastlit toolchain ručně.

Ptáte se

Co je RDP (Read-Out Protection) na čipu PY32?

RDP je hardwarová čtecí ochrana, která brání vyčtení obsahu flash paměti přes debug rozhraní (SWD/JTAG). Když je aktivní, lze se připojit k jádru, ale čtení paměti selhává. Jediný způsob, jak ochranu zrušit, je kompletní smazání flash (mass erase), čímž se ale firmware nenávratně ztratí.

Proč STM32CubeProgrammer hlásí Cannot identify the device u PY32?

CubeProgrammer je určený pro čipy STMicroelectronics a identifikuje cíl podle ID. PY32 od Puyi má jiné ID, takže ho CubeProgrammer nepozná, i když SWD komunikace funguje správně. Pro ne-STM Cortex-M čipy je vhodnější OpenOCD s generickým targetem.

Co znamená Target voltage 0.000000 v OpenOCD?

ST-Link měří referenční napětí na pinu VTREF. Pokud ukáže 0 V, znamená to, že VTREF není propojený s napájením cílové desky. ST-Link pak neví, na jakou úroveň nastavit SWD signály, a odmítne komunikovat – i když je čip sám napájený. Řešením je propojit VTREF s 3,3 V desky.

Jde firmware z čipu s aktivní RDP nějak získat?

Softwarově ne – to je přesně účel RDP. Existují invazivní hardwarové metody jako dekapsulace čipu, glitching nebo voltage fault injection, ale ty vyžadují speciální vybavení, čas a expertízu. Pro běžného bastlíře jsou nedostupné a u levného zařízení nedávají smysl.

Lze použít ST-Link z Nucleo desky na externí čip?

Ano. Stačí sundat oba jumpery CN2, čímž se ST-Link odpojí od STM32 na samotném Nucleu, a vyvést SWD signály (SWDIO, SWCLK, GND, NRST) na externí desku. Důležité je také propojit VTREF s napětím cílové desky.

Může AI agent pomoct s reverse engineeringem hardwaru?

Ano, a výrazně. AI agent zná syntaxi příkazů OpenOCD i PyOCD, typické chyby při ladění SWD a paměťovou mapu Cortex-M, dokáže diagnostikovat chybové hlášky a navrhovat další kroky. Hardware ale sám nezapojí ani nezměří – člověk musí dodat ruce, měření a reportování výstupů. Díky té spolupráci se však do reverse engineeringu může pustit i člověk, který není expert na SWD ani OpenOCD.
Sdílejte článek:
Komentáře:
2 komentářů na sociálních sítích
Koupil jsem na AliExpressu blikací hračku za pár korun a zkusil z ní vytáhnout firmware. Čip PY32F403 - klon STM32. Celý příběh na blogu 👇 chiptron.cz/hackujeme-py... ...více
Číst komentáře
- a -
Přidat svůj názor
Ukaž světu,
že jsi Maker!
Koupit tričko
Kafe pro Chiptrona
Dodej energii dalšímu článku

Související články

CH32V003 návod

Mikrokontroléry CH32V – určitě jste už o nich slyšeli. Prodávají se za naprosto směšnou cenu, ale mají velmi slušnou výbavu a navíc se prodavají v dobře pájitelném pouzdře. Mezi periferiemi najdete mimo klasických GPIO i SPI, ADC, UART, I2C, časovače…

V tomto článku vám popíšu, jak naprogramovat tuto levnou vývojovou desku s mikrokontrolérem STM32F030.

Další články o STM32(F7): Tutorial: STM32F746 (STM32F7 Discovery) – Tlačítkem rozsvítit/zhasnout LED Tutorial: STM32F746 (STM32F7 Discovery) – jak zapnout LED (ovládání GPIO) STM32F746 discovery a IDE AC6 (System Workbench for STM32) Jak začít s moderními mikrokontroléry a proč – STM32…

V návaznosti na mou LinuxDays 2017 přednášku bych zde rád zmínil několik velmi levných desek, které obsahují mikrokontrolér STM32 a stojí doslova pár desetinkorun – do (bez pošty).

STMicroelectronics vydalo novou verzi programátoru a debuggeru STLINK.

Vývojové kity/desky (nebo také development board) jsou velmi populární a každý den nějaký přibude.

Trendy