Hardware di una telecamera IP Reolink RLC 810A

Ora che sappiamo come funziona il booting del dispositivo, proviamo ad estrarre alcune parti dal firmware che abbiamo scaricato nella prima parte. Ci interessano due sezioni principali: il kernel di Linux che si preoccupa di avviare i servizi della telecamera e il Flattened Device Tree che consente al kernel di conoscere a priori la configurazione hardware senza interrogare ogni dispositivo.

Nel corso dell’articolo, procederemo inoltre ad essere produttori di hardware e con occhio critico, andremo a commentare ogni scelta fatta dal produttore.

Estrarre l’Immagine con dd

Per iniziare, proveremo a fare una estrazione manuale, utilizzando il tool dd e il risultato ottenuto dall’analisi con Binwalk. Nella terza parte, invece, utilizzeremo gli strumenti già forniti con Binwalk.

Lo strumento dd fa parte di una serie di utility già predisposte su Linux per copiare pari pari il contenuto di un file specificando l’offset. dd può duplicare dati da file, dispositivi vari, partizioni e volumi. La sua sintassi è abbastanza semplice da capire:

dd if=input_file of=output_file skip=offset count=quanti_blocchi

Identifichiamo quali delle parti dal risultato precedente vogliamo utilizzare. Vogliamo sia il Flattened Device Tree che l’eseguibile iniziale di Linux, ovvero:

34600         0x8728          Flattened device tree, size: 17375 bytes, version: 17
624319        0x986BF         uImage header, header size: 64 bytes, header CRC: 0x7B9F6E31, created: 2021-06-19 06:29:15, image size: 3153472 bytes, Data Address: 0x8000, Entry Point: 0x8000, data CRC: 0xD7FC213, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linux-4.19.91"

Ricordiamo quali dati ci interessano: l’offset (all’inizio della riga) e la dimensione del file che andremo ad estrapolare (image size). Il comando per poter estrarre l’immagine del kernel sarà:

dd if=firmware_rlc_810_a.pak of=linux_image bs=1 skip=624319 count=3153472

Un altro semplice comando (file linux_image) mostrerà la conferma dell’estrazione:

linux_image: u-boot legacy uImage, Linux-4.19.91, Linux/ARM, OS Kernel Image (Not compressed), 3153472 bytes, Sat Jun 19 06:29:15 2021, Load Address: 0X008000, Entry Point: 0X008000, Header CRC: 0X7B9F6E31, Data CRC: 0XD7FC213

Mentre invece quella per il flattened device tree è:

dd if=firmware_rlc_810_a.pak of=device_tree bs=1 skip=34600 count=17375

Anche in questo caso file device_tree conferma l’avvenuta estrazione.

device_tree: Device Tree Blob version 17, size=17375, boot CPU=0, string block size=1495, DT structure block size=15824

Un attento lettore potrebbe chiedersi se valesse la pena affrontare questa sezione di “analisi manuale”, invece di eseguire Binwalk. Si scopre però che l’analisi manuale è esattamente ciò che fa Binwalk: analizza i byte grezzi, se trova una corrispondenza con una signature particolare prova a scompattare il file header e se i dati sono validi, allora prova a estrarre l’immagine dal file analizzato.

Prima di proseguire con l’analisi più seria attraverso l’utilizzo di Binwalk, è utile spiegare il formato file Flattened Device Tree che permette al sistema operativo di sapere già a priori che dispositivi hardware sono presenti all’interno del sistema embedded.

In ambienti general-purpose, quando il sistema operativo viene caricato in memoria, procede ad interrogare tutti i dispositivi connessi per popolare una tabella che indica le informazioni di ogni dispositivo. Per esempio, cosa deve fare il sistema operativo quando la tastiera è in funzione? O quando il mouse si muove?

Per far corrispondere un’azione reale ad un evento virtuale (in input), il sistema operativo traccia tutti i dispositivi in modo da sapere come gestire un qualsiasi evento da parte dei dispositivi hardware. Lo stesso deve sapere anche per trasferire eventi virtuali in azioni fisiche per l’output. Per evitare ogni volta all’avvio di interrogare ogni singolo dispositivo hardware, possiamo adottare due approcci: il primo è quello di scrivere direttamente nel codice le singole periferiche da caricare, l’altro è quello di leggere da un file nel file system le varie configurazioni. Entrambi gli approcci non sembrano la strada giusta: il primo soffre inevitabilmente di problemi (come possiamo configurare in modo dinamico un dispositivo?) mentre il secondo potrebbe essere lento (il sistema operativo dovrebbe conoscere almeno il dispositivo da cui leggere).

La soluzione è un approccio che sta in mezzo alle due vie visti nel paragrafo precedente: il Flattened Device Tree, una sezione che specifica l’insieme dei dispositivi della board. Questa sezione viene caricata immediatamente all’avvio e consente al sistema operativo di capire quali driver caricare e quali no. Il sistema operativo deve soltanto controllare lo status dei dispositivi, al posto di interrogare ogni controllore hardware.

Procediamo quindi nell’analisi del Flattened Device Tree. Una volta estratto, possiamo visualizzarne il contenuto tramite uno strumento chiamato device-tree-compiler. Installiamo il pacchetto e procediamo ad esplorare l’hardware della videocamera ReoLink.

dtc -I dtb -O dts -o - device_tree

Le flag specificano che formato file utilizzare, in input DTB (Device Tree Blob), in output DTS (Device Tree Source) umanamente comprensibile. Una guida molto utile relativa al device-tree-compiler, si può trovare presso git.kernel.org. Il file completo si può trovare invece su Github.

Incominciamo quindi ad ispezionare l’hardware della camera IP Reolink RLC-810 A. Quella che segue è una sezione abbastanza tecnica, ci vorrebbero molti articoli per spiegare in dettaglio in maniera completa ogni singolo dispositivo. Suggerisco di soffermarsi e approfondire ciò che interessa.

Ogni device-tree inizia sempre con alcune specifiche del tipo di board o system on a chip utilizzato. Questi file sono prodotti dal costruttore della board su cui si costruisce il sistema, quindi possono essere utili per capire che tipo di hardware è stato inserito all’interno del prodotto.

model = "Novatek NA51055";
compatible = "novatek,na51055\0nvt,ca9";

Il campo model riporta un’azienda taiwanese piuttosto popolare chiamata “Novatek Microelectronics Corp” che progetta e produce circuiti integrati. La board si chiama NA51055 e sembra essere una variante del modello NT9852x più commercialmente conosciuta. Tramite una ricerca su Google, la board non sembra essere stata utilizzata solo per Reolink, ma anche per alcune dashcam dell’azienda Viofo. Non è infatti raro che un tipo di board venga utilizzata da più di un’azienda dato che molti dispositivi embedded sono simili per funzionalità (dashcam, telecamera: cambia solamente che cosa registrare).

Dopo questa breve specifica, vengono riassunti tutti i dispositivi hardware della board. Ogni dispositivo segue un preciso schema, anche se non sempre vengono specificati tutti i parametri:

nome_dispositivo {
	reg = // impostazione dei registri
	interrupts = // interrupts a cui risponde il dispositivo
	compatible = // stringa che consente al kernel di identificare il device driver capace di gestire il dispositivo
	clock = // riferimento al clock utilizzato dal dispositivo
}

Una nota in più sulla proprietà compatible: il sistema operativo tramite questa proprietà sa a quale device driver collegare il dispositivo. Per conoscere più informazioni quindi sul tipo di driver e su come comunica questa periferica, dobbiamo procedere al reversing di un driver.

Procediamo ad evidenziare alcuni dispositivi hardware:

  • CPU - dispositivo di elaborazione dati. Per questa board, è stata utilizzata una cpu basata su ARM Cortex A9, massima frequenza di clock circa 1GHz. La CPU è molto simile come potenza e possibilità alla CPU montata sull’iPhone 4S.

  • cache - modello pl310: controllore hardware che gestisce la cache dati/istruzioni (si interpone tra la memoria RAM e la CPU). Consente di velocizzare l’esecuzione evitando di continuare a prelevare istruzioni dalla RAM (molto costosa).

  • dispositivi uart: i dispositivi uart convertono dati da un formato parallelo ad un formato seriale asincrono o viceversa.

  • MMC: controllore hardware per la lettura/scrittura su dispositivi microSD.

  • NAND: memoria flash interna alla board, di solito dove viene installato il sistema operativo; interessante notare che all’interno del device flattened tree vengono specificate anche tutte le partizioni del nostro sistema. È possibile quindi cercare di ricavare in modo specifico come è composta l’immagine all’avvio del sistema operativo.

  • encoder JPEG: componente che codifica in modo nativo il flusso di dati proveniente dal sensore ottico in frame jpeg per costruire un flusso di immagini.

  • un’altra serie di dispositivi hardware di basso livello come Watchdog, convertitore analogico-digitale, real-time clock.

NovaTek

Elementi posizionati all'interno della SoC e relative funzioni. Fonte: ambchina.com

CPU

La CPU è il principale elemento hardware che dovremo studiare all’interno di una board. Il compito della CPU è elaborare informazioni: preleva le istruzioni dalla memoria che devono essere eseguite, le esegue e pone il risultato in alcuni registri. Ogni CPU infatti ha associato delle memorie di dimensione molto esigua ma allo stesso tempo sono molto veloci da scrivere o leggere: queste memorie si chiamano registri.

Come confermato durante il secondo articolo, l’architettura della telecamera Reolink è la tipica architettura ARM (Advanced RISC Machine) che possiamo trovare in un qualsiasi altro dispositivo embedded. L’architettura di un elaboratore definisce il tipo di istruzioni (ovvero ciò che deve elaborare la CPU) e di come la CPU computa queste istruzioni. L’architettura ARM è tra le più utilizzate per i dispositivi embedded grazie al ridotto consumo energetico rispetto ad altre architetture.

Quali dispositivi sono basati sull’architettura ARM? Per citarne alcuni: Nintendo DS, Nintendo DSI, iPhone 3GS, iPod. Come caratteristiche principali, troviamo un set di registri a 32 bit, istruzioni a lunghezza fissa per semplificare la decodifica e l’esecuzione, istruzioni RISC.

È bene fare un piccolo excursus sul concetto di RISC. La sigla RISC sta per Reduced Instruction Set Computer e indica un’idea di progettazione di architetture che predilige lo sviluppo di un’architettura semplice e lineare. Per eseguire un qualsiasi tipo di programma, la CPU elabora/computa delle istruzioni: preleva dalla memoria questo dato, fai un addizione. Le istruzioni che una CPU processa sono molto vicine all’hardware: c’è una diretta connessione tra le scelte nella progettazione dell’hardware e tra la complessità delle istruzioni.

Con istruzioni più complesse, la CPU permette di avere un codice di minor complessità e minor lunghezza perché il dispositivo astrae alcuni concetti e rende disponibile un’interfaccia meno complessa. D’altro canto però aumento il tempo necessario per il completamento di un’istruzione, quindi diminuisco la velocità. Un’altra scelta potrebbe essere istruzioni meno complesse: un codice di lunghezza elevata, di complessità inferiore, ma velocità aumentata.

Per spiegare ancora meglio questo fatto, introduciamo un dispositivo in particolare chiamato clock che assicura la perfetta sincronizzazione tra tutti i componenti interni alla CPU. Il clock è molto simile ad un metronomo e conferisce il tempo alla CPU: un ciclo di clock è l’unità minima temporale per cui misurare l’elaborazione delle istruzioni. Se si ha una CPU a 1GHz vuol dire che la frequenza del ciclo di clock è un 1GHz e quindi circa 1 miliardo di istruzioni ogni secondo, ipotizzando un ciclo di clock = una istruzione.

Il clock è uno strumento arbitrario: ogni progettista è in grado di aumentare o diminuire la velocità con cui il clock conferisce il segnale alla CPU. Naturalmente, è un processo molto bilanciato: se il clock è troppo veloce, c’è il rischio che la CPU perda istruzioni, se il clock è troppo lento c’è il rischio che la CPU sprechi tempo inutile. Dal momento che possiamo decidere la velocità con cui la CPU elabora queste istruzioni, più istruzioni meno complesse sembrano il perfetto approccio rispetto a “meno istruzioni più complesse”. Aumentare la velocità diminuendo la complessità delle istruzioni è molto semplice: basta aumentare la velocità del clock! È più difficile invece aumentare la velocità con istruzioni intrisicamente più complesse. Una frequenza di clock più alta in questo ultimo caso non gioverebbe alla macchina che correrebbe il rischio di saltare istruzioni.

L’approccio del “più istruzioni da eseguire, meno complesse” è l’approccio scelto per l’architettura RISC e permette di avere un consumo energetico più limitato (meno complessità, minore corrente utilizzata). Questa caratteristica fa di RISC e di ARM l’architettura preferita per la maggior parte dei dispositivi embedded.

Introdotta nel 2007, la CPU di tipo ARM Cortex presenta alcune delle seguenti caratteristiche:

  • L2 cache controller fino a 4MB: il controllore per la cache di livello 2;
  • 8 stadi per la pipeline;
  • Elaborazione multicore;
  • Thumb-2 come codifica del set di istruzioni che riduce le dimensioni dei programmi;
  • MMU abilitato: Memory Management Unit, un componente interno alla CPU che permette di abilitare il supporto alla memoria virtuale;

In particolar modo, notiamo che la board di Novatek ha una CPU a 2 core. Questo è molto importante perché consente di fatto di avere due programmi che vengono eseguiti parallelamente. Stando ad alcune ricerche e al fatto di aver trovato alcune stringhe riconducibili a RTOS, è possibile che una CPU esegua il processo principale della IP camera (catturando l’immagine e trasferendolo in un video continuo), mentre l’altra esegue una distribuzione custom basata su Linux. Per ora non ci preoccupiamo troppo della parte real-time: è sufficiente sapere che esiste un motore grafico che si preoccupa di salvare le immagini catturate dal sensore ottico.

La nostra indagine sulla CPU purtroppo si conclude qua dato che non abbiamo ulteriori informazioni da parte di Novatek. Un documento riportante il datasheet della board NT96650BG può farvi immaginare il grado di segretezza che Novatek assume rispetto alle loro informazioni.

Memoria flash NAND

La memoria flash NAND viene utilizzata come spazio per il sistema operativo e per i file applicativi (binari che controllano la telecamera, file di configurazione e molto altro). Normalmente è saldata sulla board e una volta che è stato scritto del contenuto su di essa, la riscrittura o il re-flashing richiede qualche accortezza in più.

Questo tipo di memoria è una categoria molto estesa di supporti di archiviazione (disco a stato solido) che memorizzano i dati attraverso la configurazione di transistor. Questi transistor (che possono raffigurare a seconda dei casi delle porte NOR oppure NAND) mantengono per lungo tempo una carica elettrica. Ogni transistor costituisce una cella di memoria che conserva il valore di un bit, avendo più celle di memoria in serie o in parallelo è possibile memorizzare tonnellate di dati.

Non entriamo in merito alla parte più intricata dell’hardware, possiamo però notare a posteriori come venga utilizzata la memoria FP2024 5F1GQ4UBYIG prodotta da GigaDevice.

È interessante sapere come a priori possiamo prevedere il layout della flash NAND, spulciando la sezione NAND del FDT incorporato all’interno del kernel. In particolare possiamo trovare all’interno del Flattened Device Tree:

  • partizione loader: componente incaricato di caricare il sistema operativo, zona di memoria 0x0 di dimensione 0x40000
  • partizione fdt (file nvt-na51055-evb.bin): il Flattened Device Tree, caricato nella zona di memoria 0x40000 di dimensione 0x40000
  • partizione fdt_restore: contiene una copia del Flattened Device Tree da utilizzare in caso di errore imprevisto, caricato nella zona di memoria 0x80000 di dimensione 0x40000.
  • partizione uboot (file u-boot.bin): contiene il bootloader uboot, dimensione 0x18000 a partire da 0xc0000;
  • partizione uenv: contiene i parametri di avvio per uboot di dimensione 0x40000 a partire da 0x240000;
  • partizione kernel (file uImage.bin) : contiene l’immagine del kernel di Linux (initrd) di dimensione 0x480000 a partire da 0x28000;
  • partizione rootfs (file rootfs.ubifs.bin): contiene l’immagine del file system con file di configurazioni e il sistema operativo, dimensione: 0x2000000, a partire da 0x700000;
  • partizione appfs (file appfs.ubifs.bin): contiene l’insieme di file specifici per intenti applicativi (dimensione: 0x1500000, a partire da 0x2700000);
  • altre partizioni libere che servono per l’installazione di un nuovo firmware da interfaccia web;

Facendo due conti con la memoria NAND disponibile durante l’avvio: 0x80000000 ➔134217728 byte ➔ 128 Mebibyte (MiB) ➔ 220 Byte. Troviamo quindi corrispondenza tra il modello NA51055 (probabilmente disegnato per ReoLink) e il modello NT98523 (menzionato nel Device Flattened Tree).

Hardware della Board

Ho trovato però discrepanze tra i modelli Novatek menzionati all’interno del firmware e ciò che è stato utilizzato fisicamente all’interno di Reolink. Per confermare la parte hardware e investigare ulteriormente sul firmware, possiamo controllare le immagini interne depositate alla FCC. Facciamo però un passo indietro per spiegare meglio il ruolo della FCC.

Quando un qualsiasi produttore vuole commercializzare un prodotto in un determinato paese, deve sottostare ad alcune leggi che regolano l’utilizzo delle frequenze e l’impatto che ha sulle frequenze già utilizzate. Per gli Stati Uniti, l’ente regolatore che verifica ogni prodotto e certifica la sua sicurezza si chiama Federal Communications Commission (FCC). La FCC dispone di un suo marchio che certifica che l’interferenza elettromagnetica dal dispositivo rispetta i limiti statali.

Ogni costruttore che vende un prodotto negli Stati Uniti deve certificare la sicurezza elettromagnetica, prendendo accordi con laboratori terzi per effettuare alcuni test e misurazioni. Se l’ente federale approva i dati per un certo prodotto, allora il produttore riceve il marchio FCC e il dispositivo può essere messo in vendita.

In un’ottica di trasparenza, tutte le richieste sono visibili pubblicamente e chiunque può consultare i risultati dei test, incluse le immagini interne del prodotto. Non avendo a disposizione un prodotto Reolink, ho preferito consultare ed ispezionare le immagini già disponibili sull’archivio FCC. FCCID consente di esplorare tutte le richieste pervenute alla FCC. È bastato digitare Reolink per accedere alle certificazioni da parte di Reolink Innovation Limited, l’azienda titolare dell’hardware prodotto.

Siamo interessati al Report per il prodotto 2AYHE-2012A. Reolink RLC810-A è una copia identica del modello Reolink-RLC511-WA, l’unica differenza sta nel sensore ottico. Come possiamo vedere dalle foto interne, Reolink RLC810-A monta il processore NT98523MBG 2004-BB T8N60400. Per la memoria flash interna, viene confermata una scheda 128Mb da GigaDevice (FP2024 5F1GQ4UBYIG), come ci aspettavamo dal device flattened tree. Il dispositivo è inoltre equipaggiato con 256MB di RAM da SKHynix (H5TQ2G63GFR-RDC 025A NWMN9528HF).

NovaTek CPU

Processore NT98632MBG - immagine interna dal report FCC

Il layout interno è quasi identico al modello RLC511-WA perché presenta le stesse caratteristiche di RLC810-A, solamente per una piccola differenza, ovvero il sensore ottico. Diversi report (come TechInsights e forum mobile01.com) mostrano come Reolink abbia scelto il sensore O12D40 dell’azienda OmniVision per RLC810-A che consente di memorizzare video fino ad una massima risoluzione di 4512x2512. Questo però stona un po’ dalle caratteristiche presentate dal costrutture, in cui si evidenzia una risoluzione massima di 3840x2160 con al massimo 8 MP. Con tutta probabilità, l’azienda ha preferito tenere una risoluzione più bassa del massimo per via della CPU meno potente, rispetto a quella che servirebbe per elaborare video in risoluzione più alta.

RLC511-WA Sensore ottico

Il sensore da 5MP utilizzato dal modello 'gemello' Reolink RLC-511WA - immagine interna dal report FCC.

Reolink quindi ha utilizzato lo stesso layout di memoria con la stessa potenza, tentando però di ottenere una maggiore definizione con un diverso sensore ottico. Il “miracolo” tecnico è reso possibile da un potente firmware che riesce a minimizzare il carico sulla CPU. Questo miracolo però ha qualche limite e difetto: sono infatti molteplici le recensioni che riportano come la visione e registrazione dei filmati 4k sia instabile. Approfondiremo anche questo problema nel corso di articoli successivi.

Il sensore utilizzato da RLC-810A

Il sensore utilizzato da RLC-810A, OS12D40-PB-v1.1.0

Conclusioni: Hardware Centralizzato

Non è compito di questa guida approfondire ulteriormente tutti i dispositivi hardware, quindi la sezione dedicata all’hardware finisce qui. Per sommi capi cerchiamo di concludere l’articolo con un paio di riflessioni. Non sono un esperto hardware, quindi prendete con le pinze tutto ciò che è scritto in questo articolo.

Abbiamo capito quanto un dispositivo possa essere complesso sia dal punto di vista tecnico che dal punto di vista “logistico”: tra RAM, CPU, cache e molto altro non esiste solo un fornitore ma più aziende che contribuiscono allo sviluppo della board. Abbiamo inoltre verificato di come le aziende - Reolink, ma molte altre - condividano tutte lo stesso hardware (con differente prezzo) comprato dallo stesso produttore (Novatek). C’è quindi il rischio che un hardware sia centralizzato e un problema su una board possa essere comune a molti dispositivi.

Un’altra riflessione sull’hardware riguarda la sicurezza by obscurity, una pratica che affida la sicurezza di un sistema alla segretezza nella progettazione o implementazione di un sistema. In questo caso, la “segretezza” del sistema sta nel dispositivo che non può essere facilmente ispezionato visivamente perché l’hardware/circuito integrato ha dimensioni molto piccole. Parleremo in articoli successivi della segretezza “software”.

Seppur il dispositivo Reolink sia stato testato e certificato, non c’è modo di verificare dal punto di vista della sicurezza ogni elemento hardware. Inoltre, non è possibile ricavare molte informazioni da fonti aperte, probabilmente per proteggere la proprietà intellettuale dell’azienda. Manca quindi da parte di Reolink tutta la questione dell’open-source che potrebbe beneficiare all’azienda. Ipotizziamo che parzialmente questo sia dovuto anche alla segretezza imposta dal produttore, Novatek.

La mancanza di trasparenza può fare la differenza nel caso in cui telecamere vengano impiegate in luoghi abbastanza critici: banche, aeroporti, uffici governativi. Recenti articoli additano un’altra azienda (HikVision) che produce telecamere IP di essere molto vicino al governo “cinese”. È sicuramente difficile separare ciò che è realtà dalla fantasia (complotti politici/ideali). Quello che però possiamo limitarci a fare è di avere un’obiettiva visione sul dispositivo e provare, tramite strumenti di reverse engineering, ad eseguire test/analisi.