A tarefa do desenvolvedor ou como digitalizamos os scanners manuais sem um fornecedor

Olá a todos.

Hoje, Victor Antipov e Ilya Aleshin, falaremos sobre nossa experiência com dispositivos USB através do Python PyUSB e um pouco sobre engenharia reversa.



fundo


Em 2019, entrou em vigor o Decreto do Governo da Federação Russa n.o 224, “Aprovação das regras de rotulagem de produtos de tabaco por meio de identificação e das especificidades da introdução de um sistema de informação estadual para monitorar a circulação de mercadorias sujeitas a rotulagem obrigatória por meio de identificação em relação a produtos de tabaco”.
O documento explica que, a partir de 1 de julho de 2019, os fabricantes devem rotular cada embalagem de tabaco. E os distribuidores diretos devem receber esses produtos com o design de um documento de transferência universal (UPD). As lojas, por sua vez, precisam registrar a venda de produtos rotulados por meio da caixa registradora.

Além disso, a partir de 1º de julho de 2020, produtos de tabaco não marcados são proibidos. Isso significa que todos os maços de cigarro devem ser etiquetados com um código de barras especial Datamatrix. E - um ponto importante - aconteceu que o Datamatrix não será comum, mas inverso. Ou seja, não um código preto no branco, mas vice-versa.

Testamos nossos scanners, e verificou-se que a maioria deles precisa ser reflorestada / reciclada, caso contrário, eles simplesmente não conseguem trabalhar normalmente com esse código de barras. Essa reviravolta nos garantiu uma forte dor de cabeça, porque nossa empresa possui muitas lojas espalhadas por um vasto território. Várias dezenas de milhares de mesas de dinheiro - e com muito pouco tempo.

o que era para ser feito? Existem duas opções. Primeiro: os engenheiros das instalações realizam reflash manualmente e ajustam os scanners. Segundo: trabalhamos remotamente e, de preferência, cobrimos muitos scanners de uma só vez em uma iteração.

A primeira opção, obviamente, não nos convinha: teríamos de gastar dinheiro em viagens de campo de engenheiros, e é difícil controlar e coordenar o processo nesse caso. Mas o mais importante é que as pessoas funcionariam, ou seja, potencialmente teríamos muitos erros e, muito provavelmente, não caberiam no prazo.

A segunda opção é boa para todos, se não para um, mas. Alguns fornecedores não tinham as ferramentas intermitentes remotas necessárias para todos os sistemas operacionais necessários. E como os prazos estavam acabando, eu tive que pensar com minha própria cabeça.

A seguir, descreveremos como desenvolvemos ferramentas para scanners de mão para o sistema operacional Debian 9.x (temos todas as bilheterias do Debian).

:


Diz Victor Antipov.

O utilitário oficial fornecido pelo fornecedor funciona no Windows e somente no IE. O utilitário pode piscar e configurar o scanner.

Como o sistema de destino é o Debian, instalamos o servidor de redirecionador usb no servidor Debian e o cliente de redirecionador usb no Windows. Usando os utilitários do redirecionador usb, o scanner foi encaminhado da máquina Linux para a máquina Windows.

O utilitário do fornecedor do Windows viu o scanner e até piscou normalmente. Assim, a primeira conclusão foi feita: nada depende do sistema operacional, o assunto está no protocolo intermitente.

ESTÁ BEM. Um piscar foi iniciado em uma máquina Windows e um despejo foi removido em uma máquina Linux.

Eles colocaram o despejo no WireShark e ... ficaram tristes (omitirei parte dos detalhes do despejo, eles não têm interesse).

Que despejo nos mostrou:





Os endereços 0000-0030, a julgar pelo Wireshark, são informações de serviço USB.

Estávamos interessados ​​na parte 0040-0070.

Nada ficou claro em um quadro de transmissão, exceto os caracteres MOCFT. Esses símbolos acabaram sendo símbolos do arquivo de firmware, bem como o restante dos símbolos até o final do quadro (o arquivo de firmware é destacado):



O que os símbolos fd 3e 02 01 fe significam, eu pessoalmente, como Ilya, não fazia ideia.

Olhei para o próximo quadro (as informações de serviço são excluídas aqui, o arquivo de firmware é destacado):



O que ficou claro? Que os dois primeiros bytes são algum tipo de constante. Todos os blocos subsequentes confirmaram isso, mas antes do final do bloco de transmissão:



Esse quadro também entrou em estupor, uma vez que a constante foi alterada (destacada) e, estranhamente, havia uma parte do arquivo. O tamanho dos bytes transmitidos do arquivo indica que 1024 bytes foram transferidos. O que os bytes restantes significavam - eu não sabia novamente.

Primeiro de tudo, como um antigo apelido do BBS, revisei os protocolos de transferência padrão. 1024 bytes, nenhum protocolo foi passado. Ele começou a estudar o material e encontrou o protocolo 1K Xmodem. Permitiu transmitir 1024, mas com uma nuance: a princípio apenas 128, e somente na ausência de erros o protocolo aumentou o número de bytes transmitidos. Eu imediatamente tive uma transmissão de 1024 bytes. Decidi estudar os protocolos de transmissão e, especificamente, o X-modem.

Havia duas variações do modem.

Primeiro, o formato do pacote XMODEM com suporte a CRC8 (XMODEM original):



Em segundo lugar, o formato de pacote XMODEM com suporte a CRC16 (XmodemCRC):



É semelhante, com exceção de SOH, número de pacote e CRC e o tamanho do pacote.

Olhei para o início do segundo bloco de transmissão (e vi novamente o arquivo do firmware, mas com um recuo de 1024 bytes):



Eu vi o cabeçalho familiar fd 3e 02, mas os próximos dois bytes já foram alterados: era 01 fe e se tornou 02 fd. Então eu notei que o segundo bloco agora está numerado 02 e assim entendido: na minha frente está a numeração do bloco de transmissão. A primeira transmissão 1024 é 01, a segunda 02, a terceira 03 e assim por diante (mas em hexadecimal, é claro). Mas o que significa a mudança de fe para fd? Os olhos viram uma diminuição de 1, o cérebro lembrou que os programadores contam de 0, não de 1. Mas então por que o primeiro bloco 1, não 0? Não encontrei a resposta para esta pergunta. Mas eu entendi como o segundo bloco é considerado. O segundo bloco nada mais é do que FF - (menos) o número do primeiro bloco. Assim, o segundo bloco foi designado como = 02 (FF-02) = 02 FD. A leitura subsequente do lixão confirmou meu palpite.

Em seguida, a seguinte imagem do programa começou a surgir:

O início do programa
fd 3e 02 - Início
01 FE - contador de transmissão
Transmissão (34 blocos, 1024 bytes são transmitidos)
fd 3e 1024 bytes de dados (divididos em blocos de 30 bytes).
Fim da transmissão
fd 25

Restos de dados para alinhar a 1024 bytes.

Como é o quadro final da transferência de blocos:



fd 25 - sinal para o final da transferência de blocos. Próximo 2f 52 - os restos do arquivo até 1024 bytes. 2f 52, a julgar pelo protocolo, é uma soma de verificação CRC de 16 bits.

Com base na memória antiga, criei um programa em C que extraía 1024 bytes de um arquivo e lia o CRC de 16 bits. O lançamento do programa mostrou que este não é um CRC de 16 bits. Novamente estupor - por cerca de três dias. Durante todo esse tempo, tentei entender o que poderia ser, se não uma soma de verificação. Estudando sites em inglês, descobri que o modem X usa seu próprio cálculo de soma de verificação - CRC-CCITT (XModem). Não encontrei nenhuma implementação em C para esse cálculo, mas encontrei um site que lia essa soma de verificação online. Ao carregar 1024 bytes do meu arquivo na página da web, o site me mostrou uma soma de verificação que coincidia completamente com a soma de verificação do arquivo.

Viva! O último enigma foi resolvido, agora você tinha que criar seu próprio firmware. Depois, transferi meu conhecimento (e eles permaneceram apenas na minha cabeça) para Ilya, que conhece ferramentas poderosas - Python.

Criação de programa


Narrado por Ilya Aleshin.

Tendo recebido as instruções apropriadas, fiquei muito "feliz".

Por onde começar? Certo, desde o começo. Dumping Ao descarregar de uma porta USB.

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

Escolha a porta à qual o dispositivo está conectado e o arquivo em que salvaremos o despejo.



Conectamos o scanner à máquina em que o software EZConfigScanning nativo para Windows está instalado.



Nele encontramos o ponto de enviar comandos para o dispositivo. Mas e as equipes? Onde consegui-los?
Quando o programa inicia, o equipamento é interrogado automaticamente (veremos isso um pouco mais tarde). E havia códigos de barras de treinamento a partir de documentos oficiais do equipamento. DEFALTO. Esta é a nossa equipe.



Os dados necessários são recebidos. Abra o dump.pcap através do wireshark.

Bloquear na inicialização do EZConfigScanning. Os pontos vermelhos são lugares para prestar atenção.





Vendo tudo isso pela primeira vez, eu perdi o coração. Onde cavar mais ainda não está claro.

Um pouco de brainstorming e-e-e ... Aha! Em um despejo, out está dentro e in está fora .

Pesquisou o que é URB_INTERRUPT. Descobriu que este é um método de transferência de dados. E existem 4 métodos: controle, interrupção, isócrono, a granel. Você pode ler sobre eles separadamente.

E os endereços dos terminais na interface do dispositivo USB podem ser obtidos pelo comando "lsusb –v" ou por meio do pyusb.

Agora você precisa encontrar todos os dispositivos com este VID. Você pode pesquisar especificamente por VID: PID.



Se parece com isso:





Portanto, temos as informações necessárias: comandos P_INFO. ou DEFALT, endereços onde escrever os comandos endpoint = 03 e onde obter o endpoint de resposta = 86. Resta apenas traduzir os comandos em hexadecimal.





Como já encontramos o dispositivo, desconecte-o do kernel ...



... e



grave no terminal com o endereço 0x03, ... e depois leia a resposta do terminal com o endereço 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 esses dados em dump.pcap.







Bem! Traduzimos códigos de barras do sistema para hexadecimal. Tudo, a funcionalidade de treinamento está pronta.

O que fazer com o firmware? Parece que tudo é igual, mas há uma nuance.

Depois de remover um despejo completo do processo de piscar, entendemos mais ou menos com o que estávamos lidando. Aqui está um artigo sobre o XMODEM que realmente ajudou a entender como essa comunicação acontece, embora em termos gerais: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Eu recomendo a leitura.

Olhando no dump, você pode ver que o tamanho do quadro é 1024 e o tamanho dos dados URB é 64.



Portanto, 1024/64, obtemos 16 linhas em um bloco, lemos o arquivo de firmware por 1 caractere e formam um bloco. Complementando 1 linha em um bloco com caracteres especiais fd3e02 + número do bloco.
As próximas 14 linhas são complementadas com fd25 +, usando XMODEM.calc_crc () calculamos a soma de verificação de todo o bloco (demorou muito tempo para entender que “FF - 1” é CSUM) e a última 16ª linha é complementada com fd3e.

Parece que tudo, leia o arquivo de firmware, atinja os blocos, desconecte o scanner do kernel e envie-o para o dispositivo. Mas não é tão simples. O scanner deve ser colocado no modo de firmware
enviando NEWAPP = '\\ xfd \\ x0a \\ x16 \\ x4e \\ x2c \\ x4e \\ x45 \\ x57 \\ x41 \\ x50 \\ x50 \\ x0d'.
De onde vem esse comando? Do lixão.



Mas não podemos enviar o bloco inteiro para o scanner devido à restrição de 64:



Bem, o scanner no modo intermitente NEWAPP também não aceita hexadecimal. Portanto, é necessário converter cada linha 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 já envie esses dados para o scanner.

Temos 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 você verificar o artigo sobre o XMODEM, fica claro: os dados foram aceitos.



Após a transferência de todos os blocos, concluímos a transferência END_TRANSFER = '\ xfd \ x01 \ x04'.

Bem, como esses blocos não carregam informações para pessoas comuns, tornaremos o firmware no modo oculto por padrão. E por precaução, através do tqdm, organizaremos uma barra de progresso.



Na verdade, o resto é pequeno. Resta apenas agrupar a solução em scripts para replicação em massa em um horário claramente definido, para não desacelerar o processo de trabalho nas bilheterias e adicionar log.

Total


Depois de gastar muito tempo, energia e cabelos na cabeça , fomos capazes de desenvolver as soluções de que precisávamos, além disso, cumprimos o prazo. Ao mesmo tempo, os scanners são remarcados e retreinados agora centralmente, controlamos claramente todo o processo. A empresa economizou tempo e dinheiro e adquirimos uma experiência inestimável em engenharia reversa desse tipo de equipamento.

All Articles