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.
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:
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):
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):
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:
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):
En segundo lugar, o formato de paquete XMODEM con soporte CRC16 (XmodemCRC):
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):
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:
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
Seleccione o porto ao que está conectado o dispositivo e o ficheiro onde gardamos o volcado.
Conectamos o escáner a unha máquina onde está instalado o software nativo EZConfigScanning para Windows.
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.
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.
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.
Parece así:
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.
Como xa atopamos o dispositivo, desconectémolo do núcleo...
...e escribe no punto final co enderezo 0x03,
... e despois le a resposta do punto final co enderezo 0x86.
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.
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:
Mirando o volcado, podes ver que o tamaño do cadro é 1024 e o tamaño dos datos URB é 64.
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.
Pero non podemos enviar un bloque completo ao escáner debido ao límite de 64 :
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.
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.
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