Jak vytáhnout neznámý program z Arduina UNO a zkusit ho rozluštit

Tvoříte zajímavý projekt? Pochlubte se s ním.
Pravidla fóra
Vkládejte prosím jen HOTOVÉ projekty, které chcete představit ostatním.
Odpovědět
Uživatelský avatar
Diego
Příspěvky: 282
Registrován: 23 črc 2017, 09:43
Kontaktovat uživatele:

Jak vytáhnout neznámý program z Arduina UNO a zkusit ho rozluštit

Příspěvek od Diego » 07 lis 2026, 04:45

Občas se různě po internetu setkávám s dotazy jestli je možné vyčíst neznámý program z Arduina a rozluštit ho a případně nahrát do nového. Většina se shodne že jen kopírování není problém, ale co dekódování? Tam většina řekne že to nejde. Smůla. Tím jsem se ale nenechal odradit a řekl si že to zkusím. Program jsem z Arduina bezproblému přečetl a pak ho hodil do AI a čekal. Výsledek mně příjemně překvapil, téměř 100% úspěch!
Více už u mě na webu ;)
https://www.michaluvbrloh.cz/2026/11/07 ... rozlustit/
Dekodovani_arduina_02.png
https://www.michaluvbrloh.cz - Můj web
https://hackaday.io/projects/hacker/1326779 - Moje některé probíhající i dokončené projekty

Uživatelský avatar
gilhad
Příspěvky: 922
Registrován: 07 bře 2018, 11:22

Re: Jak vytáhnout neznámý program z Arduina UNO a zkusit ho rozluštit

Příspěvek od gilhad » 10 lis 2026, 02:04

V podstatě jsem nedávno dělal něco, co by se luštitelům taky mohlo hodit, tak to tu popíšu aspoň letem světem a když tak se mi tu dá psát do Soukromých Zpráv, nebo na email gilhad zavinac seznam tecka cz kde se rad podelim o další zkušenosti a podrobnosti, nebo něco napíšu na fórum.

Šlo o vývoj programu pro ATmega2560 (z Arduino Mega (Pro)), který je dost podobný ATmega328P (z Arduina Uno), jen má víc RAM i FLASH i pinů a vychytávek na nich (88 GPI/O, 3 nezávislé HW Serial, spoustu časovačů atd). Taky jsem toho nechtěl málo, ovládat VGA monitor, PS/2 klávesnici, SD kartu, I2C, komunikovat a sdílet externí RAMchip s retro počítačem a 6xNeoPixel jen tak pro začátek. Programován trošku v C/C++, hodně v ASM a ve FORTHu (interaktivní zásobníkový jazyk s příkazovou řádkou a možností programování z klávesnice/Seriálu za běhu). Současný stav převážně funkční, částečně ve vývoji. Slov (příkazů) ve FORTHu zatím asi 415.

Kód: Vybrat vše

        |   size |   hexa | build/FORTH_c_003.elf
--------+--------+--------+--------------------------
FLASH: 	|  61462 | 0xF016 | data: 628 + text: 60834
RAM:   	|  19892 | 0x4DB4 | data: 628 + bss: 19264
Kód programu tady https://github.com/githubgilhad/memxFOR ... ORTH_c_003, zdrojáky desky tady https://github.com/githubgilhad/MegaHom ... ad/MHF-002, zdrojáky debuggeru AVRemu tady https://github.com/githubgilhad/AVRemu (můj fork s přidaným ATmega2560). (Forknuto z https://github.com/MuellerA/AVRemu)

ukázka dvou počítačů(jeden připojený, druhý ne), jednoho monitoru a jedné PS/2 klávesnice
Obrázek

A protože se ne vždy vše poskládalo (asi 150 zdrojových souborů bez knihoven) a popřekládalo jak bych si představoval, tak jsem to často různě procházel a zkoumal v přeloženém stavu, pomocí AVRemu který potřebuje jako vstup *.bin soubor (viz Diegův článek) a nejlíp i *.xref, kde jsou uloženy adresy a jejich jména (viz Xref file format), protoze pak to v disasemblovaném kódu ta jména bude používat.

Zádrhely a postup
  • pro věci ve Flash se někde používají adresy bytové (adresují se jednotlivé byte), jinde wordové (adresují je jen celá - 2bytová - slova, protože to je nativní přístup atmegy k flash. 2*Aw=Ab) a různé tooly narůzných místech používají jedny, nebo druhé a člověk si musí u svý toolů ohmatat co a jak. Když mu to někde uzazuje polovinu, nebo dvojnásobek, tak tam je jiný režim, než čekal - nejlépe si nedřív přeložit nějaký Blink a na tom si to vyzkoušet.
  • data sekce .data jsou uložena nejdřív ve flash (za tabulkou přerušení) a po startu se teprve přenesou do RAM. Dále v programu se čtou z RAM.
  • data sekce .bss jsou nulová, nejsou uložena nikde, po startu se prostě celé .bss vynuluje. Dále v programu se čtou z RAM
  • PROGMEM data jsou ve flash a čtou se z flash
  • pro čtení dat z RAM se používají instrukce LDS reg,addr, pro čteni z flash instrukce LPM reg,addr a pro čtení neměnných hodnot (jako třeba adresy, argumenty zadané číslem nebo #define LED 13 a podobně) se použije LDI reg,value
  • normálně zavolám něco jako

    Kód: Vybrat vše

    AVRemu -d -m atmega328p  -x uno_flash.xref uno_flash.bin >uno_flash.dis
    pro vytvoření disasemblovaného souboru, nebo

    Kód: Vybrat vše

    AVRemu -e -m atmega328p -x uno_flash.xref uno_flash.bin
    pro jeho krokování
  • ze souboru uno_flash.dis můžeme vygrepovat instrukce BREQ, BRNE, ... RJMP, JMP a dát je do *.xref jako "j addr J_addr" např. JMP 1234

    Kód: Vybrat vše

    j 0x1234 LJ_0x1234
    a příště už víme, že skáče na Label Jump nevyřešenou na adrese 0x1234
  • obdobně CALL 4321 přvedeme na nevyřešené Call jako

    Kód: Vybrat vše

    c 0x4321 LC_0x4321
  • krokování začíná instrukcí na adrese 0x0000 - tam je obsluha pro RESET, vetšinou instrukce

    Kód: Vybrat vše

    JMP Reset_vector
    nebo tak něco
  • následně se nastaví stavovy registr SREG (pomocí instrukcí OUT) a zásobník a kdesi cosi, vynuluje se .bss oblast a překopírují se .data a případně provedou další inicializace. Pak se zavolá

    Kód: Vybrat vše

    CALL main
    a po návratu se to přes

    Kód: Vybrat vše

    JMP .hidden
    beznadějně zacyklí. Zde získáme adresy main a v něm setup a loop a taky .data a .bss (pokud je ještě nemáme ) a můžeme je zanést do uno_flash.xref, příště se nám již budou zobrazovat.
  • Pokud víme, že to je UNO, můžeme pojmenovat i porty (a některé nám to pojmenuje samo). Taky si můžeme udělat sbírku vzorů knihoven a volání a pak neznámé funkce LC_0x??? pak porovnávat s těmito vzory, pokud začínají stejně, hned máme kandidáta na správné jméno a okolní funkce budeme hledat ve stejné knihovně
  • zanedlouho si zapamatujeme/zapíšeme i obvyklé manévry okolo for-cyklů, if-ů, while-cyklů a přiřazování argumentů a můžeme začít psát provizorní program v C // s komentáři okolo které adresy až kam zpět přeložený úsek sahá
  • Já to dělal kvůli rozsahu (a znalostem) ručně a pomocí skriptů, ale se spoustou toho může AI pomoct a vy nato kdekoli navázat a vnutit tam svou představu a třeba ho zase nechat navázat na svou práci - například místo vygenerovaného

    Kód: Vybrat vše

    for (int i = 0; i < 4; i++) {...};
    tam vnutit svoje

    Kód: Vybrat vše

    #define SEVER 0
    #define VYCHOD 1
    #define JIH 2
    #define ZAPAD 3
     for (int smer = SEVER; smer <= ZAPAD; smer++) {...};
    a mít kód trochu přehlednější a čitelnější
    Nebo si lépe nazvat uživatelské funkce, místo LC_0x4321 třeba použít regulujBazen
  • taky se hodí si někde vedle udělat zachraneny_projekt/ a v něm si čas od času přeložit dosažené a vidět, zda přeložené odpovídá zhruba zachráněnému (tady už naopak *.xref můžeme mít plně kompletní (

    Kód: Vybrat vše

    Elf.rb <elf-file(in)> <bin-file(out)> <xref-file(out)>
    např.

    Kód: Vybrat vše

    Elf.rb zachraneny_projekt.elf zachraneny_projekt.bin zachraneny_projekt.xref
    ) a posuzování funkcí a proměnných nám půjde snadno)
Už je to nějaké dlouhé a je pozdě v noci, tak toho nechám (asi je tam většina důležitého) a pokud by chtěl někdo něco k této cestě, tak se ozvěte :)

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 3 hosti