開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

大家好。

我們,Viktor Antipov 和 Ilya Aleshin,今天將討論我們透過 Python PyUSB 使用 USB 裝置的經驗以及一些關於逆向工程的知識。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

2019年,俄羅斯聯邦政府第224號法令“關於批准帶有識別手段的煙草製品標籤規則和實施國家信息系統的特徵,以監控強制帶有識別手段的標籤的商品流通”與煙草製品有關的規定”生效。
文件解釋說,從 1 年 2019 月 XNUMX 日起,製造商必須在每包菸草上貼上標籤。 直接分銷商必須透過執行通用轉移文件 (UDD) 來接收這些產品。 反過來,商店需要透過收銀機登記貼有標籤的產品的銷售情況。

此外,自1年2020月XNUMX日起,禁止無標籤菸草製品流通。 這意味著所有香菸包裝都必須標有特殊的 Datamatrix 條碼。 此外 - 重要的一點 - 事實證明,資料矩陣不會是普通的,而是逆的。 也就是說,不是白底黑字,而是反之亦然。

我們測試了我們的掃描儀,結果發現大多數掃描儀都需要重新刷新/重新訓練,否則它們根本無法正常使用此條碼。 這一變故讓我們非常頭疼,因為我們公司有很多商店,而且分佈在很大的地區。 數以萬計的收銀機——而且時間很少。

怎麼辦? 有兩種選擇。 第一:現場工程師手動重新閃光並調整掃描器。 第二:我們遠端工作,並且最好在一次迭代中同時覆蓋許多掃描器。

第一個選項顯然不適合我們:我們必須花錢請工程師上門,在這種情況下很難控制和協調流程。 但最重要的是人們會工作,也就是說,我們可能會遇到很多錯誤,而且很可能無法準時完成任務。

第二個選擇對每個人都有好處,即使不是一件事。 有些供應商沒有我們所需的所有作業系統所需的遠端刷新工具。 由於最後期限已到,我不得不用自己的頭腦思考。

接下來,我們將告訴您我們如何為 Debian 9.x 作業系統(我們所有的收銀機都在 Debian 上)開發手持式掃描器工具。

解決謎題:如何閃爍掃描儀

維克多·安蒂波夫報道。

供應商提供的官方實用程式可在 Windows 下運行,並且僅適用於 IE。 此實用程式可以刷新並配置掃描器。

由於我們的目標系統是 Debian,因此我們在 Debian 上安裝了 usb-redirector 伺服器,在 Windows 上安裝了 usb-redirector 用戶端。 使用 usb-redirector 實用程序,我們將掃描器從 Linux 電腦轉送到 Windows 電腦。

Windows 供應商的實用程式看到了掃描儀,甚至可以正常刷新它。 因此,我們得出第一個結論:與作業系統無關,而是閃存協定的問題。

好的。 我們在 Windows 電腦上執行刷新,並在 Linux 電腦上刪除轉儲。

我們將轉儲資料塞入 WireShark 中,然後…感到難過(我將省略轉儲資料的一些細節,它們沒有任何意義)。

轉儲向我們展示了什麼:

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

透過Wireshark判斷,位址0000-0030是USB服務資訊。

我們對 0040-0070 部分感興趣。

除了 MOCFT 字元之外,一幀傳輸幀中沒有任何內容是清晰的。 這些字符原來是韌體檔案中的字符,以及直到幀末尾的剩餘字符(韌體檔案突出顯示):

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

我個人和伊利亞一樣,不知道符號 fd 3e 02 01 fe 的意思。

我查看了以下框架(此處已刪除服務信息,固件文件已突出顯示):

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

什麼變得清楚了? 前兩個位元組是某種常數。 所有後續區塊都證實了這一點,但在傳輸區塊結束之前:

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

這個框架也令人震驚,因為常數已經改變(突出顯示),而且奇怪的是,還有文件的一部分。 文件傳輸位元組大小顯示傳輸了1024位元組。 我再次不知道剩餘位元組意味著什麼。

首先,作為一個舊BBS暱稱,回顧一下標準傳輸協定。 沒有協定傳輸 1024 位元組。 我開始研究硬體並遇到了 1K Xmodem 協議。 它允許傳輸 1024,但有一個警告:最初只有 128,並且只有在沒有錯誤的情況下,協定才會增加傳輸的位元組數。 我立即傳輸了 1024 位元組。 我決定研究傳輸協議,特別是 X-modem。

調製解調器有兩種變體。

一、支援CRC8的XMODEM封裝格式(原廠的XMODEM):

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

其次,支援CRC16的XMODEM資料包格式(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-modem 使用自己的校驗和計算 - CRC-CCITT (XModem)。 我沒有找到任何此計算的 C 實現,但我找到了一個在線計算此校驗和的站點。 將我的文件的 1024 位元組傳輸到網頁後,該網站向我顯示了一個與文件中的校驗和完全匹配的校驗和。

萬歲! 最後一個謎題解決了,現在我需要製作自己的韌體。 接下來,我將我的知識(它只留在我的腦海中)傳授給熟悉強大的 Python 工具包的 Ilya。

創建程式

伊利亞·阿萊辛報道。

收到相應的指示後,我非常「高興」。

從哪裡開始? 沒錯,從一開始就是這樣。  從 USB 連接埠取得轉儲。

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

選擇設備連接的連接埠以及我們將保存轉儲的檔案。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

我們將掃描器連接到安裝了適用於 Windows 的本機 EZConfigScanning 軟體的電腦。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

在其中我們找到用於向設備發送命令的項目。 但團隊呢? 我在哪裡可以得到它們?
當程式啟動時,設備會自動輪詢(我們稍後會看到)。 還有來自官方設備文件的訓練條碼。 預設. 這是我們的團隊。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

已收到必要的數據。 透過wireshark開啟dump.pcap。

啟動 EZConfigScanning 時阻止。 需要注意的地方都用紅色標註了。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

第一次看到這一切,我心灰意冷。 目前尚不清楚下一步該在哪裡挖掘。

集思廣益,然後……啊哈! 在垃圾場裡 - 是 inin.

我用谷歌搜尋了 URB_INTERRUPT 是什麼。 我發現這是一種資料傳輸方法。 有4種這樣的方法:控制、中斷、同步、批量。 您可以單獨閱讀它們。

USB 裝置介面中的端點位址可以透過「lsusb –v」指令或使用 pyusb 來取得。

現在我們需要找到具有該 VID 的所有裝置。 您可以透過VID:PID專門搜尋。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

它看起來像這樣:

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

所以,我們有必要的資訊:P_INFO 命令。 或 DEFALT,位址寫入命令端點 = 03 以及取得回應端點 = 86 的位置。 剩下的就是將命令轉換為十六進制。

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

既然我們已經找到了該設備,那麼讓我們將其與核心斷開連接...

開發人員的任務,或者我們如何在沒有供應商的情況下刷新手持式掃描儀

....並寫入位址為 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 個字元並形成一個區塊。 用特殊字元 fd1e3 + 區塊號補充區塊中的 02 行。
接下來的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 閃爍模式的掃描器不接受十六進位。 因此,您必須翻譯每一行 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

添加評論