Come programmare un droide Star Wars

Parole
Andrea Stagi
Tempo di lettura
6

Una nuova Saga di Star Wars ha inizio, impariamo a programmare un droide Sphero con la forza del reverse engineering.

D

Secondo tentativo: qualcuno sul web avrà provato a far muovere il nostro eroe con del codice? Una sola risposta, un solo articolo che spiega un po' il processo ma non arriva fino in fondo al funzionamento del nostro R2D2. Ci resta solo una cosa: fare del sano reverse engineering!

Cosa vuol dire reverse engineering? Si tratta sostanzialmente di una pratica piuttosto diffusa dove analizzando un sistema si riproduce il suo esatto funzionamento. Lo scopo di questo tutorial sarà capire quali messaggi Bluetooth si scambiano la app e il droide e provare a decifrarli e replicarli con del codice!

Una sola cosa ci viene in aiuto: per fortuna Sphero ha rilasciato una documentazione del protocollo di comunicazione tra device e droide, niente di specifico per il nostro amico ma è un buon punto di partenza!

 

Cosa ci serve?

Armiamoci di tutto ciò che serve per questo esperimento! Ovviamente noi qua parliamo di R2D2 ma potete utilizzare la stessa tecnica anche per altri device che vengono controllati tramite Bluetooth!

  1. Un'infarinatura di base sul protocollo Bluetooth LTE (qui un tutorial per principianti)
  2. Un computer provvisto di BLE (sto usando un MacBook Pro)
  3. Un telefono Android (ho un Motorola con Android 6)

La prima cosa da fare è installare Wireshark e Android Developer tools sul PC

  1. Wireshark è un analizzatore di protocolli di rete, lo possiamo utilizzare per leggere i log Bluetooth. Potete scaricarlo dal sito ufficiale
  2. Android Developer tools è un set di strumenti, uno dei quali, adb, servità a noi per comunicare con il telefono e scaricare i log. Qua il link

Una volta settato il PC è il turno del telefono: le cose da fare sono due:

  1. Installare l'app ufficiale di Sphero per controllare il nostro droide.
  2. Ablilitare l'opzione BLE HCI Spoofing

 

Usando questa funzionalità è possibile salvare la comunicazione del telefono con i vari dispositivi Bluetooth, esattamente quello che ci serve

Catturare i dati

Una volta abilitata la funzione bisogna aprire l'app e giocare un po' con il nostro droide. Dopodiché è possibile reperire il file di log con tutta la comunicazione Bluetooth utilizzando adb:

adb pull /sdcard/btsnoop_hci.log /dest/path

Questo file generalmente viene salvato nella path /sdcard/btsnoop_hci.log e può essere ispezionato con Wireshark.

Come utilizzare Wireshark

Questa è la parte più interessante del progetto! Aprendo Wireshark è possibile avere la lista completa di tutti i messaggi scambiati, quindi sarà semplice capire come ricreare il comportamento della app. Questo è quello che ho ottenuto dopo la mia prima sessione: ci sono un sacco di pacchetti di richiesta di informazioni tra il nostro Android device (localhost) e il droide che non ci interessano (il mio droide è quello con indirizzo d7:1b:52:17:7b:d6) ma dopo un po' di scroll finalmente arriva la prima richiesta di scrittura da parte della app (write request)!

Come si può vedere dall'inspector di Wireshark il primo messaggio che la app manda al droide è: “usetheforce. ..band”. Siamo sulla strada giusta :) 

Un'altra informazione importante da salvare è il Service UUID e la Characteristic UUID, valori da annotare per sapere dove mandare il messaggio "usetheforce. ..band"! 

Adesso bisogna sapere come continuare a spulciare il nostro file di log! Dalla documentazione otteniamo una grande informazione utile, la struttura del pacchetto:

Ogni pacchetto scambiato tra app e R2D2 parte con un byte SOP (Start of packet) e un byte EOP (End of packet), rispettivamente di valore 0x8D e 0xD8, perciò bisogna stare molto attenti a tutti i pacchetti che hanno questa forma, saranno loro le azioni che la app dice di eseguire al droide. Ci sono altri byte interessanti da tenere a mente:

SEQ (Sequence Number): un numero sequenziale che viene incrementato ogni volta che la app manda un pacchetto al droide 

DATA (Message Data): una serie di dati (ad esempio se il carrello deve star fuori o dentro) 

CHK (Checksum): la somma di tutti i byte (esclusi SOP and EOP) modulo 256, e con i bit invertiti (qui una funzione per calcolarlo)

Andando più avanti nel log vediamo che il primo pacchetto che rispetta questa struttura è:

0x8D 0x0A 0x13 0x0D 0x00 0xD5 0xD8

Cambiano Service UUID e Characteristic UUID e il byte SEQ è ovviamente 0x00 essendo il primo!

N.B. Da adesso in poi tutti i messaggi andranno verso quest'ultima Characteristic, che chiameremo MAIN_CHAR.

Un altro utile pacchetto da salvare è l'ultimo inviato dalla app prima di chiudersi, il pacchetto che spegne il droide e che ovviamente potete trovare alla fine del file di log:

0x8D 0x0A 0x13 0x01 0x20 0xC1 0xD8

Ogni volta che mandiamo questi messaggi dobbiamo sempre aspettarci una risposta! 

Seguendo la documentazione vediamo che la risposta a comando avvenuto è di nuovo uno stream di byte con SOP e EOP identici, questa volta però con il byte ERR non vuoto, ma di valore 0x00 se tutto è andato per il verso giusto, altrimenti con un codice di errore specifico che sta ad indicare cosa è andato storto. Qui una lista completa dei vari codici di errore

Ci sono inoltre alcuni comandi, come ad esempio quello per le animazioni, che inviano un secondo messaggio di risposta ad azione avvenuta, molto utile per capire quando un'animazione ha finito la sua esecuzione.

Scrivere e leggere dati via Bluetooth

Seguendo lo stesso procedimento che abbiamo adottato per trovare i messaggi per inizializzare e spegnere il droide, cerchiamo adesso quei messaggi per fargli eseguire qualche azione! In questo modo possiamo mandare attraverso il codice questi messaggi e leggere le risposte dal droide.

Per scrivere e leggere i dati via Bluetooth solitamente vengono usate delle apposite librerie che permettono la connessione ai dispositivi, le funzioni per mandare dati verso una specifica caratteristica e leggere le risposte.

Il codice sostanzialmente deve fare le seguenti cose:

1. Connetti il droide specificando il suo indirizzo
2. Manda il messaggio "usetheforce.. .band"
3. Cerca l'oggetto Characteristic e salvalo (MAIN_CHAR) 
4. Manda a MAIN_CHAR il messaggio di iniziazione (SEQ = 0)

Ogni volta che vien scritto un pacchetto verso una data Characteristic:

1. Crea la sequenza di byte calcolando il byte CHK e il SEQ incrementato di 1.
2. Manda questa sequenza di byte a MAIN_CHAR.
3. Attendi una o più risposte e controlla il byte ERR se tutto è andato ok

Qui potete trovare il codice che utilizza Noble una libreria per Node.js per comunicare con i device BLE.

La Saga continua

Se volete proseguire nel dettaglio di come è stato fatto tutto il processo di reverse engineering vi consiglio caldamente l'articolo specifico, corredato di codice e richiami alla documentazione, dove potete trovare come ruotare la parte superiore di R2D2, aprire il carrello e animarlo. La Saga continuerà con un secondo episodio che spiegherà come far muovere il droide e lavorare con i sensori di collisione.

Per i frettolosi smanettoni vi rimando al codice su Github

Buone feste e che la Forza sia con voi!


Credits dell'immagine di copertina: Artwork by Snowmarite (CC)

Analizza la tua presenza online.

Scrivici per una consulenza gratuita



Richiedi consulenza