Je úžasné sledovat, co dnes AI umožňuje. Za jeden den zvládne skoro kdokoliv množství práce, na které před patnácti lety muselo být celé vývojové oddělení výrobce a trvalo to měsíce. Nemyslím tím, že by AI tu práci udělala za vás – jak uvidíte dál, spoustu času jsem strávil tím, že jsem jí vyvracel nesmysly. Ale posun v tom, co je pro jednoho člověka o víkendu dosažitelné, je obrovský.
Zkoušel jsem si to na krabičce, která mi z té doby zbyla: AverMedia Game Capture HD II, modelové označení C285. Je to slušný kus hardwaru – uvnitř sedí SoC Texas Instruments DM368 na 432 MHz, 256 MB paměti a má hardwarový H.264 enkodér.
V době vzniku uměl věci, které dávaly smysl: nahrávat na disk, streamovat rovnou na YouTube, ovládat se z mobilu. Jenže to YouTube API dávno neexistuje, mobilní aplikace zmizely z obchodů a já sám jsem k němu už dávno ztratil dálkové ovládání. Podpora skončila. Zůstal funkční hardware, ke kterému nevede žádná použitelná cesta.
Oprášil jsem ho z konkrétního důvodu. Pracuji na herním enginu picogame pro mikrokontroléry a potřeboval jsem nahrávat jejich video výstup – DVI 640×480. Doufal jsem, že aspoň na takhle jednoduchou věc box poslouží, protože záznam na disk jde spustit hardwarovým tlačítkem na krabičce.
Neposloužil 😥. Na vstupu podporoval jen velmi omezenou sadu rozlišení a VGA 640×480 mezi nimi nebylo. Krabička signál prostě nepřijala.
To byla ta chvíle, kdy mě napadlo, že by stálo za to podívat se dovnitř. A hned na začátku prozradím pointu, protože dobře ilustruje, o čem celý tenhle text je: to omezení nebylo v hardwaru. V ovladači jádra je tabulka podporovaných vstupních režimů a položka pro 640×480 progresivní tam celou dobu byla. Jen se k ní přes vendorskou aplikaci nedalo dostat.
Co je uvnitř
Zajímalo mě, proč je 640×480 hlášeno jako špatné rozlišení – jestli je to omezení hardwaru, nebo softwaru. Rozmontoval jsem tedy krabičku a podíval se, co ji vlastně pohání.
| osazený díl | |
|---|---|
| SoC | Texas Instruments DM368ZCE, jádro ARM926EJ-S @ 432 MHz |
| integrovaný HDVICP – hardwarový koprocesor pro H.264 | |
| ISIF + IPIPE (previewer a resizer) pro zpracování obrazu | |
| Řídicí MCU | Nuvoton NUC100 (Cortex-M0) – I²C master celé desky |
| HDMI vstup | ITE IT6604E – HDMI/DVI přijímač |
| HDMI výstup | ITE IT6613E – HDMI vysílač |
| Analogový vstup | TI TVP7002 – komponentní/VGA video dekodér |
| RAM | 2× Nanya DDR2, dohromady 256 MB |
| NAND | Winbond W29N01HVS1NA – 1 Gbit SLC, tedy 128 MB |
| Ethernet PHY | Realtek RTL8201EL – 100Mbit |
| USB ↔ SATA | Genesys Logic GL830 |
| Sběrnicové budiče | několik 74LVC244A mezi ITE čipy a SoC |
| RTC | zálohovaný CR2032 |
| EEPROM | 24C256 (32 kB) na I²C, drží nastavení a MAC adresu |
| Zvuk | dva kodeky TI TLV320AIC3x |
Jedna věc byla patrná až po rozebrání: mezi ITE čipy a SoC sedí několik budičů 74LVC244A. To je fyzický důkaz toho, jak je vedená obrazová sběrnice, a později to dostalo smysl: přijímač a vysílač si data předávají po společné šestnáctibitové sběrnici a SoC z ní jen odečítá. Proto může na monitoru zároveň běžet obraz i bez aktivního zachytávání přes SoC.
V NAND paměti jsou dvě kompletní sady firmwaru:
mtd0 bootloader 0x00000000–0x003c0000 3,75 MB
mtd1 params 0x003c0000–0x00400000 256 kB (prostředí U-Bootu)
mtd2 kernel_fw1 0x00400000–0x00800000 4 MB
mtd3 filesystem_fw1 0x00800000–0x04000000 56 MB
mtd4 kernel_fw2 0x04000000–0x04400000 4 MB
mtd5 filesystem_fw2 0x04400000–0x07c00000 56 MB
mtd6 programer_space 0x07c00000–0x08000000 4 MB (zapisovatelný jffs2)
Dvě banky, mezi kterými se přepíná jednou proměnnou v zavaděči. To se později ukázalo jako naprosto zásadní – jedna banka zůstala celou dobu jako záchranná síť, do které se dá vrátit, zatímco jsem tu druhou opakovaně přepisoval a několikrát rozbil.


Hardware to umí, tak proč ne?
Podle datasheetů nic nenasvědčovalo tomu, že by ty čipy měly mít s 640×480 problém. IT6604 je běžný HDMI/DVI přijímač, který VGA režimy zvládá bez potíží. IPIPE v DM368 pracuje se šířkami až 2176 pixelů. Rozlišení 640×480 je oproti 1080p, které box umí, výrazně menší zátěž.
Usoudil jsem tedy, že omezení bude v softwaru – a že na téhle krabičce nejspíš poběží nějaký Linux. Průzkum internetu to potvrdil velmi rychle, a navíc mnohem líp, než jsem doufal.
Texas Instruments pro tuhle řadu dodával DVSDK – Digital Video Software Development Kit. Není to jen ovladač, je to kompletní stavebnice pro přesně tenhle typ zařízení:
- codecs-dm365 – samotný H.264 enkodér běžící na HDVICP
- linuxutils – jaderné moduly
cmemk(souvislá paměť pro DMA),edmak,irqk,dm365mmap - a hlavně dvsdk-demos, mezi nimiž je demo jménem
encode
To poslední je pointa. Vendorská aplikace v téhle krabičce se jmenuje encode a startuje ji init skript /etc/init.d/encode-demo. Jinými slovy: komerční produkt, který jsem si kdysi koupil, je potomek demo aplikace z SDK od Texas Instruments – a to jméno v něm zůstalo dodnes.
Na boxu je celý ten SDK pořád k dispozici, v /opt/dvsdk/dm368/, včetně skriptu loadmodules_hd.sh, který zavádí ty jaderné moduly. Verze odpovídají době vzniku: jádro Linux 2.6.32.17-davinci1 přeložené v prosinci 2017 kompilátorem gcc 4.3.3, zavaděč U-Boot 2009.03 z ledna 2014.
Tím se úloha proměnila. Nešlo o to, obejít hardwarové omezení – šlo o to dostat se k vrstvě, kterou vendorská aplikace zakrývala.
Mobilní aplikace, která už neexistuje
Než jsem se pustil dovnitř, zkusil jsem to nejjednodušší: co box vlastně nabízí po síti. Odpovídal na jediném portu, na kterém běželo API pro mobilní aplikaci. Ta ale zmizela z obchodů, takže mi to samo o sobě nebylo k ničemu.
Podařilo se mi dohledat starší APK a dekompilovat ho. Z toho vyplynul celý protokol. A byl jednoduchý – nešifrované HTTP na portu 24170. Žádná autentizace, žádné TLS, ani jiné složitosti. Komunikace má i druhý směr box aplikaci posílá události na port TCP 1516.
Celkem se mi podařilo zmapovat 117 koncových bodů – párování s PIN kódem, přepínání vstupu, spouštění a zastavování záznamu, emulaci tlačítek dálkového ovládání.
Tady poprvé nastoupila AI. Z těch nálezů jsem nechal napsat CLI nástroj a malou webovou aplikaci pro ovládání boxu. Povedlo se to prakticky napoprvé a plně to nahradilo ztracené dálkové ovládání i mrtvou mobilní aplikaci. Bez jediného zásahu do firmwaru jsem měl krabičku znovu ovladatelnou.
Sériová konzole: první vstup dovnitř
Ovládání jsem měl zpátky, ale původní problém zůstal. Doufal jsem, že někde v menu – které jsem teď konečně mohl procházet – najdu nastavení, které to rozlišení povolí. Nenašel. Nic takového tam prostě není.
Byl čas pokročit o kus dál. Na desce jsem našel pravděpodobný UART port. Opatrně jsem prozkoumal, co je co, připojil převodník – a za chvíli se na obrazovce objevil U-Boot (na 115200 8N1 což odpovídalo i datasheetu).
U-Boot 2009.03-dirty (Jan 14 2014 - 09:44:01)
I2C: ready
DRAM: 256 MB
NAND: 128 MiB
In: serial
Out: serial
Err: serial
Po něm nastartoval Linux a nakonec vendorská aplikace. A tady přišel první zádrhel: aplikace si převzala vstupy, takže sériová konzole byla po naskočení appky k ničemu.
Bootování se mi však podařilo přerušit pomocí CTRL+C a naskočil login:
| _ |___ ___ ___ ___ | _ |___ ___ |_|___ ___| |_
| | _| .'| . | . | | __| _| . | | | -_| _| _|
|__|__|_| |__,|_ |___| |__| |_| |___|_| |___|___|_|
|___| |___|
Arago Project http://arago-project.org dm368-evm
Arago 2011.02 dm368-evm
Arago je distribuce, kterou pro tuhle řadu dodával přímo TI – postavená na OpenEmbedded. A všimněte si toho hostname: dm368-evm, jméno vývojového kitu. Opět referenční návrh tak, jak přišel od výrobce čipu.
Jenže ani tenhle login mi nebyl k ničemu – vendorská aplikace naskočila souběžně a na vstupy zase nereagoval. Konzole byla obsazená.
Jedna věc mi ale to CTRL+C prozradila, a byla důležitější než samotný login: fungovalo. Box tedy moje znaky opravdu dostával – sériová linka byla obousměrně funkční. Tenhle poznatek si zapamatujte – za chvíli z něj bude záhada.
Zbývala totiž cesta o patro níž: dostat se do U-Bootu ještě předtím, než se Linux vůbec spustí. Zavaděč přitom sám nabízel přesně to, co jsem potřeboval:
Hit any key to stop autoboot: 1
Stiskni libovolnou klávesu. Odpočet jedna vteřina.
Na klávesy nereagoval.
A právě proto to byl skutečný hlavolam, a ne banální chyba v zapojení, protože serial prokazatelně fungoval. Znaky odcházely. Zavaděč je jen z nějakého důvodu zahazoval.
Firmware ke stažení je zašifrovaný
Než jsem se pustil do lámání konzole, zkusil jsem samozřejmě to pohodlnější: stáhnout starší firmware, které výrobce kdysi vydával, a rozebrat je v klidu na stole. Nepomohly.
Soubory měly čitelnou hlavičku:
AVT-CEDxc285WW001.002.0990.0.20.0.32 201710121914 723c8a4f5cacd1cc5a3fabb...
#k_s
2364296
#f_m
16
#f_s
3145752
3145752
...
Jenže všechno za tou hlavičkou je zašifrované (entropie 8 bitu na bajt = prakticky náhodná data).
Tím se cíl vyjasnil: bylo nutné se dostat k rozšifrovanému stavu v běžícím systému. Dumpovat flash paměť přímo z čipu jsem vyloučil – vybavení na to po ruce nemám (je to paralelní flash, která by se musela odpájet, ne jednoduchá sériová SPI).
Šum na sériové lince
Zbývala tedy ta konzole a U-Boot, který na klávesy nereagoval. Jedním z triků, které jsem zkusil, bylo poslat na sériový vstup šum – místo stisků konkrétních kláves prostě proud náhodných dat.
A ono to zabralo 🤯. Na obrazovce vyskočilo:
DM365 EVM >
Prompt zavaděče!
Co to odemklo:
Prodloužení odpočtu. Nastavil jsem bootdelay z jedné vteřiny na pět, abych měl příště víc času na stisk klávesy. Spoiler: nepomohlo to, a proč, to je jedna z nejlepších částí celého příběhu – vrátíme se k ní.
Prompt zavaděče sám o sobě ale ještě není výhra. Za zmínku stojí, co ten U-Boot umí a co ne: v tabulce příkazů je nand, setenv, saveenv, bootm, dhcp, tftpboot – ale žádné usb, fatload ani mmc. Z U-Bootu samotného tedy nešlo nic uložit na flash disk; ten uměl leda sáhnout po síti. Skutečná cena promptu byla jinde – v tom, že mi dovolil přepsat, co se řekne jádru při startu. A přesně tam vedla cesta dál.
Ze zavaděče do shellu: přepsat bootargs
Původní boot parametry vypadaly takhle:
bootargs=mem=97M console=ttyS0,115200n8 quiet root=/dev/mtdblock5 rootfstype=cramfs ro
video=davincifb:vid0=OFF:vid1=OFF:osd0=1280x720x16,5400K
dm365_imp.oper_mode=0 davinci_capture.device_type=4
davinci_enc_mngr.ch0_output=LCD davinci_enc_mngr.ch0_mode=720P-60
bootcmd=nboot 0x80700000 0 0x4000000;bootm
Ten řádek toho prozradil opravdu hodně:
- systém běží z
mtdblock5– tedy z druhé banky,filesystem_fw2, - kořenový systém je cramfs, připojený read-only (takže nic nepůjde jen tak přepsat),
- jádru zbývá 97 MB z 256 – zbytek si drží kodek,
- video výstup je natvrdo 720p60,
- a jsou tu jména ovladačů i s parametry:
dm365_imp.oper_mode,davinci_capture.device_type,davinci_enc_mngr.ch0_output. Každý z nich se mi později hodil.
Stačilo tedy na konec připsat init=/bin/sh. Vendorská aplikace se spouští až z init skriptů – když se init nikdy nespustí, aplikace nenaběhne, nesebere mi sériovou konzoli a poprvé mám skutečný root shell na běžícím, rozšifrovaném systému.
Odsud už to byla rutina: připojit USB flash disk a vysypat NAND oddíl po oddílu přes dd z /dev/mtd*. Zavaděč, obě jádra, oba souborové systémy.
Poklady v rozšifrovaném systému
Teď jsem měl na disku celý souborový systém a mohl jsem se v něm hrabat v klidu. A vyplatilo se to hned třikrát.
Klíč k firmwaru
Vzpomínáte na ty stažené .bin, které měly entropii přesně 8,0 a nedaly se rozbalit? Odpověď, jak je rozšifrovat, ležela v hlavní aplikaci encode, kde je tenhle příkaz:
openssl enc -d -des3 -in /tmp/file.en -out /tmp/file.de -pass pass:Av3rMed1a
To je 3DES s heslem Av3rMed1a – možná v tom hesle něco poznáte 🙂. Teď stačí jen jeden příkaz:
openssl enc -d -des3 -md md5 -pass pass:Av3rMed1a -in blob.en -out blob.de
Šifra je přitom symetrická a ta čitelná hlavička je kompletní recept, jak balík poskládat zpátky. Klíč by tak mohl posloužit i k zabalení vlastního „oficiálního fw“, který by přijal updater v aplikaci. Nakonec jsem to ale vůbec nepotřeboval: když mám root shell, zapíšu upravený systém rovnou do neaktivní banky NAND a celou aktualizační systém obejdu.
Root heslo: DES crypt a půl hodiny s hashcat
Z rozšifrovaného systému jsem vytáhl /etc/passwd. Řádek pro roota:
root:xvaWxZvodd.wU:0:0:root:/home/root:/bin/sh
Jedná se o prehistorický DES crypt(3) hash. Po zhruba půl hodině ho hashcat vydal. Samotné heslo by mi bez shellu bylo k ničemu – box žádnou síťovou přihlašovací službu standardně nespouštěl. A přesně o to šlo dál.
Telnet jednou proměnnou v prostředí zavaděče
telnetd je na boxu přítomný (busybox), ale ve výchozím stavu se nespouští. V init skriptu encode-demo je ale tohle:
var_logswitch=`fw_printenv log_switch | cut -c 12`
# enable telnet if debug log is turned on
if [ "$var_logswitch" == "1" ]; then
telnetd
fi
Vzdálený přístup visí na jedné proměnné v U-Boot – log_switch. Původně sloužila k zapnutí ladicího logu, ale jako vedlejší efekt nastartuje i telnet. A protože prostředí zavaděče je perzistentní (žije v oddílu mtd1), stačí ho jednou nastavit z shellu příkazem fw_setenv a telnet naskočí při každém dalším startu, sám od sebe.
Hotovo. Root heslo z prolomeného hashe + telnet, který se pouští automaticky, = plný, perzistentní root přístup k boxu po síti, bez sériového kabelu, bez zásahů do bootargs při každém startu. Od téhle chvíle byla krabička normální malý Linux server, na který se dá kdykoliv připojit a pracovat na něm.
Vlastní firmware – a tady začíná pracovat AI
Do téhle chvíle šlo o klasický reverse engineering: kabel, konzole, dumpy, prolomený hash. Odsud dál se povaha práce změnila. Měl jsem rozšifrovaný systém a root přístup po síti – a nastal čas napsat vlastní software a dostat ho do krabičky. Tuhle část už prakticky celou odvedla AI. Vlastní záznamovou aplikaci, HTTP i RTSP server, webové rozhraní, build i flashovací postup (s trochou popostrčení správným směrem). Nebylo to bez úskalí, ale rozsah toho, co vzniklo prakticky za večer, by jinak znamenal týdny práce.
Proč se to nedá jen tak přepsat
Souborový systém je cramfs připojený read-only – to jsme věděli už z bootargs. Nejde do něj tedy nic připsat za běhu; jakákoliv změna znamená postavit celý obraz znovu. AI z toho udělala reprodukovatelný build: vyjmenuje zařízení v /dev z originálního cramfs, postaví strom pod fakeroot a slepí ho zpět pomocí mkfs.cramfs. Výsledek je obraz, který jádro připojí úplně stejně jako ten vendorský – jen je v něm místo aplikace encode ta moje.
Dvě banky jako záchranná síť
Tady se ta dvoubanková konstrukce z první kapitoly opravdu vyplatila. Vlastní firmware jsem vždycky nahrával do neaktivní banky, zatímco běžící systém jel z té druhé. Když nový obraz selhal – a několikrát selhal – stará banka pořád nastartovala. To je při experimentování k nezaplacení.
Jenže flashování trvalo čtvrt hodiny
Háček byl v tom, že banku, ze které systém běží, nejde přepsat za chodu – čte se z ní průběžně, takže smazat ji zpod běžícího systému znamená ho rozbít. Muselo se proto nabootovat do druhé, vendorské banky, teprve odtud tu naši přepsat, a nabootovat zpět. Dva rebooty, mazání, flashování a pobyt ve vendorském firmwaru – dohromady zhruba čtvrt hodiny.
Pro jednu velkou finální verzi je to v pořádku. Ale při ladění, kdy člověk mění jeden řádek a chce vidět výsledek, je patnáct minut na každou iteraci zabiják. Muselo to jít líp.
Firmware z flashdisku
Řešení bylo elegantní a využilo to, co v krabičce stejně bylo – USB disk. Spouštěč vlastního firmwaru při každém (re)startu aplikace nejdřív mrkne na připojený flashdisk. Když na něm najde binárku avmbox_h264, spustí přednostně ji místo té ve flash:
Tím se z patnácti minut stalo pár vteřin: wget binárky na disk, zavolat /api/restart – a běží nová verze. Flashování zůstalo jen pro to, aby se do trvalého obrazu zapekla finální ověřená verze.
for d in /tmp/media/*; do
if [ -x "$d/avmbox_h264" ]; then OVR="$d/avmbox_h264"; break; fi
done
Proč box odmítal 640×480?
Teď, když vlastní aplikace běžela, jsem se konečně mohl vrátit k původní otázce: proč vlastně box to rozlišení odmítal? Opravdu to nebylo o hardwaru. Žádná složka řetězce s 640×480 problém nemá: přijímač IT6604 se na něj zamkne, ovladač davinci_capture ho zná, a kódování obstarává FFmpeg nad hardwarovým enkodérem, pro který je to úplná banalita.
Zádrhel byl o patro výš – v politice vendorské aplikace. encode porovnává detekovaný režim s ručně udržovaným seznamem povolených standardů, a když v něm režim není, nastavení selže přesně tou hláškou o „nepodporovaném rozlišení“. Nešlo tedy o žádnou technickou hranici, jen o whitelist, do kterého VGA nikdo nedopsal (a UI bylo stejně napevno postavené na 720p).
Dalo se to spravit záplatou té binárky, ale pořád by zůstala zavřená aplikace mluvící mrtvým protokolem. Čistší cesta byla naše vlastní aplikace: mluví přímo s V4L2 a vezme prostě tu geometrii, na kterou se driver zamkl – 640×480 tak „funguje samo“, a stejným krokem přibyl streaming, webové rozhraní i volba kodeku.
Bitva o barvy: když se hádá ve špatném modulu
Zachytávání se rozjelo, ale obraz byl zelený a posunutý dolů. A tady se ukázalo, jak vypadá spolupráce s AI ve své lepší i horší podobě zároveň 😁.
Nejdřív ta horší. AI vygenerovala jednu teorii za druhou – špatné pořadí bajtů, přehození barevných složek, konverze barev v čipu – a každou zkoušela naslepo. Několik kol dokola, bez posunu. Hrabala se přitom v tom modulu obrazové cesty, který vypadal jako viník. Nebyl.
Zlom přišel, když jsem trval na měření místo dohadů. AI si přečetla surové snímky přímo z paměti a ukázalo se, že barvy jsou na sběrnici celou dobu správně – chyba nebyla před čipem, ale kus dál v obrazové cestě, jinde, než se hledalo. Odtud to byla otázka dvou drobných vysvětlení: jedno řeklo čipu, ať příchozí data bere jako barvu (bez něj šlo všechno do zelena), druhé posunulo, kde v obraze začíná aktivní plocha (to srovnalo ten svislý posun). Dva bity a obraz seděl.
AI umí vygenerovat nekonečně věrohodně znějících hypotéz a poslušně je zkoušet – ale bez měření se točí v kruhu. Ta produktivní část nezačala lepší teorií, ale tím, že jsem ji donutil přestat hádat a začít měřit.
Výkon: od 3,6 k 60 snímkům za vteřinu
První verze zachytávání běžela na 3,6 snímku za vteřinu. To je slideshow, ne záznam hry. Cesta k použitelné rychlosti vedla přes tři úzká hrdla, a všechna byla o zbytečné práci s pamětí.
Nejdřív se u každého snímku softwarově kódoval JPEG – 270 ms a procesor na 99 %, i když se nikdo nedíval. Nechal jsem ho běžet jen tehdy, když je náhled opravdu potřeba. Pak vyšlo najevo, že snímky sedí v necachované paměti, kterou procesor čte zoufale pomalu (~21 MB/s); přesun na hardwarový DMA řadič zkrátil tentýž přenos na 3,2 ms a poslal FPS přes třicet. Poslední hrdlo byla konverze pixelů do formátu, který chce hardwarový enkodér – 10,7 ms na snímek, skoro tolik co celé kódování.
A tady přišel nejhezčí moment celého ladění: zachytávací hardware ten formát umí dodat rovnou. Jediné, co tomu bránilo, byl překlep v parsování parametrů – přepínač -E omylem vypínal -N. Tedy chyba v kódu, který AI sama napsala a pak kolem ní pracně optimalizovala konverzi, kterou vůbec nemusela dělat 🤦. Po opravě klesla konverze na nulu a snímková frekvence byla konečně tam, kde ji chci mít.
Webové rozhraní
Řetězec zachytávání teď jel rychle a se správným obrazem. Zbývalo to celé udělat ovladatelné. Vendorská aplikace se řídila přes dálkové ovládání a mobil, obojí pryč. Nechal jsem tedy napsat webové UI s použitím Bulma a Alpine.js – oba stahované z CDN (tuto kombinaci rád používám s mikrokontroléry).

Rozhraní má čtyři stránky: živý náhled, záznamy, nastavení a diagnostiku. Skoro každé rozhodnutí v tom UI plyne z jednoho faktu: na takhle pomalém SoC každý dotaz něco stojí – jeden poll stavu znamená několik I²C čtení přes MCU a jeden zápis konfigurace smazání bloku v jffs2. Proto se o stav stará jediný časovač (a na neaktivním tabu se zastaví) a změny nastavení se posílají po skupinách.
Záhada klávesy „U“
Teď splatím dluh z úvodu. Vzpomínáte na ten odpočet, který na klávesy nereagoval?
Hit any key to stop autoboot: 5
Jenže žádná „libovolná“ nefungovala i když serial rozhodně fungoval. Tady jsem měl od začátku podezření, že to nebude libovolná klávesa, ale nějaká konkrétní, a opakovaně jsem žádal, ať se prověří samotný U-Boot. AI stále tvrdila, že to podrobně prozkoumala a že opravdu stačí cokokoliv. Nestačilo.
Nechal jsem si tedy najít kód konkrétní kód v disassemly a na první pohled to bylo hned jasné a i AI svou chybu okamžitě pochopila:
333b40: bl 0x330c50 ; getc() - přečti stisknutý znak
333b44: and r3, r0, #255 ; r3 = znak & 0xFF
333b48: cmp r3, #85 ; ← porovnání s 0x55 = 'U'
333b54: bne 0x333b68 ; není 'U'? → ignoruj a odpočítávej dál
333b58: mov r5, #1 ; je 'U'? → přeruš autoboot
333b5c: mov r4, #0 ; a skoč do shellu
To cmp r3, #85 je celé jádro věci. Číslo 85 je 0x55, a 0x55 je v ASCII velké U. Nečeká se na libovolnou klávesu ale právě na tento znak. Jen tam někdo nechal původní hlášku z defaultního chování. AI i přes několik žádostí o hloubkové prověření skončila na tom, že našla tuto hlášku a tak to musí být pravda a dále to neřešila…
Na téhle epizodě je zajímavé, jak snadné to nakonec bylo – a jak dlouho to trvalo. Ta instrukce nebyla nikde schovaná. Je to jedno porovnání v přehledně pojmenované funkci abortboot, na kterou se dá v disassembly podívat během pár minut…
Kde měla AI problémy
Slíbil jsem v úvodu, že bude jasné i to, kde AI klopýtla — a spoustu času jsem strávil vyvracením nesmyslů. Opakovaly se ve vzorcích:
- Věří vypsané hlášce víc než kódu. Ta proradná klávesa
U…; jindy si naivním scannerem „napočítala“ klíčové snímky, které v souboru vůbec nebyly. - Z jedné chyby postaví princip. Opakovaně tvrdila, že současný passthrough a záznam „nejde“ – přitom to byl vedlejší efekt jejího vlastního příkazu, ne vlastnost zařízení. Stihla to zabudovat i do API a komentářů jako fakt.
- Vymyslí si důkaz a uvěří mu. Domněnku, že vendorská aplikace přepisuje bootargs, „doložila“ výpisem, který si předtím sama vyrobila – a zapsala do trvalé paměti jako fakt.
- Ublíží tomu, na čem pracuje. Několik pádů boxu si způsobila sama – slepým sondováním přes MCU, zaplavením systému stovkami shellů (dvakrát došla paměť), nebo
kill -9, co shodil síť.
Na druhou stranu tytéž schopnosti odvedly obrovské množství správné, nudné práce a chybu skoro vždy dohledaly, jakmile jsem ji pojmenoval a nasměroval práci na správné místo.
Co box umí dnes
Z blackboxu, přivázaného ke službám, které dnes už neexistují, je otevřený síťový
capture box – a umí toho víc než v den, kdy jsem si ho koupil. Část práce bylo původní
funkce získat zpět na vlastním softwaru. Hlavně souběžný obraz na monitoru i záznam přes
hardwarovou cestu přijímač → vysílač (to uměl i originál, jen mi dalo zabrat rozchodit to na
vlastním firmwaru). Ale toho úplně nového je tam víc:
- Živý RTSP stream po síti – pro mě ta zásadní funkce. Originál uměl jen push na YouTube. Teď mám univerzální H.264 stream po síti do OBS, VLC nebo ffmpeg (a MJPEG rovnou do prohlížeče).
- Libovolné rozlišení – od 640×480, které vendor zakazoval a kvůli kterému to celé začalo,
až po 1080p. To druhé si vyžádalo přeskládat v paměti oblast vyhrazenou kodeku a uvolnit v ní
~58 MB. - Záznam se vším všudy – Matroska kontejner se správným časováním, volitelným bitrate i snímkovou frekvencí.
- Moderní webové rozhraní místo zmizelé mobilní aplikace.
- 60 snímků/s ve 640×480 tam, kde to začínalo na nepoužitelných 3,6.
A protože je z toho obyčejný malý Linux server s vlastním softwarem, není to konečný stav, ale
základ, na kterém jde stavět dál.
Závěr
Začal jsem s krabičkou, kterou by většina lidí vyhodila: nepodporovaná, s mrtvým cloudem, bez ovladače, odmítající to jediné, co jsem po ní chtěl. Skončil jsem s otevřeným zařízením, které nezávisí na ničí cizí službě.
Nechci ale tvrdit, že „to udělala AI“. Dělba práce byla docela jasná. Klasický hardwarový reverse engineering – kabel, konzole, měření, náhodný vstup do zavaděče – byl na mně. Jakmile ale byla data venku, převzala AI drtivou většinu skutečné práce: rozbor firmwaru, dešifrovací klíč, celou vlastní aplikaci, server, webové rozhraní i build. Množství kódu a analýzy, které vzniklo za pár večerů, by dřív znamenalo týdny. Jen je dobré vědět, že ten člověk u toho pořád musí být a i sám technice trochu rozumět, aby hlad AI po pálení tokenů směroval správným směrem.








Žádné sociální komentáře k dispozici.