Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Ola a todos.

Nós, Viktor Antipov e Ilya Aleshin, hoxe falaremos da nosa experiencia traballando con dispositivos USB a través de Python PyUSB e un pouco sobre a enxeñaría inversa.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

prehistoria

En 2019, o Decreto do Goberno da Federación Rusa núm. 224 "Sobre a aprobación das regras para a etiquetaxe dos produtos de tabaco con medios de identificación e as características da implantación dun sistema de información estatal para controlar a circulación de mercadorías suxeitas á etiquetaxe obrigatoria con medios de identificación". en relación cos produtos do tabaco” entrou en vigor.
O documento explica que a partir do 1 de xullo de 2019, os fabricantes están obrigados a etiquetar cada paquete de tabaco. E os distribuidores directos deben recibir estes produtos coa execución dun documento de transferencia universal (UDD). As tendas, pola súa banda, teñen que rexistrar a venda de produtos etiquetados a través da caixa rexistradora.

Así mesmo, a partir do 1 de xullo de 2020 está prohibida a circulación de produtos de tabaco sen etiquetar. Isto significa que todos os paquetes de cigarros deben estar marcados cun código de barras Datamatrix especial. Ademais, un punto importante, resultou que o Datamatrix non será común, senón inverso. É dicir, non código negro sobre branco, senón viceversa.

Probamos os nosos escáneres, e resultou que a maioría deles necesitan ser actualizados/readestrados, se non, simplemente non poden funcionar normalmente con este código de barras. Este xiro de acontecementos garantiunos unha forte dor de cabeza, porque a nosa empresa ten moitas tendas espalladas por un vasto territorio. Varias decenas de miles de caixas rexistradoras, e moi pouco tempo.

Que había que facer? Hai dúas opcións. Primeiro: os enxeñeiros no lugar reinician manualmente e axustan os escáneres. Segundo: traballamos de forma remota e, preferiblemente, cubrimos moitos escáneres á vez nunha soa iteración.

A primeira opción, obviamente, non nos era axeitada: teriamos que gastar cartos en enxeñeiros visitantes, e neste caso sería difícil controlar e coordinar o proceso. Pero o máis importante é que a xente traballe, é dicir, que potencialmente cometemos moitos erros e, moi probablemente, non cumprimos o prazo.

A segunda opción é boa para todos, se non por unha cousa. Algúns provedores non tiñan as ferramentas de flasheo remoto que necesitabamos para todos os sistemas operativos necesarios. E como os prazos se estaban acabando, tiven que pensar coa miña cabeza.

A continuación, contarémosche como desenvolvemos ferramentas para escáneres de man para o sistema operativo Debian 9.x (todas as nosas caixas rexistradoras están en Debian).

Resolve o enigma: como flashear un escáner

Víctor Antipov informa.

A utilidade oficial proporcionada polo vendedor funciona baixo Windows e só con IE. A utilidade pode flashear e configurar o escáner.

Dado que o noso sistema de destino é Debian, instalamos un servidor de redireccionamento USB en Debian e un cliente de redireccionamento USB en Windows. Usando as utilidades de redirección USB, enviamos o escáner dunha máquina Linux a unha máquina Windows.

Unha utilidade dun provedor de Windows viu o escáner e ata o flasheou normalmente. Así, fixemos a primeira conclusión: nada depende do SO, trátase do protocolo de parpadeo.

OK. Executamos o flasheo na máquina Windows e eliminamos o volcado na máquina Linux.

Metemos o vertedoiro en WireShark e... puxémonos tristes (omitirei algúns dos detalles do vertedoiro, non teñen ningún interese).

O que nos amosou o vertedoiro:

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Os enderezos 0000-0030, a xulgar por Wireshark, son información do servizo USB.

Interesábanos a parte 0040-0070.

Nada estaba claro nun marco de transmisión excepto para os caracteres MOCFT. Estes caracteres resultaron ser caracteres do ficheiro de firmware, así como os caracteres restantes ata o final do cadro (o ficheiro de firmware está resaltado):

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

O que significaban os símbolos fd 3e 02 01 fe, eu persoalmente, como Ilya, non tiña nin idea.

Mirei o seguinte cadro (a información do servizo foi eliminada aquí, o ficheiro de firmware destacou):

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Que quedou claro? Que os dous primeiros bytes son unha especie de constante. Todos os bloques posteriores confirmaron isto, pero antes do final do bloque de transmisión:

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Este cadro tamén era estupendo, xa que a constante cambiara (resaltada) e, curiosamente, había parte do ficheiro. O tamaño dos bytes transferidos do ficheiro mostrou que se transferiron 1024 bytes. De novo non sabía o que significaban os bytes restantes.

En primeiro lugar, como antigo alcume de BBS, revisei os protocolos de transmisión estándar. Non se transmitiu ningún protocolo 1024 bytes. Comecei a estudar o hardware e atopeime co protocolo 1K Xmodem. Permitía transmitir 1024, pero cunha salvedade: ao principio só 128, e só se non había erros, o protocolo aumentaba o número de bytes transmitidos. Tiven inmediatamente unha transferencia de 1024 bytes. Decidín estudar os protocolos de transmisión, e concretamente o X-modem.

Había dúas variantes do módem.

En primeiro lugar, o formato do paquete XMODEM con soporte CRC8 (o XMODEM orixinal):

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

En segundo lugar, o formato de paquete XMODEM con soporte CRC16 (XmodemCRC):

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Parece semellante, excepto para SOH, número de paquete e CRC e lonxitude do paquete.

Mirei o comezo do segundo bloque de transmisión (e volvín ver o ficheiro de firmware, pero xa está sangrado por 1024 bytes):

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Vin a cabeceira familiar fd 3e 02, pero os dous bytes seguintes xa cambiaran: era 01 fe e converteuse en 02 fd. Entón notei que o segundo bloque estaba agora numerado 02 e así entendín: diante de min estaba a numeración do bloque de transmisión. A primeira marcha 1024 é 01, a segunda é 02, a terceira é 03 e así por diante (pero en hexadecimal, por suposto). Pero que significa o cambio de fe a fd? Os ollos viron unha diminución de 1, o cerebro recordou que os programadores contaban desde 0, non desde 1. Pero entón por que o primeiro bloque é 1 e non 0? Aínda non atopei a resposta a esta pregunta. Pero entendín como se conta o segundo bloque. O segundo bloque non é máis que FF - (menos) o número do primeiro bloque. Así, o segundo bloque designouse como = 02 (FF-02) = 02 FD. A lectura posterior do vertedoiro confirmou a miña suposición.

Entón comezou a aparecer a seguinte imaxe da transmisión:

Inicio da transmisión
fd 3e 02 – Comezo
01 FE – contador de transmisión
Transferencia (34 bloques, 1024 bytes transferidos)
fd 3e 1024 bytes de datos (divididos en bloques de 30 bytes).
Fin da transmisión
fd 25

Os datos restantes deben aliñarse a 1024 bytes.

Como é o cadro final de transmisión do bloque:

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

fd 25 – sinal para finalizar a transmisión do bloque. Seguinte 2f 52: o resto do ficheiro ten un tamaño de ata 1024 bytes. 2f 52, a xulgar polo protocolo, é unha suma de verificación CRC de 16 bits.

Polo amor dos vellos tempos, fixen un programa en C que extraía 1024 bytes dun ficheiro e calculou un CRC de 16 bits. O lanzamento do programa demostrou que este non é un CRC de 16 bits. Estupor de novo - durante uns tres días. Durante todo este tempo tratei de entender o que podía ser, se non unha suma de verificación. Mentres estudaba sitios en inglés, descubrín que o X-modem usa o seu propio cálculo de suma de verificación: CRC-CCITT (XModem). Non atopei ningunha implementación C deste cálculo, pero atopei un sitio que calculou esta suma de verificación en liña. Tras transferir 1024 bytes do meu ficheiro á páxina web, o sitio mostroume unha suma de comprobación que coincidía completamente coa suma de comprobación do ficheiro.

Hurra! O último enigma estaba resolto, agora necesitaba facer o meu propio firmware. A continuación, pasei os meus coñecementos (e quedou só na miña cabeza) a Ilya, que está familiarizado co poderoso conxunto de ferramentas Python.

Creando un programa

Ilya Aleshin informa.

Despois de recibir as instrucións axeitadas, quedei moi "feliz".

Por onde comezar? Así é, dende o principio.  De facer un volcado do porto USB.

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

Seleccione o porto ao que está conectado o dispositivo e o ficheiro onde gardamos o volcado.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Conectamos o escáner a unha máquina onde está instalado o software nativo EZConfigScanning para Windows.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Nel atopamos o elemento para enviar comandos ao dispositivo. Pero que pasa cos equipos? Onde podo conseguilos?
Cando se inicia o programa, o equipo é interrogado automaticamente (verémolo un pouco máis adiante). E había códigos de barras de adestramento dos documentos oficiais do equipamento. DEFALT. Este é o noso equipo.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Recibíronse os datos necesarios. Abre dump.pcap mediante wireshark.

Bloquear ao iniciar EZConfigScanning. Os lugares aos que debes prestar atención están marcados en vermello.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Ao ver todo isto por primeira vez, perdín o ánimo. Non está claro onde cavar a continuación.

Unha pequena chuvia de ideas e-e-e... Ai! No vertedoiro fóra - é inE in este fóra.

Busquei en Google o que é URB_INTERRUPT. Descubrín que este é un método de transferencia de datos. E hai 4 métodos deste tipo: control, interrupción, isócrono, masivo. Podes ler sobre eles por separado.

E os enderezos dos puntos finais na interface do dispositivo USB pódense obter mediante o comando "lsusb –v" ou mediante pyusb.

Agora necesitamos atopar todos os dispositivos con este VID. Podes buscar especificamente por VID:PID.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Parece así:

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Así, temos a información necesaria: os comandos P_INFO. ou DEFALT, enderezos onde escribir comandos endpoint=03 e onde obter a resposta endpoint=86. Todo o que queda é converter os comandos a hexadecimal.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Como xa atopamos o dispositivo, desconectémolo do núcleo...

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

...e escribe no punto final co enderezo 0x03,

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

... e despois le a resposta do punto final co enderezo 0x86.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Resposta estruturada:

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

Vemos estes datos en dump.pcap.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Genial! Converte códigos de barras do sistema a hexadecimal. Isto é todo, a funcionalidade de adestramento está lista.

E o firmware? Todo parece ser igual, pero hai un matiz.

Despois de verter completamente o proceso de intermitencia, entendemos aproximadamente o que estabamos a tratar. Aquí tes un artigo sobre XMODEM, que foi moi útil para entender como se produce esta comunicación, aínda que en termos xerais: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Recomendo a súa lectura.

Mirando o volcado, podes ver que o tamaño do cadro é 1024 e o tamaño dos datos URB é 64.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Polo tanto - 1024/64 – obtemos 16 liñas nun bloque, lemos o ficheiro de firmware 1 carácter á vez e formamos un bloque. Complementando 1 liña nun bloque con caracteres especiais fd3e02 + número de bloque.
As seguintes 14 liñas complétanse con fd25 +, usando XMODEM.calc_crc() calculamos a suma de comprobación de todo o bloque (levou moito tempo entender que "FF - 1" é CSUM) e a última liña 16 complétase con fd3e.

Parece que é iso, le o ficheiro de firmware, golpea os bloques, desconecta o escáner do núcleo e envíao ao dispositivo. Pero non é tan sinxelo. O escáner debe cambiarse ao modo de firmware,
отправив ему NEWAPP = ‘\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
De onde é este equipo?? Do vertedoiro.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Pero non podemos enviar un bloque completo ao escáner debido ao límite de 64 :

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Ben, o escáner no modo intermitente NEWAPP non acepta hexadecimal. Polo tanto, terás que traducir cada liña 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 despois enviar estes datos ao escáner.

Obtemos a resposta:

[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 consultas o artigo sobre XMODEM, quedará claro: os datos foron aceptados.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

Despois de transferir todos os bloques, completamos a transferencia END_TRANSFER = 'xfdx01x04'.

Pois ben, dado que estes bloques non levan información para a xente común, instalaremos o firmware en modo oculto por defecto. E por se acaso, organizaremos unha barra de progreso a través de tqdm.

Unha tarefa para un programador, ou como mostramos escáneres de man sen un vendedor

En realidade, entón é cuestión de pequenas cousas. Só queda envolver a solución en scripts para a replicación masiva nun momento claramente definido, para non ralentizar o proceso de traballo nas caixas e engadir rexistros.

Total

Despois de dedicar moito tempo, esforzo e cabelo na cabeza, puidemos desenvolver as solucións que necesitábamos, e tamén cumprimos o prazo. Ao mesmo tempo, os escáneres están agora actualizados e adestrados de forma centralizada, controlamos claramente todo o proceso. A empresa aforrou tempo e diñeiro, e adquirimos unha experiencia inestimable en equipos de enxeñería inversa deste tipo.

Fonte: www.habr.com

Engadir un comentario