A task for the developer, or how we flashed hand-held scanners without a vendor

Hello.

We, Viktor Antipov and Ilya Aleshin, today will talk about our experience with USB devices via Python PyUSB and a bit about reverse engineering.

A task for the developer, or how we flashed hand-held scanners without a vendor

prehistory

In 2019, Decree of the Government of the Russian Federation No. 224 β€œOn Approval of the Rules for Labeling Tobacco Products with Identification Tools and Features of the Implementation of the State Information System for Monitoring the Turnover of Goods Subject to Mandatory Labeling with Identification Tools in Relation to Tobacco Products” came into force.
The document explains that from July 1, 2019, manufacturers are required to label each pack of tobacco. And direct distributors must receive these products with the execution of a universal transfer document (UPD). Stores, in turn, need to register the sale of labeled products through the cash register.

Also, from July 1, 2020, the circulation of unlabeled tobacco products is prohibited. This means that all packs of cigarettes must be marked with a special Datamatrix barcode. And - an important point - it turned out that the Datamatrix will not be ordinary, but inverse. That is, not black code on white, but vice versa.

We tested our scanners, and it turned out that most of them need to be reflashed / retrained, otherwise they are simply not able to work normally with this barcode. This turn of events guaranteed us a big headache, because our company has a lot of stores that are scattered over a vast territory. Several tens of thousands of cash desks - and very little time.

What was to be done? Option two. First, engineers at the site manually reflash and reconfigure the scanners. Second: we work remotely and, preferably, we cover many scanners at once in one iteration.

The first option, obviously, did not suit us: we would have to spend money on visits of engineers, and in this case it would be difficult to control and coordinate the process. But the most important thing is that people would work, that is, we potentially received a lot of errors and, most likely, did not meet the deadline.

The second option is good for everyone, if not for one thing. Some vendors did not have the remote flashing tools we needed for all the required OSes. And since the deadlines were running out, I had to think with my head.

Next, we will tell you how we developed tools for handheld scanners under Debian 9.x OS (we have all cash registers on Debian).

Solve the riddle: how to flash a scanner

By Viktor Antipov.

The official utility provided by the vendor works under Windows, and only with IE. The utility can flash and configure the scanner.

Since our target system is Debian, we put it on a Debian usb-redirector server, on a Windows usb-redirector client. With the help of the usb-redirector utilities, we made a scanner transfer from a Linux machine to a Windows machine.

The utility from the vendor under Windows saw the scanner and even flashed it normally. Thus, we made the first conclusion: nothing depends on the OS, the point is in the flashing protocol.

OK. A flashing was launched on a Windows machine, a dump was taken on a Linux machine.

They stuffed the dump into WireShark and ... saddened (I will omit some of the details of the dump, they are of no interest).

What dump showed us:

A task for the developer, or how we flashed hand-held scanners without a vendor

A task for the developer, or how we flashed hand-held scanners without a vendor

Addresses 0000-0030, judging by Wireshark, are USB service information.

We were interested in part 0040-0070.

Nothing was clear from one transmission frame, except for the MOCFT symbols. These characters turned out to be characters from the firmware file, as well as the rest of the characters before the end of the frame (the firmware file is highlighted):

A task for the developer, or how we flashed hand-held scanners without a vendor

What the symbols fd 3e 02 01 fe meant, I personally, like Ilya, had no idea.

I looked at the following frame (service information has been removed here, the firmware file has been highlighted):

A task for the developer, or how we flashed hand-held scanners without a vendor

What became clear? That the first two bytes are some kind of constant. All subsequent blocks confirmed this, but before the end of the transmission block:

A task for the developer, or how we flashed hand-held scanners without a vendor

This frame was also put into a stupor, since the constant was changed (highlighted) and, oddly enough, there was a part of the file. The size of the file bytes transferred showed that 1024 bytes were transferred. What the rest of the bytes meant, I didn't know again.

First of all, as an old BBS nickname, I revised the standard transfer protocols. 1024 bytes were not transmitted by any protocol. I started to study the materiel and came across the 1K Xmodem protocol. It allowed to transfer 1024, but with a nuance: at first only 128, and only in the absence of errors did the protocol increase the number of bytes transferred. I immediately had a transfer of 1024 bytes. I decided to study transmission protocols, and specifically the X-modem.

There were two variations of the modem.

First, the XMODEM package format with CRC8 support (original XMODEM):

A task for the developer, or how we flashed hand-held scanners without a vendor

Secondly, the XMODEM package format with CRC16 support (XmodemCRC):

A task for the developer, or how we flashed hand-held scanners without a vendor

It looks similar, except for the SOH, the packet number and CRC and the length of the package.

I looked at the beginning of the second transmission block (and again saw the firmware file, but with an indent of 1024 bytes):

A task for the developer, or how we flashed hand-held scanners without a vendor

I saw the familiar fd 3e 02 header, but the next two bytes have already changed: it was 01 fe, and it became 02 fd. Then I noticed that the second block is now numbered 02 and thus understood: in front of me is the numbering of the transmission block. The first 1024 gear is 01, the second is 02, the third is 03, and so on (but in hex, of course). But what does the change from fe to fd mean? The eyes saw a decrease by 1, the brain reminded that programmers count from 0 and not from 1. But then why is the first block 1 and not 0? I have not found an answer to this question. But I understood how the second block is considered. The second block is nothing but FF - (minus) the number of the first block. Thus, the second block was designated as = 02 (FF-02) = 02 FD. Subsequent reading of the dump confirmed my hunch.

Then the following picture began to emerge:

Transfer start
fd 3e 02 – Start
01 FE - transfer counter
Transfer (34 blocks, 1024 bytes transferred)
fd 3e 1024 bytes of data (broken into blocks of 30 bytes).
End of transmission
fd 25

Remaining data to align up to 1024 bytes.

What does the block transfer end frame look like:

A task for the developer, or how we flashed hand-held scanners without a vendor

fd 25 - signal to the end of the block transmission. Then 2f 52 - the rest of the file up to a size of 1024 bytes. 2f 52, judging by the protocol, is a 16-bit CRC checksum.

From old memory, I made a program in C that pulled 1024 bytes from a file and read 16-bit CRC. Running the program showed that it was not a 16-bit CRC. Stupor again - for about three days. All this time I was trying to figure out what it could be, if not a checksum. Studying English-language sites, I found that the X-modem uses its own checksum calculation - CRC-CCITT (XModem). I did not find implementations in C of this calculation, but I found a site that online calculated this checksum. After uploading 1024 bytes of their file to a web page, the site showed me a checksum that completely matched the checksum from the file.

Hooray! The last riddle is solved, now it was necessary to make your firmware. Then I transferred my knowledge (and they remained only in my head) to Ilya, who is familiar with the powerful toolkit - Python.

Program creation

Ilya Alyoshin says.

Having received the appropriate instructions, I was very "delighted."

Where to begin? That's right, from the beginning.  From the removal of the dump from the USB port.

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

We select the port to which the device is connected, and the file where we save the dump.

A task for the developer, or how we flashed hand-held scanners without a vendor

We connect the scanner to the machine where the native EZConfigScanning software for Windows is installed.

A task for the developer, or how we flashed hand-held scanners without a vendor

In it we find the point for sending commands to the device. But what about teams? Where to get them?
When the program starts, the equipment is polled automatically (we will see this a little later). And there were also training barcodes from official equipment documents. DEFALT. This is our team.

A task for the developer, or how we flashed hand-held scanners without a vendor

The required data has been received. Open dump.pcap via wireshark.

Block when starting EZConfigScanning. Areas that need attention are marked in red.

A task for the developer, or how we flashed hand-held scanners without a vendor

A task for the developer, or how we flashed hand-held scanners without a vendor

Seeing all this for the first time, I lost heart. Where to dig further is not clear.

A little bit of brainstorming and-and-and ... Aha! In the dump out - is in, in it out.

Googled what URB_INTERRUPT is. Found out that this is a data transfer method. And there are 4 such methods: control, interrupt, isochronous, bulk. You can read about them separately.

And the endpoint addresses in the USB device interface can be obtained either through the β€œlsusb –v” command, or using pyusb.

Now we need to find all devices with this VID. You can search specifically by VID:PID.

A task for the developer, or how we flashed hand-held scanners without a vendor

It looks like this:

A task for the developer, or how we flashed hand-held scanners without a vendor

A task for the developer, or how we flashed hand-held scanners without a vendor

So, we have the necessary information: P_INFO commands. or DEFALT, addresses where to write commands endpoint=03 and from where to get the answer endpoint=86. It remains only to translate the commands into hex.

A task for the developer, or how we flashed hand-held scanners without a vendor

A task for the developer, or how we flashed hand-held scanners without a vendor

Since we have already found the device, we will disconnect it from the kernel ...

A task for the developer, or how we flashed hand-held scanners without a vendor

...and write to endpoint with address 0x03,

A task for the developer, or how we flashed hand-held scanners without a vendor

…and then read the response from endpoint 0x86.

A task for the developer, or how we flashed hand-held scanners without a vendor

Structured response:

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

We see this data in dump.pcap.

A task for the developer, or how we flashed hand-held scanners without a vendor

A task for the developer, or how we flashed hand-held scanners without a vendor

A task for the developer, or how we flashed hand-held scanners without a vendor

Great! Converting system barcodes to hex. Everything, the training functionality is ready.

What about the firmware? It seems that everything is the same, but there is a nuance.

Having taken a complete dump of the flashing process, we roughly understood what we were dealing with. Here is an article about XMODEM that was very helpful in understanding how this communication takes place, albeit in general terms: http://microsin.net/adminstuff/others/xmodem-protocol-overview.html I recommend reading it.

Looking at the dump, you can see that the frame size is 1024 and the URB-data size is 64.

A task for the developer, or how we flashed hand-held scanners without a vendor

Therefore – 1024/64 – we get 16 lines in a block, read the firmware file 1 character at a time and form a block. Complementing 1 line in a block with special characters fd3e02 + block number.
We add fd14 + to the next 25 lines, using XMODEM.calc_crc() we calculate the checksum of the entire block (it took a long time to understand that β€œFF - 1” is CSUM) and the last, 16th line, we add fd3e.

It would seem that everything, read the firmware file, hit the blocks, disconnect the scanner from the core and send it to the device. But not everything is so simple. The scanner needs to be put into firmware mode,
ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ² Π΅ΠΌΡƒ NEWAPP = β€˜\xfd\x0a\x16\x4e\x2c\x4e\x45\x57\x41\x50\x50\x0d’.
Where is this team from? From dump.

A task for the developer, or how we flashed hand-held scanners without a vendor

But we cannot send a whole block to the scanner due to the 64 limit:

A task for the developer, or how we flashed hand-held scanners without a vendor

Well, the scanner in the NEWAPP flashing mode does not accept hex. Therefore, you will have to translate each line 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]

And send this data to the scanner.

We get the answer:

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

If you check the article about XMODEM, it becomes clear: the data is accepted.

A task for the developer, or how we flashed hand-held scanners without a vendor

After all blocks have been transferred, we complete the transfer END_TRANSFER = 'xfdx01x04'.

Well, since these blocks do not carry any information for ordinary people, we will make the default firmware in hidden mode. And just in case, through tqdm we will organize a progress bar.

A task for the developer, or how we flashed hand-held scanners without a vendor

Actually, the next thing is small. It remains only to wrap the solution in scripts for mass replication at a clearly defined time, so as not to slow down the process of working at the checkout, and add logging.

Π‘onclusion

Having spent a lot of time and effort and hair on our heads, we were able to develop the solutions we needed, and besides, we met the deadline. At the same time, scanners are now reflashed and retrained centrally, we clearly control the entire process. The company saved time and money, and we gained invaluable experience in reverse engineering of this type of equipment.

Source: habr.com

Add a comment