En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Hei alle sammen.

Vi, Viktor Antipov og Ilya Aleshin, vil i dag snakke om vår erfaring med å jobbe med USB-enheter via Python PyUSB og litt om reverse engineering.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

forhistorie

I 2019, dekret fra regjeringen i den russiske føderasjonen nr. 224 "Om godkjenning av reglene for merking av tobakksprodukter med identifikasjonsmidler og funksjoner ved implementeringen av et statlig informasjonssystem for overvåking av sirkulasjonen av varer som er underlagt obligatorisk merking med identifikasjonsmidler i forhold til tobakksvarer» trådte i kraft.
Dokumentet forklarer at fra 1. juli 2019 er produsenter pålagt å merke hver pakke tobakk. Og direkte distributører må motta disse produktene med utførelse av et universelt overføringsdokument (UDD). Butikker må på sin side registrere salg av merkede produkter gjennom kassaapparatet.

Fra 1. juli 2020 er det også forbudt å sirkulere umerkede tobakksprodukter. Dette betyr at alle sigarettpakker skal merkes med en spesiell Datamatrix-strekkode. Dessuten - et viktig poeng - viste det seg at Datamatrisen ikke vil være vanlig, men invers. Det vil si ikke svart kode på hvitt, men omvendt.

Vi testet skannerne våre, og det viste seg at de fleste av dem må etterfylles/opplæres, ellers klarer de rett og slett ikke å fungere normalt med denne strekkoden. Denne hendelsen garanterte oss en alvorlig hodepine, fordi selskapet vårt har mange butikker som er spredt over et stort territorium. Flere titusenvis av kasseapparater – og svært lite tid.

Hva skulle gjøres? Det er to alternativer. For det første: ingeniører på stedet manuelt relash og justerer skannerne. For det andre: vi jobber eksternt og dekker fortrinnsvis mange skannere samtidig i én iterasjon.

Det første alternativet var åpenbart ikke egnet for oss: vi måtte bruke penger på å besøke ingeniører, og i dette tilfellet ville det være vanskelig å kontrollere og koordinere prosessen. Men det viktigste er at folk ville jobbe, det vil si at vi potensielt ville fått mange feil og mest sannsynlig ikke holdt tidsfristen.

Det andre alternativet er bra for alle, om ikke for én ting. Noen leverandører hadde ikke fjernblinkverktøyene vi trengte for alle de nødvendige operativsystemene. Og siden fristene gikk ut, måtte jeg tenke med mitt eget hode.

Deretter skal vi fortelle deg hvordan vi utviklet verktøy for håndholdte skannere for Debian 9.x OS (alle våre kasseapparater er på Debian).

Løs gåten: hvordan flashe en skanner

Victor Antipov rapporterer.

Det offisielle verktøyet levert av leverandøren fungerer under Windows, og bare med IE. Verktøyet kan blinke og konfigurere skanneren.

Siden målsystemet vårt er Debian, installerte vi en usb-omdirigeringsserver på Debian og en usb-omdirigeringsklient på Windows. Ved å bruke usb-omdirigeringsverktøy videresendte vi skanneren fra en Linux-maskin til en Windows-maskin.

Et verktøy fra en Windows-leverandør så skanneren og blinket til og med normalt. Dermed gjorde vi den første konklusjonen: ingenting avhenger av operativsystemet, det er et spørsmål om den blinkende protokollen.

OK. Vi kjørte blinkingen på Windows-maskinen, og fjernet dumpen på Linux-maskinen.

Vi stappet dumpen inn i WireShark og... ble triste (jeg utelater noen av detaljene om dumpen, de er ikke av interesse).

Hva dumpen viste oss:

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Adressene 0000-0030, bedømt av Wireshark, er USB-tjenesteinformasjon.

Vi var interessert i del 0040-0070.

Ingenting var klart fra en overføringsramme bortsett fra MOCFT-karakterene. Disse tegnene viste seg å være tegn fra fastvarefilen, så vel som de gjenværende tegnene til slutten av rammen (fastvarefilen er uthevet):

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Hva symbolene fd 3e 02 01 fe betydde, hadde jeg personlig, som Ilya, ingen anelse om.

Jeg så på følgende ramme (tjenesteinformasjon er fjernet her, fastvarefilen er uthevet):

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Hva ble klart? At de to første bytene er en slags konstant. Alle påfølgende blokker bekreftet dette, men før slutten av overføringsblokken:

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Denne rammen var også forvirrende, siden konstanten hadde endret seg (uthevet) og merkelig nok var det en del av filen. Størrelsen på de overførte bytene til filen viste at 1024 byte ble overført. Jeg visste igjen ikke hva de gjenværende bytene betydde.

Først av alt, som et gammelt BBS-kallenavn, gjennomgikk jeg standard overføringsprotokoller. Ingen protokoll overført 1024 byte. Jeg begynte å studere maskinvaren og kom over 1K Xmodem-protokollen. Den tillot overføring av 1024, men med et forbehold: først bare 128, og bare hvis det ikke var noen feil, økte protokollen antallet byte som ble overført. Jeg hadde umiddelbart en overføring på 1024 byte. Jeg bestemte meg for å studere overføringsprotokoller, og spesifikt X-modemet.

Det var to varianter av modemet.

Først XMODEM-pakkeformatet med CRC8-støtte (den originale XMODEM):

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

For det andre, XMODEM-pakkeformatet med CRC16-støtte (XmodemCRC):

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Det ser likt ut, bortsett fra SOH, pakkenummer og CRC og pakkelengde.

Jeg så på begynnelsen av den andre overføringsblokken (og så igjen fastvarefilen, men allerede rykket inn med 1024 byte):

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Jeg så den velkjente overskriften fd 3e 02, men de neste to bytene var allerede endret: den var 01 fe, og ble 02 fd. Så la jeg merke til at den andre blokken nå var nummerert 02 og forsto dermed: foran meg var nummereringen av overføringsblokken. Det første 1024 giret er 01, det andre er 02, det tredje er 03 og så videre (men i hex, selvfølgelig). Men hva betyr endringen fra fe til fd? Øynene så en nedgang med 1, hjernen minnet om at programmerere teller fra 0, ikke 1. Men hvorfor er så den første blokken 1, og ikke 0? Jeg har fortsatt ikke funnet svaret på dette spørsmålet. Men jeg forsto hvordan den andre blokken regnes. Den andre blokken er ikke mer enn FF – (minus) nummeret til den første blokken. Dermed ble den andre blokken betegnet som = 02 (FF-02) = 02 FD. Etterfølgende lesing av dumpen bekreftet min gjetning.

Så begynte følgende bilde av overføringen å dukke opp:

Start av overføring
fd 3e 02 – Start
01 FE – sendeteller
Overføring (34 blokker, 1024 byte overført)
fd 3e 1024 byte med data (delt i 30 byte blokker).
Slutt på overføring
fd 25

Gjenværende data skal justeres til 1024 byte.

Hvordan ser blokktransmisjonens enderamme ut:

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

fd 25 – signal til sluttblokkoverføring. Neste 2f 52 – resten av filen opptil 1024 byte i størrelse. 2f 52, bedømt etter protokollen, er en 16-bits CRC-sjekksum.

For gamle dagers skyld laget jeg et program i C som trakk 1024 byte fra en fil og beregnet en 16-biters CRC. Å starte programmet viste at dette ikke er en 16-bits CRC. Stupor igjen - i omtrent tre dager. Hele denne tiden prøvde jeg å forstå hva det kunne være, om ikke en sjekksum. Mens jeg studerte engelskspråklige nettsteder, oppdaget jeg at X-modemet bruker sin egen kontrollsumberegning - CRC-CCITT (XModem). Jeg fant ingen C-implementeringer av denne beregningen, men jeg fant et nettsted som beregnet denne sjekksummen på nettet. Etter å ha overført 1024 byte av filen min til nettsiden, viste nettstedet meg en kontrollsum som samsvarte fullstendig med kontrollsummen fra filen.

Hurra! Den siste gåten var løst, nå måtte jeg lage min egen firmware. Deretter ga jeg kunnskapen min videre (og den forble bare i hodet mitt) til Ilya, som er kjent med den kraftige verktøypakken Python.

Opprette et program

Ilya Aleshin rapporterer.

Etter å ha mottatt de riktige instruksjonene, var jeg veldig "glad".

Hvor skal jeg begynne? Det stemmer, fra begynnelsen.  Fra å ta en dump fra USB-porten.

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

Velg porten som enheten er koblet til og filen der vi skal lagre dumpen.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Vi kobler skanneren til en maskin der den opprinnelige EZConfigScanning-programvaren for Windows er installert.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

I den finner vi elementet for å sende kommandoer til enheten. Men hva med lagene? Hvor kan jeg få tak i dem?
Når programmet starter polles utstyret automatisk (det får vi se litt senere). Og det var treningsstrekkoder fra offisielle utstyrsdokumenter. DEFALT. Dette er laget vårt.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Nødvendige data er mottatt. Åpne dump.pcap via wireshark.

Blokker når du starter EZConfigScanning. Steder du må være oppmerksom på er merket med rødt.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Da jeg så alt dette for første gang, mistet jeg motet. Det er ikke klart hvor du skal grave videre.

Litt idédugnad og-og-og... Aha! På søppelplassen ut - Er inOg in dette ut.

Jeg googlet hva URB_INTERRUPT er. Jeg fant ut at dette er en dataoverføringsmetode. Og det er 4 slike metoder: kontroll, avbrudd, isokron, bulk. Du kan lese om dem separat.

Og endepunktadressene i USB-enhetsgrensesnittet kan oppnås enten gjennom kommandoen "lsusb -v" eller ved å bruke pyusb.

Nå må vi finne alle enheter med denne VID. Du kan søke spesifikt etter VID:PID.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Det ser slik ut:

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Så vi har den nødvendige informasjonen: P_INFO-kommandoene. eller DEFALT, adresserer hvor man skal skrive kommandoer endpoint=03 og hvor man skal hente responsen endpoint=86. Alt som gjenstår er å konvertere kommandoene til hex.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Siden vi allerede har funnet enheten, la oss koble den fra kjernen ...

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

...og skriv til endepunktet med adresse 0x03,

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

... og les deretter svaret fra endepunktet med adresse 0x86.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Strukturert svar:

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

Vi ser disse dataene i dump.pcap.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Flott! Konverter systemstrekkoder til hex. Det er det, treningsfunksjonaliteten er klar.

Hva med fastvaren? Alt ser ut til å være det samme, men det er en nyanse.

Etter å ha tatt en fullstendig dump av blinkingsprosessen, skjønte vi omtrent hva vi hadde å gjøre med. Her er en artikkel om XMODEM, som var svært nyttig for å forstå hvordan denne kommunikasjonen skjer, om enn i generelle termer: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Jeg anbefaler å lese den.

Når du ser på dumpen, kan du se at rammestørrelsen er 1024, og URB-datastørrelsen er 64.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Derfor – 1024/64 – vi får 16 linjer i en blokk, leser fastvarefilen 1 tegn om gangen og danner en blokk. Kompletterer 1 linje i en blokk med spesialtegn fd3e02 + blokknummer.
De neste 14 linjene er supplert med fd25 +, ved hjelp av XMODEM.calc_crc() beregner vi kontrollsummen for hele blokken (det tok mye tid å forstå at “FF – 1” er CSUM) og den siste, 16. linjen er supplert med fd3e.

Det ser ut til at det er det, les fastvarefilen, trykk på blokkene, koble skanneren fra kjernen og send den til enheten. Men det er ikke så enkelt. Skanneren må byttes til fastvaremodus,
отправив ему NEWAPP = ‘\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
Hvor er dette laget fra?? Fra søppelfyllingen.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Men vi kan ikke sende en hel blokk til skanneren på grunn av 64-grensen:

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Vel, skanneren i NEWAPP blinkende modus godtar ikke hex. Derfor må du oversette hver linje 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]

Og send deretter disse dataene til skanneren.

Vi får svaret:

[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]

Hvis du sjekker artikkelen om XMODEM, vil det bli klart: dataene er akseptert.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Etter at alle blokker er overført, fullfører vi overføringen END_TRANSFER = 'xfdx01x04'.

Vel, siden disse blokkene ikke inneholder informasjon for vanlige mennesker, vil vi installere fastvaren i skjult modus som standard. Og bare i tilfelle, vil vi organisere en fremdriftslinje gjennom tqdm.

En oppgave for en utvikler, eller hvordan vi flashet håndholdte skannere uten en leverandør

Da er det faktisk snakk om småting. Alt som gjenstår er å pakke løsningen inn i skript for massereplikering på et klart definert tidspunkt, for ikke å bremse prosessen med å jobbe ved kassen, og legge til logging.

Total

Etter å ha brukt mye tid og krefter og hår på hodet, klarte vi å utvikle de løsningene vi trengte, og holdt også tidsfristen. Samtidig blir skannerne nå reflashet og omskolert sentralt, vi styrer tydelig hele prosessen. Selskapet sparte tid og penger, og vi fikk uvurderlig erfaring med reverseringsutstyr av denne typen.

Kilde: www.habr.com

Legg til en kommentar