Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Bonjour.

Nous, Viktor Antipov et Ilya Aleshin, parlerons aujourd'hui de notre expérience de travail avec des périphériques USB via Python PyUSB et un peu de l'ingénierie inverse.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Préhistoire

En 2019, décret du gouvernement de la Fédération de Russie n° 224 « sur l'approbation des règles d'étiquetage des produits du tabac avec des moyens d'identification et les caractéristiques de la mise en œuvre d'un système d'information d'État pour surveiller la circulation des marchandises soumises à un étiquetage obligatoire avec des moyens d'identification concernant les produits du tabac» est entrée en vigueur.
Le document explique qu'à partir du 1er juillet 2019, les fabricants sont tenus d'étiqueter chaque paquet de tabac. Et les distributeurs directs doivent recevoir ces produits avec l'exécution d'un document de transfert universel (UDD). Les magasins, à leur tour, doivent enregistrer la vente de produits étiquetés via la caisse enregistreuse.

Aussi, à partir du 1er juillet 2020, la circulation des produits du tabac sans étiquette est interdite. Cela signifie que tous les paquets de cigarettes doivent être marqués d'un code-barres Datamatrix spécial. De plus - point important - il s'est avéré que le Datamatrix ne sera pas ordinaire, mais inverse. Autrement dit, pas de code noir sur blanc, mais vice versa.

Nous avons testé nos scanners et il s'est avéré que la plupart d'entre eux doivent être reflashésés/recyclés, sinon ils ne sont tout simplement pas capables de fonctionner normalement avec ce code-barres. Cette tournure des événements nous a assuré un sérieux casse-tête, car notre entreprise possède de nombreux magasins dispersés sur un vaste territoire. Plusieurs dizaines de milliers de caisses enregistreuses – et très peu de temps.

Que fallait-il faire ? Il existe deux options. Premièrement : les ingénieurs sur site reflasher et ajustent manuellement les scanners. Deuxièmement : nous travaillons à distance et, de préférence, couvrons plusieurs scanners à la fois en une seule itération.

La première option, évidemment, ne nous convenait pas : nous devions dépenser de l'argent en visites d'ingénieurs, et dans ce cas, il serait difficile de contrôler et de coordonner le processus. Mais le plus important est que les gens travaillent, c'est-à-dire que nous aurions potentiellement beaucoup d'erreurs et, très probablement, ne respecterions pas les délais.

La deuxième option est bonne pour tout le monde, voire pour une chose. Certains fournisseurs ne disposaient pas des outils de flashage à distance dont nous avions besoin pour tous les systèmes d'exploitation requis. Et comme les délais étaient comptés, j'ai dû réfléchir avec ma propre tête.

Nous vous expliquerons ensuite comment nous avons développé des outils pour scanners portables pour le système d'exploitation Debian 9.x (toutes nos caisses enregistreuses sont sur Debian).

Résolvez l'énigme : comment flasher un scanner

Victor Antipov rapporte.

L'utilitaire officiel fourni par le fournisseur fonctionne sous Windows et uniquement avec IE. L'utilitaire peut flasher et configurer le scanner.

Puisque notre système cible est Debian, nous avons installé un serveur de redirecteur USB sur Debian et un client de redirecteur USB sous Windows. À l'aide des utilitaires de redirection USB, nous avons transféré le scanner d'une machine Linux vers une machine Windows.

Un utilitaire d'un fournisseur Windows a vu le scanner et l'a même flashé normalement. Ainsi, nous avons tiré la première conclusion : rien ne dépend de l’OS, c’est une question de protocole de flashage.

D'ACCORD. Nous avons exécuté le flashage sur la machine Windows et supprimé le dump sur la machine Linux.

Nous avons mis le dump dans WireShark et... sommes devenus tristes (je vais omettre certains détails du dump, ils n'ont aucun intérêt).

Ce que la décharge nous a montré :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Les adresses 0000-0030, à en juger par Wireshark, sont des informations sur le service USB.

Nous étions intéressés par la pièce 0040-0070.

Rien n'était clair sur une trame de transmission, à l'exception des caractères MOCFT. Ces caractères se sont avérés être des caractères du fichier du firmware, ainsi que les caractères restants jusqu'à la fin de la trame (le fichier du firmware est mis en surbrillance) :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Ce que signifiaient les symboles fd 3e 02 01 fe, personnellement, comme Ilya, n'en avais aucune idée.

J'ai regardé le cadre suivant (les informations de service ont été supprimées ici, le fichier du firmware a été mis en surbrillance) :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Qu’est-ce qui est devenu clair ? Que les deux premiers octets sont une sorte de constante. Tous les blocs suivants l'ont confirmé, mais avant la fin du bloc de transmission :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Ce cadre était également stupéfiant, puisque la constante avait changé (mis en surbrillance) et, curieusement, il y avait une partie du fichier. La taille des octets transférés du fichier a montré que 1024 octets ont été transférés. Encore une fois, je ne savais pas ce que signifiaient les octets restants.

Tout d’abord, en tant qu’ancien surnom du BBS, j’ai passé en revue les protocoles de transmission standard. Aucun protocole n'a transmis 1024 octets. J'ai commencé à étudier le matériel et suis tombé sur le protocole 1K Xmodem. Il permettait d'en transmettre 1024, mais avec une mise en garde : au début seulement 128, et seulement s'il n'y avait pas d'erreurs, le protocole augmentait le nombre d'octets transmis. J'ai immédiatement eu un transfert de 1024 octets. J'ai décidé d'étudier les protocoles de transmission, et plus particulièrement le X-modem.

Il y avait deux variantes du modem.

Tout d’abord, le format du package XMODEM avec prise en charge CRC8 (le XMODEM d’origine) :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Deuxièmement, le format de paquet XMODEM avec prise en charge CRC16 (XmodemCRC) :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Cela semble similaire, à l'exception du SOH, du numéro de package, du CRC et de la longueur du package.

J'ai regardé le début du deuxième bloc de transmission (et j'ai de nouveau vu le fichier du firmware, mais déjà en retrait de 1024 octets) :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

J'ai vu l'en-tête familier fd 3e 02, mais les deux octets suivants avaient déjà changé : c'était 01 fe et sont devenus 02 fd. Puis j'ai remarqué que le deuxième bloc était désormais numéroté 02 et j'ai ainsi compris : devant moi se trouvait la numérotation du bloc de transmission. Le premier rapport 1024 est le 01, le deuxième est le 02, le troisième est le 03 et ainsi de suite (mais en hexadécimal, bien sûr). Mais que signifie le passage de fe à fd ? Les yeux ont vu une diminution de 1, le cerveau a rappelé que les programmeurs comptent à partir de 0 et non de 1. Mais alors pourquoi le premier bloc est-il à 1, et non à 0 ? Je n'ai toujours pas trouvé la réponse à cette question. Mais j'ai compris comment le deuxième bloc est compté. Le deuxième bloc n’est rien de plus que FF – (moins) le numéro du premier bloc. Ainsi, le deuxième bloc a été désigné comme = 02 (FF-02) = 02 FD. La lecture ultérieure du dump a confirmé ma supposition.

Puis l’image suivante de la transmission a commencé à émerger :

Début de transmission
fd 3e 02 – Début
01 FE – compteur de transmission
Transfert (34 blocs, 1024 octets transférés)
fd 3e 1024 octets de données (divisés en blocs de 30 octets).
Fin de transmission
jour 25

Les données restantes doivent être alignées sur 1024 octets.

À quoi ressemble la trame de fin de transmission du bloc :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

fd 25 – signal pour terminer la transmission du bloc. Next 2f 52 – le reste du fichier jusqu’à 1024 octets. 2f 52, à en juger par le protocole, est une somme de contrôle CRC de 16 bits.

Pour le bon vieux temps, j'ai créé un programme en C qui extrayait 1024 octets d'un fichier et calculait un CRC de 16 bits. Le lancement du programme a montré qu'il ne s'agit pas d'un CRC 16 bits. Stupeur à nouveau - pendant environ trois jours. Pendant tout ce temps, j'essayais de comprendre ce que cela pouvait être, sinon une somme de contrôle. En étudiant des sites en anglais, j'ai découvert que le X-modem utilise son propre calcul de somme de contrôle - CRC-CCITT (XModem). Je n'ai trouvé aucune implémentation C de ce calcul, mais j'ai trouvé un site qui calculait cette somme de contrôle en ligne. Après avoir transféré 1024 octets de mon fichier vers la page Web, le site m'a montré une somme de contrôle qui correspondait complètement à la somme de contrôle du fichier.

Hourra! La dernière énigme était résolue, je devais maintenant créer mon propre firmware. Ensuite, j'ai transmis mes connaissances (et elles ne sont restées que dans ma tête) à Ilya, qui connaît la puissante boîte à outils Python.

Création d'un programme

Ilya Aleshin rapporte.

Ayant reçu les instructions appropriées, j’étais très « heureux ».

Où commencer? C'est vrai, depuis le début.  En effectuant un dump depuis le port USB.

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

Sélectionnez le port auquel l'appareil est connecté et le fichier dans lequel nous enregistrerons le dump.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Nous connectons le scanner à une machine sur laquelle est installé le logiciel natif EZConfigScanning pour Windows.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Nous y trouvons l'élément permettant d'envoyer des commandes à l'appareil. Mais qu’en est-il des équipes ? Où puis-je les obtenir?
Au démarrage du programme, l'équipement est interrogé automatiquement (nous le verrons un peu plus tard). Et il y avait des codes-barres de formation provenant des documents officiels d'équipement. DÉFAUT. C'est notre équipe.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Les données nécessaires ont été reçues. Ouvrez dump.pcap via Wireshark.

Bloquer au démarrage d'EZConfigScanning. Les endroits auxquels vous devez faire attention sont marqués en rouge.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

En voyant tout cela pour la première fois, j'ai perdu courage. On ne sait pas où creuser ensuite.

Un petit brainstorming et-et-et... Aha ! Dans la décharge ande - Est inEt in это ande.

J'ai cherché sur Google ce qu'est URB_INTERRUPT. J'ai découvert qu'il s'agissait d'une méthode de transfert de données. Et il existe 4 méthodes de ce type : contrôle, interruption, isochrone, masse. Vous pouvez les lire séparément.

Et les adresses des points de terminaison dans l'interface du périphérique USB peuvent être obtenues soit via la commande « lsusb –v » soit en utilisant pyusb.

Nous devons maintenant trouver tous les appareils dotés de ce VID. Vous pouvez effectuer une recherche spécifiquement par VID:PID.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Cela ressemble à ceci:

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Nous disposons donc des informations nécessaires : les commandes P_INFO. ou DEFALT, adresses où écrire les commandes endpoint=03 et où obtenir la réponse endpoint=86. Il ne reste plus qu'à convertir les commandes en hexadécimal.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Puisque nous avons déjà trouvé le périphérique, déconnectons-le du noyau...

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

...et écrivez sur le point final avec l'adresse 0x03,

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

... puis lisez la réponse du point de terminaison avec l'adresse 0x86.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Réponse structurée :

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

Nous voyons ces données dans dump.pcap.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Super! Convertissez les codes-barres du système en hexadécimal. Ça y est, la fonctionnalité de formation est prête.

Et le firmware ? Tout semble pareil, mais il y a une nuance.

Après avoir complètement vidé le processus de flashage, nous avons à peu près compris à quoi nous avions affaire. Voici un article sur XMODEM, qui a été très utile pour comprendre comment cette communication se produit, bien qu'en termes généraux : http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Je recommande de le lire.

En regardant le dump, vous pouvez voir que la taille de la trame est de 1024 et la taille des données URB est de 64.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Donc – 1024/64 – nous obtenons 16 lignes dans un bloc, lisons le fichier du firmware 1 caractère à la fois et formons un bloc. Compléter 1 ligne dans un bloc avec des caractères spéciaux fd3e02 + numéro de bloc.
Les 14 lignes suivantes sont complétées par fd25 +, en utilisant XMODEM.calc_crc() nous calculons la somme de contrôle de tout le bloc (il a fallu beaucoup de temps pour comprendre que « FF – 1 » est CSUM) et la dernière, 16ème ligne est complétée avec fd3e.

Il semblerait que ce soit tout, lisez le fichier du firmware, frappez les blocs, déconnectez le scanner du noyau et envoyez-le à l'appareil. Mais ce n'est pas si simple. Le scanner doit être basculé en mode firmware,
отправив ему NEWAPP = ‘\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
D'où vient cette équipe ?? De la décharge.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Mais nous ne pouvons pas envoyer un bloc entier au scanner en raison de la limite de 64 :

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Eh bien, le scanner en mode clignotant NEWAPP n'accepte pas l'hexadécimal. Vous devrez donc traduire chaque ligne 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]

Et puis envoyez ces données au scanner.

Nous obtenons la réponse :

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

Si vous consultez l'article sur XMODEM, cela deviendra clair : les données ont été acceptées.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

Une fois tous les blocs transférés, nous terminons le transfert END_TRANSFER = 'xfdx01x04'.

Eh bien, puisque ces blocs ne contiennent aucune information pour les gens ordinaires, nous installerons le firmware en mode caché par défaut. Et juste au cas où, nous organiserons une barre de progression via tqdm.

Une tâche pour le développeur, ou comment nous avons flashé des scanners portables sans fournisseur

En fait, c’est une question de petites choses. Il ne reste plus qu'à envelopper la solution dans des scripts de réplication massive à un moment clairement défini, afin de ne pas ralentir le processus de travail aux caisses, et d'ajouter une journalisation.

Total

Après avoir consacré beaucoup de temps, d'efforts et de cheveux sur la tête, nous avons pu développer les solutions dont nous avions besoin, tout en respectant les délais. Dans le même temps, les scanners sont désormais reflashésés et recyclés de manière centralisée, nous contrôlons clairement l'ensemble du processus. L’entreprise a économisé du temps et de l’argent et nous avons acquis une expérience inestimable dans l’ingénierie inverse d’équipements de ce type.

Source: habr.com

Ajouter un commentaire