Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Усім прывітанне.

Мы, Віктар Анціпаў і Ілля Алешын, сёння раскажам пра свой досвед працы з USB-дэвайсамі праз Python PyUSB і крыху пра рэверс-інжынірынгу.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

перадгісторыя

У 2019 годзе ўступіла ў сілу Пастанова Урада РФ № 224 "Аб зацвярджэнні Правілаў маркіроўкі тытунёвай прадукцыі сродкамі ідэнтыфікацыі і асаблівасцях укаранення дзяржаўнай інфармацыйнай сістэмы маніторынгу за абаротам тавараў, якія падлягаюць абавязковай маркіроўцы сродкамі ідэнтыфікацыі, адносна тытунёвай прадукцыі".
Дакумент тлумачыць, што з 1 ліпеня 2019 года вытворцы абавязаны маркіраваць кожны пачак тытуню. А прамыя дыстрыбутары павінны атрымліваць дадзеную прадукцыю з афармленнем універсальнага перадаткавага дакумента (УПД). Крамам, у сваю чаргу, неабходна рэгістраваць продаж маркіраванай прадукцыі праз касу.

Таксама з 1 ліпеня 2020 года абарот немаркіраванай тытунёвай прадукцыі забаронены. Гэта азначае, што ўсе пачкі цыгарэт павінны маркіравацца спецыяльным штрыхкодам Datamatrix. Прычым - важны момант - высветлілася, што Datamatrix будзе не звычайны, а інверсны. То бок, не чорны код на белым, а наадварот.

Мы пратэставалі нашы сканары, і аказалася, што большую іх частку трэба перапрошваць/перанавучваць, інакш яны проста не ў стане нармальна працаваць з гэтым штрыхкодам. Такі паварот падзей гарантаваў нам моцны галаўны боль, таму што ў нашай кампаніі вельмі шмат крам, якія раскіданыя па вялізнай тэрыторыі. Некалькі дзясяткаў тысяч кас - і вельмі мала часу.

Што было рабіць? Варыянту два. Першы: інжынеры на аб'екце ўручную запытваюць і данабудоўваюць сканары. Другі: працуем выдалена і, пажадана, ахапляем адразу шмат сканараў за адну ітэрацыю.

Першы варыянт нам, відавочна, не падыходзіў: прыйшлося б патраціцца на выезды інжынераў, ды і кантраляваць і каардынаваць працэс у такім выпадку складана. Але самае галоўнае - працавалі б людзі, гэта значыць патэнцыйна мы атрымлівалі мноства памылак і, хутчэй за ўсё, не ўкладваліся ў тэрмін.

Другі варыянт усім добры, калі б не адно але. У некаторых вендараў не аказалася неабходных нам прылад выдаленай перапрашыўкі для ўсіх патрабаваных АС. А так як тэрміны падціскалі, прыйшлося думаць сваёй галавой.

Далей раскажам, як мы распрацоўвалі прылады для ручных сканараў пад АС Debian 9.x (у нас усе касы на Debian).

Разгадаць загадку: як адштабнаваць сканер

Расказвае Віктар Анціпаў.

Афіцыйная ўтыліта, якую падаў вендар, працуе пад Windows, прычым толькі з IE. Утыліта ўмее прашываць і наладжваць сканер.

Бо мэтавая сістэма ў нас Debian, то паставілі на Debian usb-redirector server, на Windows usb-redirector client. Пры дапамозе ўтыліт usb-redirector зрабілі пракід сканара з Linux машыны, на Windows машыну.

Утыліта ад вендара пад Windows убачыла сканер і нават яго нармальна адштабнавала. Такім чынам, зрабілі першую выснову: ад АС нічога не залежыць, справа ў пратаколе перапрашыўкі.

Ок. На Windows-машыне запусцілі перапрашыўку, на Linux-машыне знялі dump.

Запіхнулі dump у WireShark і… засумавалі (частка дэталяў dump я апушчу, яны ніякай цікавасці не ўяўляюць).

Што нам паказаў dump:

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Адрасы 0000-0030, мяркуючы па Wireshark, - службовая інфармацыя USB.

Нас цікавіла частка 0040-0070.

З аднаго кадра перадачы нічога не было зразумела, за выключэннем сімвалаў MOCFT. Гэтыя знакі апынуліся знакамі з файла прашыўкі, як, зрэшты, і астатнія знакі да канчатка кадра (вылучаны файл прашыўкі):

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Што азначалі знакі fd 3e 02 01 fe, асабіста я, як і Ілля, паняцця не меў.

Паглядзеў наступны кадр (службовая інфармацыя тут выдалена, выдзелены файл прашыўкі):

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Што стала зразумела? Што першыя два байта - нейкая канстанта. Усе наступныя блокі гэта пацвердзілі, але да заканчэння блока перадачы:

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Гэты кадр таксама ўвёў у ступар, бо змянілася канстанта (вылучыў) і, як ні дзіўна, мелася частка файла. Памер перададзеных байт файла паказваў, што было перададзена 1024 байта. Што значылі астатнія байты - я зноў не ведаў.

Перш за ўсё, як стары BBS-нік, я перагледзеў стандартныя пратаколы перадачы. 1024 байты ніводны пратакол не перадаваў. Пачаў вывучаць матчасьць і натыкнуўся на пратакол 1К Xmodem. Ён дазваляў перадаваць 1024, але з нюансам: спачатку толькі 128, і толькі пры адсутнасці памылак пратакол павялічваў колькасць перадаюцца байт. У мяне ж адразу была перадача 1024 байта. Вырашыў вывучаць пратаколы перадачы, а менавіта Х-мадэм.

Варыяцый мадэма было дзве.

Па-першае, фармат пакета XMODEM з падтрымкай CRC8 (арыгінальны XMODEM):

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Па-другое, фармат пакета XMODEM з падтрымкай CRC16 (XmodemCRC):

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

З выгляду падобна, за выключэннем SOH, нумары пакета і CRC і даўжыні пасылкі.

Паглядзеў пачатак другога блока перадачы (і зноў убачыў файл прашыўкі, але ўжо з водступам у 1024 байта):

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Убачыў знаёмы загаловак fd 3e 02, але наступныя два байта ўжо змяніліся: было 01 fe, а стала 02 fd. Тут я заўважыў, што другі блок зараз нумаруецца 02 і такім чынам зразумеў: перада мной нумарацыя блока перадачы. Першая 1024 перадача - 01, другая - 02, трэцяя - 03 і гэтак далей (але ў hex, натуральна). Але што азначае змена з fe на fd? Вочы бачылі памяншэнне на 1, мозг нагадваў, што праграмісты лічаць з 0, а не з 1. Але тады чаму першы блок 1, а не 0? Адказу на гэтае пытаньне я так і не знайшоў. Затое зразумеў, як лічыцца другі блёк. Другі блок - гэта не што іншае як FF - (мінус) нумар першага блока. Такім чынам, другі блок абазначаўся як = 02 (FF-02) = 02 FD. Наступнае чытанне дампа пацвердзіла маю здагадку.

Тады стала вымалёўвацца наступная карціна перадачы:

Пачатак перадачы
fd 3e 02 – Start
01 FE – лічыльнік перадачы
Перадача (34 блокі, перадаецца 1024 байта)
fd 3e 1024 байта дадзеных (разбітыя на блокі па 30 байт).
Канчатак перадачы
fd 25

Рэшткі дадзеных для выраўноўвання да 1024 байта.

Як выглядае кадр заканчэння перадачы блока:

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

fd 25 - сігнал да канчатка перадачы блока. Далей 2f 52 - рэшткі файла да памеру 1024 байта. 2f 52, мяркуючы па пратаколе, - кантрольная сума 16-bit CRC.

Па старой памяці зрабіў на З праграму, якая тузала з файла 1024 байта і лічыла 16-bit CRC. Запуск праграмы паказаў, што гэта ня 16-bit CRC. Зноў ступар - прыкладна на тры дні. Увесь гэты час я спрабаваў зразумець, што гэта можа быць такое, калі не кантрольная сума. Вывучаючы англамоўныя сайты, я выявіў, што для X-мадэм выкарыстоўваецца свой падлік кантрольнай сумы - CRC-CCITT (XModem). Рэалізацый на C дадзенага падліку я не знайшоў, але знайшоў сайт, які ў online лічыў дадзеную кантрольную суму. Перакінуўшы на вэб-старонку 1024 байта свайго файла, сайт паказаў мне кантрольную суму, якая цалкам супала з кантрольнай сумай з файла.

Ура! Апошняя загадка вырашана, зараз трэба было зрабіць сваю прашывалку. Далей я перадаў свае веды (а яны засталіся толькі ў мяне ў галаве) Іллі, які знаёмы з магутным інструментарыем – Python.

Стварэнне праграмы

Расказвае Ілля Алёшын.

Атрымаўшы адпаведныя інструкцыі, я вельмі "узрадаваўся".

З чаго пачаць? Правільна, з пачатку.  Са зняцця дампа з USB порта.

Запускаем USB-pcap https://desowin.org/usbpcap/tour.html

Выбіраемы порт, да якога падлучана прылада, і файл, куды захаваем dump.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Падлучальны сканер да машыны, дзе ўсталявана роднае ПА EZConfigScanning для Windows.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

У ім знаходзім пункт адпраўкі каманд на прыладу. Але што рабіць з камандамі? Дзе іх узяць?
Пры старце праграмы абсталяванне апытваецца аўтаматычна (гэта мы ўбачым крыху пазней). І яшчэ былі навучальныя штрыхкоды з афіцыйных дакументаў абсталявання. DEFALT. Гэта і ёсць наша каманда.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Неабходныя дадзеныя атрыманы. Адкрываем dump.pcap праз wireshark.

Блок пры старце EZConfigScanning. Чырвоным адзначаны месцы, на якія трэба звярнуць увагу.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Убачыўшы ўсё гэта ў першы раз, я ўпаў духам. Куды капаць далей - незразумела.

Трохі мазгавога штурму і-і-і... Ага! У дампе з - гэта in, А in гэта з.

Пагугліў, што такое URB_INTERRUPT. Высветліў, што гэта метад перадачы даных. І такіх метадаў 4: control, interrupt, isochronous, bulk. Аб іх можна пачытаць асобна.

А endpoint адрасы ў інтэрфейсе USB-дэвайса можна атрымаць або праз каманду "lsusb -v", або сродкамі pyusb.

Цяпер трэба знайсці ўсе прылады з такім VID. Можна шукаць канкрэтна па VID: PID.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Выглядае гэта так:

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Такім чынам, у нас зьявілася патрэбная інфармацыя: каманды P_INFO. ці DEFALT, адрасы, куды запісаць каманды endpoint=03 і адкуль атрымаць адказ endpoint=86. Засталося толькі перавесці каманды ў hex.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Бо прылада ў нас ужо знойдзена, адключым яе ад ядра…

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

…і выканаем запіс у endpoint c адрасам 0x03,

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

… а затым зачытаем адказ з endpoint з адрасам 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.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Выдатна! Перакладаны сістэмныя штрыхкодаў у hex. Усё, функцыянал навучання готаў.

Як быць з прашыўкай? Здаецца, усё тое ж самае, але ёсць нюанс.

Зняўшы поўны дамп працэсу перапрашыўкі, мы прыкладна зразумелі, з чым маем справу. Вось артыкул пра XMODEM, якая вельмі дапамагла зразумець, як гэтыя зносіны адбываюцца, хай і ў агульных рысах: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html Рэкамендую прачытаць.

Паглядзеўшы ў дамп, можна ўбачыць, што памер кадра - 1024, а памер URB-data - 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 які арганізуецца прагрэсар.

Задача для распрацоўніка, ці як мы без вендара ручныя сканары прашывалі

Уласна, далей справа за малым. Застаецца толькі абгарнуць рашэнне ў скрыпты для масавага тыражавання ў выразна зададзены час, каб не тармазіць працэс працы на касах, і дадаць лагіраванне.

Вынік

Выдаткаваўшы кучу часу і сіл і волас на галаве, мы здолелі распрацаваць патрэбныя нам рашэнні, да таго ж ўклаліся ў тэрмін. Пры гэтым сканары запытваюцца і перанавучаюцца зараз цэнтралізавана, мы дакладна кантралюем увесь працэс. Кампанія зэканоміла час і сродкі, а мы атрымалі бясцэнны вопыт рэверс-інжынірынгу абсталявання такога тыпу.

Крыніца: habr.com

Дадаць каментар