Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Ciao.

Noi, Victor Antipov e Ilya Aleshin, oggi parleremo della nostra esperienza di lavoro con dispositivi USB tramite Python PyUSB e un po' di reverse engineering.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Sfondo

Nel 2019, decreto del governo della Federazione Russa n. 224 “Approvazione delle norme per l'etichettatura dei prodotti del tabacco con mezzi di identificazione e caratteristiche dell'attuazione di un sistema informativo statale per il monitoraggio della circolazione delle merci soggette a etichettatura obbligatoria con mezzi di identificazione in relazione ai prodotti del tabacco” è entrato in vigore.
Nel documento si spiega che dal 1 luglio 2019 i produttori sono tenuti ad etichettare ogni confezione di tabacco. E i distributori diretti devono ricevere questi prodotti con la sottoscrizione di un documento di trasferimento universale (UDD). I negozi, a loro volta, devono registrare la vendita dei prodotti etichettati tramite il registratore di cassa.

Inoltre, dal 1 luglio 2020, è vietata la circolazione di prodotti del tabacco senza etichetta. Ciò significa che tutti i pacchetti di sigarette devono essere contrassegnati con uno speciale codice a barre Datamatrix. Inoltre, punto importante, si è scoperto che Datamatrix non sarà ordinario, ma inverso. Cioè, non codice nero su bianco, ma viceversa.

Abbiamo testato i nostri scanner e abbiamo scoperto che la maggior parte di essi necessita di un reflash/riqualificazione, altrimenti semplicemente non sono in grado di funzionare normalmente con questo codice a barre. Questa svolta degli eventi ci ha garantito un forte mal di testa, perché la nostra azienda ha molti negozi sparsi su un vasto territorio. Diverse decine di migliaia di registratori di cassa – e pochissimo tempo.

cosa doveva essere fatto? Ci sono due opzioni. Primo: i tecnici in loco eseguono il reflash e regolano manualmente gli scanner. Secondo: lavoriamo in remoto e, preferibilmente, copriamo più scanner contemporaneamente in un'unica iterazione.

La prima opzione, ovviamente, non era adatta a noi: dovremmo spendere soldi per gli ingegneri in visita, e in questo caso sarebbe difficile controllare e coordinare il processo. Ma la cosa più importante è che le persone lavorino, cioè potenzialmente commetteremmo molti errori e, molto probabilmente, non rispetteremo la scadenza.

La seconda opzione va bene per tutti, se non per una cosa. Alcuni fornitori non disponevano degli strumenti di flashing remoto di cui avevamo bisogno per tutti i sistemi operativi richiesti. E poiché le scadenze stavano per scadere, ho dovuto pensare con la mia testa.

Successivamente, ti diremo come abbiamo sviluppato strumenti per scanner portatili per il sistema operativo Debian 9.x (tutti i nostri registratori di cassa sono su Debian).

Risolvi l'enigma: come flashare uno scanner

Lo riferisce Victor Antipov.

L'utilità ufficiale fornita dal venditore funziona su Windows e solo con IE. L'utilità può eseguire il flashing e configurare lo scanner.

Poiché il nostro sistema di destinazione è Debian, abbiamo installato un server di reindirizzamento USB su Debian e un client di reindirizzamento USB su Windows. Utilizzando le utilità di reindirizzamento USB, abbiamo inoltrato lo scanner da una macchina Linux a una macchina Windows.

Un'utilità di un fornitore Windows ha rilevato lo scanner e lo ha persino visualizzato normalmente. Quindi siamo giunti alla prima conclusione: nulla dipende dal sistema operativo, è una questione di protocollo flash.

OK. Abbiamo eseguito il flashing sulla macchina Windows e rimosso il dump sulla macchina Linux.

Abbiamo inserito il dump in WireShark e... ci siamo rattristati (ometterò alcuni dettagli del dump, non sono di alcun interesse).

Cosa ci ha mostrato la discarica:

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Gli indirizzi 0000-0030, a giudicare da Wireshark, sono informazioni sul servizio USB.

Eravamo interessati alla parte 0040-0070.

Nulla era chiaro da un frame di trasmissione tranne i caratteri MOCFT. Questi caratteri si sono rivelati caratteri del file del firmware, così come i caratteri rimanenti fino alla fine del frame (il file del firmware è evidenziato):

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Cosa significassero i simboli fd 3e 02 01 fe, personalmente, come Ilya, non ne avevo idea.

Ho esaminato il seguente frame (le informazioni sul servizio sono state rimosse qui, il file del firmware è stato evidenziato):

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Cosa è diventato chiaro? Che i primi due byte sono una sorta di costante. Tutti i blocchi successivi lo hanno confermato, ma prima della fine del blocco di trasmissione:

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Anche questo fotogramma era stupefacente, poiché la costante era cambiata (evidenziata) e, stranamente, c'era parte del file. La dimensione dei byte trasferiti del file ha mostrato che sono stati trasferiti 1024 byte. Ancora una volta non sapevo cosa significassero i byte rimanenti.

Innanzitutto, come vecchio nickname BBS, ho ripassato i protocolli di trasmissione standard. Nessun protocollo trasmesso 1024 byte. Ho iniziato a studiare l'hardware e mi sono imbattuto nel protocollo 1K Xmodem. Permetteva di trasmetterne 1024, ma con un avvertimento: all'inizio solo 128, e solo se non c'erano errori, il protocollo aumentava il numero di byte trasmessi. Ho subito avuto un trasferimento di 1024 byte. Ho deciso di studiare i protocolli di trasmissione, e nello specifico l'X-modem.

C'erano due varianti del modem.

Innanzitutto, il formato del pacchetto XMODEM con supporto CRC8 (l'XMODEM originale):

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

In secondo luogo, il formato del pacchetto XMODEM con supporto CRC16 (XmodemCRC):

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Sembra simile, ad eccezione di SOH, numero del pacchetto, CRC e lunghezza del pacchetto.

Ho guardato l'inizio del secondo blocco di trasmissione (e ho visto di nuovo il file del firmware, ma già rientrato di 1024 byte):

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Ho visto l'intestazione familiare fd 3e 02, ma i due byte successivi erano già cambiati: era 01 fe e è diventato 02 fd. Poi ho notato che il secondo blocco ora era numerato 02 e quindi ho capito: davanti a me c'era la numerazione del blocco di trasmissione. La prima marcia di 1024 è 01, la seconda è 02, la terza è 03 e così via (ma in esadecimale, ovviamente). Ma cosa significa il passaggio da fe a fd? Gli occhi hanno visto una diminuzione di 1, il cervello ha ricordato che i programmatori contano da 0, non da 1. Ma allora perché il primo blocco è 1 e non 0? Non ho ancora trovato la risposta a questa domanda. Ma ho capito come viene contato il secondo blocco. Il secondo blocco non è altro che FF – (meno) il numero del primo blocco. Pertanto, il secondo blocco è stato designato come = 02 (FF-02) = 02 FD. La successiva lettura del dump ha confermato la mia ipotesi.

Quindi cominciò ad emergere la seguente immagine della trasmissione:

Inizio della trasmissione
fd 3e 02 – Inizio
01 FE – contatore di trasmissione
Trasferimento (34 blocchi, 1024 byte trasferiti)
fd 3e 1024 byte di dati (divisi in blocchi da 30 byte).
Fine della trasmissione
fd 25

I dati rimanenti devono essere allineati a 1024 byte.

Che aspetto ha il telaio terminale della trasmissione a blocchi:

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

fd 25 – segnale per terminare la trasmissione del blocco. Next 2f 52 – il resto del file ha una dimensione massima di 1024 byte. 2f 52, a giudicare dal protocollo, è un checksum CRC a 16 bit.

In ricordo dei vecchi tempi, ho creato un programma in C che estraeva 1024 byte da un file e calcolava un CRC a 16 bit. L'avvio del programma ha mostrato che non si tratta di un CRC a 16 bit. Di nuovo stupore - per circa tre giorni. Per tutto questo tempo ho cercato di capire cosa potesse essere, se non un checksum. Studiando i siti in lingua inglese, ho scoperto che l'X-modem utilizza il proprio calcolo del checksum: CRC-CCITT (XModem). Non ho trovato alcuna implementazione C di questo calcolo, ma ho trovato un sito online che calcolava questo checksum. Dopo aver trasferito 1024 byte del mio file sulla pagina web, il sito mi ha mostrato un checksum che corrispondeva completamente al checksum del file.

Evviva! L'ultimo enigma è stato risolto, ora dovevo creare il mio firmware. Successivamente, ho trasmesso la mia conoscenza (ed è rimasta solo nella mia testa) a Ilya, che ha familiarità con il potente toolkit Python.

Creazione di un programma

Lo riferisce Ilya Aleshin.

Avendo ricevuto le istruzioni appropriate, ero molto “felice”.

Da dove cominciare? Esatto, dall'inizio.  Dall'acquisizione di un dump dalla porta USB.

Avvia USB-pcap https://desowin.org/usbpcap/tour.html

Seleziona la porta a cui è connesso il dispositivo e il file in cui salveremo il dump.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Colleghiamo lo scanner a una macchina su cui è installato il software nativo EZConfigScanning per Windows.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

In esso troviamo la voce per l'invio di comandi al dispositivo. Ma per quanto riguarda le squadre? Dove posso trovarli?
All'avvio del programma, l'apparecchiatura viene interrogata automaticamente (lo vedremo tra poco). E c'erano codici a barre di addestramento dai documenti ufficiali dell'attrezzatura. DEFALTO. Questa è la nostra squadra.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

I dati necessari sono stati ricevuti. Apri dump.pcap tramite wireshark.

Blocca all'avvio di EZConfigScanning. I luoghi a cui devi prestare attenzione sono contrassegnati in rosso.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Vedendo tutto questo per la prima volta, mi sono perso d'animo. Non è chiaro dove scavare dopo.

Un po' di brainstorming e-e-e... Aha! Nella discarica su - è inE in essa su.

Ho cercato su Google cos'è URB_INTERRUPT. Ho scoperto che questo è un metodo di trasferimento dati. E ci sono 4 metodi di questo tipo: controllo, interruzione, isocrono, massa. Puoi leggerli separatamente.

E gli indirizzi degli endpoint nell'interfaccia del dispositivo USB possono essere ottenuti tramite il comando "lsusb –v" o utilizzando pyusb.

Ora dobbiamo trovare tutti i dispositivi con questo VID. È possibile effettuare una ricerca specifica per VID:PID.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Sembra questo:

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Quindi abbiamo le informazioni necessarie: i comandi P_INFO. oppure DEFALT, indirizzi dove scrivere i comandi endpoint=03 e dove ottenere la risposta endpoint=86. Non resta che convertire i comandi in esadecimale.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Dato che abbiamo già trovato il dispositivo, scolleghiamolo dal kernel...

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

...e scrivere sull'endpoint con indirizzo 0x03,

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

... e quindi leggere la risposta dall'endpoint con indirizzo 0x86.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Risposta strutturata:

P_INFOfmt: 1
mode: app
app-present: 1
boot-present: 1
hw-sn: 18072B44CA
hw-rev: 0x20
cbl: 4
app-sw-rev: CP000116BBA
boot-sw-rev: CP000014BAD
flash: 3
app-m_name: Voyager 1450g
boot-m_name: Voyager 1450g
app-p_name: 1450g
boot-p_name: 1450g
boot-time: 16:56:02
boot-date: Oct 16 2014
app-time: 08:49:30
app-date: Mar 25 2019
app-compat: 289
boot-compat: 288
csum: 0x6986

Vediamo questi dati in dump.pcap.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Grande! Converti i codici a barre del sistema in esadecimali. Questo è tutto, la funzionalità di formazione è pronta.

E il firmware? Tutto sembra essere uguale, ma c'è una sfumatura.

Dopo aver analizzato completamente il processo di flashing, abbiamo capito a grandi linee con cosa avevamo a che fare. Ecco un articolo su XMODEM, che è stato molto utile per capire come avviene questa comunicazione, anche se in termini generali: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Consiglio di leggerlo.

Osservando il dump, puoi vedere che la dimensione del frame è 1024 e la dimensione dei dati URB è 64.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Quindi – 1024/64 – otteniamo 16 righe in un blocco, leggiamo il file firmware 1 carattere alla volta e formiamo un blocco. Complementare 1 riga in un blocco con caratteri speciali fd3e02 + numero di blocco.
Le successive 14 righe vengono integrate con fd25 +, utilizzando XMODEM.calc_crc() calcoliamo il checksum dell'intero blocco (ci è voluto molto tempo per capire che “FF – 1” è CSUM) e l'ultima, la sedicesima riga, viene integrata con fd16e.

Sembrerebbe che sia tutto, leggi il file del firmware, colpisci i blocchi, disconnetti lo scanner dal kernel e invialo al dispositivo. Ma non è così semplice. Lo scanner deve essere impostato sulla modalità firmware,
отправив ему NEWAPP = ‘\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
Da dove viene questa squadra?? Dalla discarica.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Ma non possiamo inviare un intero blocco allo scanner a causa del limite di 64:

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Bene, lo scanner in modalità flash NEWAPP non accetta hex. Pertanto, dovrai tradurre ogni riga bytes_array

[253, 10, 22, 78, 44, 78, 69, 87, 65, 80, 80, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

E poi invia questi dati allo scanner.

Otteniamo la risposta:

[2, 1, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Se controlli l'articolo su XMODEM, diventerà chiaro: i dati sono stati accettati.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

Dopo che tutti i blocchi sono stati trasferiti, completiamo il trasferimento END_TRANSFER = 'xfdx01x04'.

Bene, poiché questi blocchi non contengono alcuna informazione per la gente comune, installeremo il firmware in modalità nascosta per impostazione predefinita. E per ogni evenienza, organizzeremo una barra di avanzamento tramite tqdm.

Un compito per uno sviluppatore o il modo in cui abbiamo flashato gli scanner portatili senza un fornitore

In realtà poi è questione di piccole cose. Non resta che avvolgere la soluzione in script per la replica di massa in un momento ben definito, in modo da non rallentare il processo di lavoro alle casse, e aggiungere il logging.

risultato

Avendo dedicato molto tempo, impegno e capelli in testa, siamo stati in grado di sviluppare le soluzioni di cui avevamo bisogno e di rispettare anche la scadenza. Allo stesso tempo, gli scanner vengono ora aggiornati e riqualificati a livello centrale, controlliamo chiaramente l'intero processo. L'azienda ha risparmiato tempo e denaro e abbiamo acquisito una preziosa esperienza nel reverse engineering di apparecchiature di questo tipo.

Fonte: habr.com

Aggiungi un commento