Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Olá a todos.

Nós, Viktor Antipov e Ilya Aleshin, falaremos hoje sobre nossa experiência trabalhando com dispositivos USB via Python PyUSB e um pouco sobre engenharia reversa.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Pré-história

Em 2019, o Decreto do Governo da Federação Russa nº 224 “Sobre a aprovação das Regras para rotulagem de produtos de tabaco com meios de identificação e características da implementação de um sistema de informação estatal para monitorar a circulação de mercadorias sujeitas a rotulagem obrigatória com meios de identificação em relação aos produtos do tabaco” entrou em vigor.
O documento explica que a partir de 1º de julho de 2019 os fabricantes são obrigados a rotular cada maço de tabaco. E os distribuidores diretos devem receber esses produtos com a assinatura de um documento de transferência universal (UDD). As lojas, por sua vez, precisam registrar a venda dos produtos etiquetados por meio do caixa.

Além disso, a partir de 1º de julho de 2020, é proibida a circulação de produtos de tabaco não rotulados. Isto significa que todos os maços de cigarros devem ser marcados com um código de barras especial Datamatrix. Além disso - um ponto importante - descobriu-se que o Datamatrix não será comum, mas inverso. Ou seja, não o código preto no branco, mas vice-versa.

Testamos nossos scanners e descobrimos que a maioria deles precisa ser atualizada/treinada novamente, caso contrário, eles simplesmente não serão capazes de funcionar normalmente com este código de barras. Essa reviravolta nos garantiu uma forte dor de cabeça, pois nossa empresa possui muitas lojas espalhadas por um vasto território. Várias dezenas de milhares de caixas registradoras – e muito pouco tempo.

o que era para ser feito? Existem duas opções. Primeiro: os engenheiros no local atualizam e ajustam manualmente os scanners. Segundo: trabalhamos remotamente e, de preferência, cobrimos muitos scanners ao mesmo tempo em uma iteração.

A primeira opção, obviamente, não nos convinha: teríamos que gastar dinheiro com visitas de engenheiros e, neste caso, seria difícil controlar e coordenar o processo. Mas o mais importante é que as pessoas trabalhassem, ou seja, potencialmente teríamos muitos erros e, muito provavelmente, não cumpriríamos o prazo.

A segunda opção é boa para todos, senão para uma coisa. Alguns fornecedores não tinham as ferramentas de atualização remota necessárias para todos os sistemas operacionais necessários. E como os prazos estavam se esgotando, tive que pensar com minha própria cabeça.

A seguir, contaremos como desenvolvemos ferramentas para scanners portáteis para o sistema operacional Debian 9.x (todas as nossas caixas registradoras estão no Debian).

Resolva o enigma: como atualizar um scanner

Relatórios de Victor Antipov.

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

Como nosso sistema alvo é o Debian, instalamos um servidor redirecionador usb no Debian e um cliente redirecionador usb no Windows. Usando utilitários de redirecionamento usb, encaminhamos o scanner de uma máquina Linux para uma máquina Windows.

Um utilitário de um fornecedor do Windows viu o scanner e até o atualizou normalmente. Assim, tiramos a primeira conclusão: nada depende do SO, é uma questão de protocolo de flashing.

OK. Executamos o flash na máquina Windows e removemos o dump na máquina Linux.

Colocamos o despejo no WireShark e... ficamos tristes (vou omitir alguns detalhes do despejo, eles não têm nenhum interesse).

O que o despejo nos mostrou:

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

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

Estávamos interessados ​​na peça 0040-0070.

Nada ficou claro em um quadro de transmissão, exceto os caracteres MOCFT. Esses caracteres acabaram sendo caracteres do arquivo de firmware, bem como os caracteres restantes até o final do quadro (o arquivo de firmware está destacado):

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

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

Observei o seguinte quadro (as informações de serviço foram removidas aqui, o arquivo de firmware foi destacado):

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

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:

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Esse quadro também era estupefato, pois a constante havia mudado (destacada) e, curiosamente, havia parte do arquivo. O tamanho dos bytes transferidos do arquivo mostrou que 1024 bytes foram transferidos. Mais uma vez, não sabia o que significavam os bytes restantes.

Em primeiro lugar, como apelido antigo do BBS, revisei os protocolos de transmissão padrão. Nenhum protocolo transmitiu 1024 bytes. Comecei a estudar o hardware e me deparei com o protocolo 1K Xmodem. Permitia transmitir 1024, mas com uma ressalva: a princípio apenas 128, e somente se não houvesse erros, o protocolo aumentava o número de bytes transmitidos. Imediatamente tive uma transferência de 1024 bytes. Decidi estudar protocolos de transmissão e, especificamente, o modem X.

Havia duas variações do modem.

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

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

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

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

É semelhante, exceto pelo SOH, número do pacote e CRC e comprimento do pacote.

Olhei o início do segundo bloco de transmissão (e vi novamente o arquivo de firmware, mas já recuado em 1024 bytes):

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Vi o cabeçalho familiar fd 3e 02, mas os próximos dois bytes já haviam mudado: era 01 fe e passou a ser 02 fd. Aí notei que o segundo bloco agora estava com o número 02 e assim entendi: na minha frente estava a numeração do bloco de transmissão. A primeira marcha 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 a partir de 0, não de 1. Mas então por que o primeiro bloco é 1 e não 0? Ainda não encontrei a resposta para esta pergunta. Mas entendi como o segundo bloco é contado. 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 despejo confirmou meu palpite.

Então começou a surgir a seguinte imagem da transmissão:

Início da transmissão
fd 3e 02 – Início
01 FE – contador de transmissão
Transferência (34 blocos, 1024 bytes transferidos)
fd 3e 1024 bytes de dados (divididos em blocos de 30 bytes).
Fim da transmissão
fd 25

Os dados restantes serão alinhados a 1024 bytes.

Qual é a aparência do quadro final da transmissão em bloco:

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

fd 25 – sinal para finalizar a transmissão do bloco. Próximo 2f 52 – o restante do arquivo com até 1024 bytes de tamanho. 2f 52, a julgar pelo protocolo, é uma soma de verificação CRC de 16 bits.

Para relembrar os velhos tempos, fiz um programa em C que extraiu 1024 bytes de um arquivo e calculou um CRC de 16 bits. O lançamento do programa mostrou que este não é um CRC de 16 bits. Estupor novamente - por cerca de três dias. Todo esse tempo eu estava tentando entender o que poderia ser, senão uma soma de verificação. Ao estudar 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 C desse cálculo, mas encontrei um site que calculou essa soma de verificação online. Depois de transferir 1024 bytes do meu arquivo para a página da web, o site me mostrou uma soma de verificação que correspondia completamente à soma de verificação do arquivo.

Viva! O último enigma foi resolvido, agora eu precisava fazer meu próprio firmware. Em seguida, passei meu conhecimento (e ele ficou apenas na minha cabeça) para Ilya, que está familiarizado com o poderoso kit de ferramentas Python.

Criando um programa

Ilya Aleshin relata.

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

Por onde começar? Isso mesmo, desde o início.  De fazer um dump da porta USB.

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

Selecione a porta à qual o dispositivo está conectado e o arquivo onde salvaremos o dump.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Conectamos o scanner a uma máquina onde o software nativo EZConfigScanning para Windows está instalado.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Nele encontramos o item para envio de comandos ao aparelho. Mas e as equipes? Onde posso obtê-los?
Ao iniciar o programa, o equipamento é sondado automaticamente (veremos isso um pouco mais tarde). E havia códigos de barras de treinamento de documentos oficiais de equipamentos. PADRÃO. Esta é a nossa equipe.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Os dados necessários foram recebidos. Abra dump.pcap via wireshark.

Bloquear ao iniciar o EZConfigScanning. Os locais aos quais você precisa prestar atenção estão marcados em vermelho.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Vendo tudo isso pela primeira vez, perdi o ânimo. Não está claro onde cavar a seguir.

Um pouco de brainstorming e-e-e... Aha! No lixão Fora - É inE in это Fora.

Pesquisei no Google o que é URB_INTERRUPT. Descobri que este é um método de transferência de dados. E existem 4 métodos: controle, interrupção, isócrono, em massa. Você pode ler sobre eles separadamente.

E os endereços dos endpoints na interface do dispositivo USB podem ser obtidos por meio do comando “lsusb –v” ou usando pyusb.

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

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Parece assim:

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Assim, temos as informações necessárias: os comandos P_INFO. ou DEFALT, endereços onde escrever os comandos endpoint=03 e onde obter a resposta endpoint=86. Resta apenas converter os comandos para hexadecimal.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Como já encontramos o dispositivo, vamos desconectá-lo do kernel...

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

...e escreva no endpoint com endereço 0x03,

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

... e então leia a resposta do endpoint com endereço 0x86.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

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.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Ótimo! Converta códigos de barras do sistema em hexadecimal. É isso, a funcionalidade de treinamento está pronta.

E o firmware? Tudo parece igual, mas há uma nuance.

Depois de analisar completamente o processo de flashing, entendemos aproximadamente com o que estávamos lidando. Aqui está um artigo sobre XMODEM, que foi muito útil para entender como ocorre essa comunicação, ainda que em termos gerais: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Eu recomendo a leitura.

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

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Portanto – 1024/64 – obtemos 16 linhas em um bloco, lemos o arquivo de firmware 1 caractere por vez e formamos 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 para entender que “FF – 1” é CSUM) e a última, 16ª linha é complementada com fd3e.

Parece que é isso, leia o arquivo do firmware, acerte os blocos, desconecte o scanner do kernel e envie para o dispositivo. Mas não é tão simples. O scanner precisa ser colocado no modo firmware,
отправив ему NEWAPP = ‘\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
De onde é esse time?? Do lixão.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Mas não podemos enviar um bloco inteiro para o scanner devido ao limite de 64:

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Bem, o scanner no modo flash NEWAPP não aceita hexadecimal. Portanto, você terá que traduzir 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 então envie esses dados para o scanner.

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 você conferir o artigo sobre XMODEM, ficará claro: os dados foram aceitos.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Após a transferência de todos os blocos, concluímos a transferência END_TRANSFER = 'xfdx01x04'.

Bem, como esses blocos não carregam nenhuma informação para pessoas comuns, instalaremos o firmware em modo oculto por padrão. E, por precaução, organizaremos uma barra de progresso por meio do tqdm.

Uma tarefa para um desenvolvedor ou como atualizamos scanners portáteis sem fornecedor

Na verdade, então é uma questão de pequenas coisas. Resta envolver a solução em scripts para replicação em massa em um horário claramente definido, para não retardar o processo de trabalho nos checkouts, e adicionar log.

Total

Depois de gastar muito tempo, esforço e cabelos na cabeça, conseguimos desenvolver as soluções que precisávamos e também cumprimos o prazo. Ao mesmo tempo, os scanners agora são atualizados e retreinados centralmente, controlamos claramente todo o processo. A empresa economizou tempo e dinheiro e ganhamos uma experiência inestimável em equipamentos de engenharia reversa desse tipo.

Fonte: habr.com

Adicionar um comentário