Задача за разработчик или как флашнахме ръчни скенери без доставчик

Здравейте на всички.

Ние, Виктор Антипов и Иля Алешин, днес ще говорим за нашия опит в работата с USB устройства чрез Python PyUSB и малко за обратното инженерство.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

праистория

През 2019 г. Указ на правителството на Руската федерация № 224 „За одобряване на Правилата за етикетиране на тютюневи изделия с идентификационни средства и характеристики на прилагането на държавна информационна система за наблюдение на движението на стоки, подлежащи на задължително етикетиране с идентификационни средства по отношение на тютюневите изделия” влезе в сила.
В документа се пояснява, че от 1 юли 2019 г. производителите са длъжни да етикетират всяка опаковка тютюн. И директните дистрибутори трябва да получат тези продукти с изпълнението на универсален документ за прехвърляне (UDD). Магазините от своя страна трябва да регистрират продажбата на етикетирани продукти през касовия апарат.

Също така от 1 юли 2020 г. се забранява движението на неетикетирани тютюневи изделия. Това означава, че всички цигарени кутии трябва да бъдат маркирани със специален баркод Datamatrix. Освен това - важен момент - оказа се, че Datamatrix няма да е обикновен, а инверсен. Тоест не черен код върху бяло, а обратното.

Тествахме нашите скенери и се оказа, че повечето от тях трябва да бъдат препрограмирани/обучени, в противен случай просто не могат да работят нормално с този баркод. Този развой на събитията ни гарантира силно главоболие, тъй като нашата компания има много магазини, които са разпръснати на огромна територия. Няколко десетки хиляди касови апарата – и много малко време.

Какво трябваше да се направи? Има две възможности. Първо: инженерите на място ръчно презареждат и настройват скенерите. Второ: ние работим дистанционно и, за предпочитане, покриваме много скенери наведнъж в една итерация.

Първият вариант очевидно не беше подходящ за нас: ще трябва да харчим пари за посещение на инженери и в този случай ще бъде трудно да контролираме и координираме процеса. Но най-важното е, че хората ще работят, тоест потенциално ще получим много грешки и най-вероятно няма да спазим срока.

Вторият вариант е добър за всички, ако не и за едно нещо. Някои доставчици не разполагаха с инструментите за дистанционно мигане, от които се нуждаехме за всички необходими операционни системи. И тъй като сроковете изтичаха, трябваше да мисля със собствената си глава.

След това ще ви разкажем как разработихме инструменти за ръчни скенери за Debian 9.x OS (всичките ни касови апарати са на Debian).

Решете загадката: как да флашнете скенер

Разказва Виктор Антипов.

Официалната помощна програма, предоставена от доставчика, работи под Windows и само с IE. Помощната програма може да мига и да конфигурира скенера.

Тъй като нашата целева система е Debian, инсталирахме сървър за usb-пренасочване на Debian и клиент за usb-пренасочване на Windows. Използвайки помощните програми за usb-пренасочване, ние пренасочихме скенера от Linux машина към Windows машина.

Помощна програма от доставчик на Windows видя скенера и дори го флашна нормално. Така направихме първото заключение: нищо не зависи от операционната система, това е въпрос на мигащ протокол.

ДОБРЕ. Изпълнихме мигането на машината с Windows и премахнахме дъмпа на машината с Linux.

Напъхахме дъмпа в WireShark и... се натъжихме (ще пропусна някои от подробностите за дъмпа, не представляват интерес).

Какво ни показа сметището:

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Адреси 0000-0030, съдейки по Wireshark, са информация за USB услуги.

Интересувахме се от част 0040-0070.

Нищо не беше ясно от един предавателен кадър, освен MOCFT символите. Тези символи се оказаха знаци от файла на фърмуера, както и останалите символи до края на кадъра (файлът на фърмуера е маркиран):

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Какво означават символите fd 3e 02 01 fe, аз лично, като Иля, нямах представа.

Погледнах следния кадър (сервизната информация е премахната тук, файлът на фърмуера е маркиран):

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Какво стана ясно? Че първите два байта са някаква константа. Всички следващи блокове потвърдиха това, но преди края на предавателния блок:

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Този кадър също беше смайващ, тъй като константата беше променена (маркирана) и, колкото и да е странно, имаше част от файла. Размерът на прехвърлените байтове на файла показва, че са прехвърлени 1024 байта. Отново не знаех какво означават останалите байтове.

Първо, като стар псевдоним на BBS, прегледах стандартните протоколи за предаване. Няма предадени протоколи 1024 байта. Започнах да изучавам хардуера и попаднах на протокола 1K Xmodem. Той позволяваше предаване на 1024, но с уговорка: първоначално само 128 и само ако нямаше грешки, протоколът увеличаваше броя на предаваните байтове. Веднага имах трансфер от 1024 байта. Реших да проуча протоколите за предаване и по-специално X-модема.

Имаше две разновидности на модема.

Първо, форматът на пакета XMODEM с поддръжка на CRC8 (оригиналния XMODEM):

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Второ, пакетният формат XMODEM с поддръжка на CRC16 (XmodemCRC):

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Изглежда подобно, с изключение на SOH, номера на пакета и CRC и дължината на пакета.

Погледнах началото на втория блок за предаване (и отново видях файла на фърмуера, но вече с отстъп от 1024 байта):

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Видях познатия хедър fd 3e 02, но следващите два байта вече бяха променени: беше 01 fe и стана 02 fd. Тогава забелязах, че вторият блок вече е номериран с 02 и по този начин разбрах: пред мен беше номерацията на предавателния блок. Първата предавка 1024 е 01, втората е 02, третата е 03 и така нататък (но в шестнадесетичен, разбира се). Но какво означава промяната от fe на fd? Очите видяха намаление с 1, мозъкът напомни, че програмистите броят от 0, а не от 1. Но тогава защо първият блок е 1, а не 0? Все още не съм намерил отговора на този въпрос. Но разбрах как се брои вторият блок. Вторият блок не е нищо повече от FF – (минус) номерът на първия блок. Така вторият блок беше обозначен като = 02 (FF-02) = 02 FD. Последвалото прочитане на дъмпа потвърди предположението ми.

След това започна да се появява следната картина на предаването:

Начало на предаването
fd 3e 02 – Начало
01 FE – брояч на предаване
Трансфер (34 блока, 1024 байта прехвърлени)
fd 3e 1024 байта данни (разделени на блокове от 30 байта).
Край на предаването
fd 25

Останалите данни да бъдат подравнени към 1024 байта.

Как изглежда крайната рамка на предаване на блок:

Задача за разработчик или как флашнахме ръчни скенери без доставчик

fd 25 – предаване на сигнал до крайния блок. Следващ 2f 52 – останалата част от файла с размер до 1024 байта. 2f 52, съдейки по протокола, е 16-битова CRC контролна сума.

Заради старите времена направих програма на C, която изтегли 1024 байта от файл и изчисли 16-битов CRC. Стартирането на програмата показа, че това не е 16-битов CRC. Отново ступор - за около три дни. През цялото това време се опитвах да разбера какво може да бъде, ако не контролна сума. Докато изучавах англоезични сайтове, открих, че X-модемът използва собствено изчисление на контролната сума - CRC-CCITT (XModem). Не намерих C реализации на това изчисление, но намерих сайт, който изчислява тази контролна сума онлайн. След като прехвърлих 1024 байта от моя файл на уеб страницата, сайтът ми показа контролна сума, която напълно съвпада с контролната сума от файла.

Ура! Последната загадка беше разрешена, сега трябваше да направя свой собствен фърмуер. След това предадох знанията си (и те останаха само в главата ми) на Иля, който е запознат с мощния инструментариум Python.

Създаване на програма

Иля Алешин съобщава.

След като получих съответните инструкции, бях много „щастлив“.

Откъде да започна? Точно така, от самото начало.  От вземане на дъмп от USB порта.

Стартирайте USB-pcap https://desowin.org/usbpcap/tour.html

Изберете порта, към който е свързано устройството и файла, където ще запазим дъмпа.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Свързваме скенера към машина, на която е инсталиран собственият софтуер EZConfigScanning за Windows.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

В него намираме елемента за изпращане на команди към устройството. Но какво да кажем за отборите? Къде мога да ги взема?
Когато програмата стартира, оборудването се запитва автоматично (ще видим това малко по-късно). И имаше тренировъчни баркодове от официалните документи на оборудването. ДЕФАЛТ. Това е нашият екип.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Необходимите данни са получени. Отворете dump.pcap чрез wireshark.

Блокира при стартиране на EZConfigScanning. Местата, на които трябва да обърнете внимание, са маркирани в червено.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Виждайки всичко това за първи път, паднах духом. Не е ясно къде да копаем по-нататък.

Малко мозъчна атака и-и-и... Аха! В бунището от – това са inИ in този от.

Потърсих в Google какво е URB_INTERRUPT. Разбрах, че това е метод за пренос на данни. И има 4 такива метода: контрол, прекъсване, изохронен, групов. Можете да прочетете за тях отделно.

А адресите на крайната точка в интерфейса на USB устройството могат да бъдат получени или чрез командата „lsusb –v“ или с помощта на pyusb.

Сега трябва да намерим всички устройства с този VID. Можете да търсите конкретно по VID:PID.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Изглежда така:

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Задача за разработчик или как флашнахме ръчни скенери без доставчик

И така, имаме необходимата информация: командите P_INFO. или DEFALT, адреси къде да се пишат команди endpoint=03 и къде да се получи отговор endpoint=86. Всичко, което остава, е да конвертирате командите в hex.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Тъй като вече намерихме устройството, нека го изключим от ядрото...

Задача за разработчик или как флашнахме ръчни скенери без доставчик

...и пишете до крайната точка с адрес 0x03,

Задача за разработчик или как флашнахме ръчни скенери без доставчик

... и след това прочетете отговора от крайната точка с адрес 0x86.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Структуриран отговор:

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

Виждаме тези данни в dump.pcap.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Страхотен! Преобразувайте системните баркодове в шестнадесетичен. Това е всичко, функционалността за обучение е готова.

Какво ще кажете за фърмуера? Всичко изглежда същото, но има нюанс.

След като направихме пълно изхвърляне на процеса на мигане, ние приблизително разбрахме с какво имаме работа. Ето една статия за XMODEM, която беше много полезна за разбирането как се осъществява тази комуникация, макар и в общи линии: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Препоръчвам да го прочетете.

Разглеждайки дъмпа, можете да видите, че размерът на рамката е 1024, а размерът на URB-данните е 64.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Следователно – 1024/64 – получаваме 16 реда в блок, четем файла на фърмуера по 1 знак наведнъж и образуваме блок. Допълване на 1 ред в блок със специални знаци fd3e02 + номер на блок.
Следващите 14 реда се допълват с fd25 +, използвайки XMODEM.calc_crc() изчисляваме контролната сума на целия блок (отне много време, за да разберем, че „FF – 1“ е CSUM) и последният, 16-ти ред се допълва с fd3e.

Изглежда, че това е всичко, прочетете файла на фърмуера, натиснете блоковете, изключете скенера от ядрото и го изпратете на устройството. Но не е толкова просто. Скенерът трябва да бъде превключен в режим на фърмуер,
отправив ему NEWAPP = ‘\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
От къде е този отбор?? От бунището.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Но не можем да изпратим цял блок към скенера поради ограничението от 64:

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Е, скенера в NEWAPP мигащ режим не приема hex. Следователно ще трябва да преведете всеки ред 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]

След това изпратете тези данни на скенера.

Получаваме отговора:

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

Ако проверите статията за XMODEM, ще стане ясно: данните са приети.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

След като всички блокове са прехвърлени, завършваме прехвърлянето END_TRANSFER = 'xfdx01x04'.

Е, тъй като тези блокове не носят никаква информация за обикновените хора, ние ще инсталираме фърмуера в скрит режим по подразбиране. И за всеки случай ще организираме лента за напредъка чрез tqdm.

Задача за разработчик или как флашнахме ръчни скенери без доставчик

Всъщност това е въпрос на дребни неща. Остава само да обвиете решението в скриптове за масова репликация в ясно определено време, за да не забавяте процеса на работа на касите и да добавите логване.

Общо

След като отделихме много време и усилия и косми на главите си, успяхме да разработим решенията, от които се нуждаехме, и също така спазихме крайния срок. В същото време скенерите вече се презареждат и обучават централно, ние ясно контролираме целия процес. Компанията спести време и пари, а ние натрупахме безценен опит в оборудването за обратно инженерство от този тип.

Източник: www.habr.com

Добавяне на нов коментар