Reverse Engineering a Samsung Scanner Button, page 4

Pages: 1 2 3 4 5 6 7 8

Before we proceed, we should talk about URBs and Endpoints. An 'URB' is a USB Request Block. If you want to fully understand the packet structure of an URB, that link and several other resources on the Internet are available. Discussing URBs in detail is beyond the scope of this article. Fortunately for us, we don't require this in-depth knowledge of URBs in order to accomplish our task. We only need to understand the way that "usbmon" represents the calls going from the Linux kernel to the device, and packets from the device coming back to the Linux Kernel.

Endpoints are the points in USB terminology that we can talk to, sort of like sockets. As represented by usbmon, they are either listening for a request 'S = Submission', or they are sending back data after a request 'C = Callback'. The response will come from the same endpoint as the request.

The types of Endpoints and associated bits of information (according to usbmon) that we need to understand are as follows:

Endpoint Types:

	   Control Transfer
	   Interrupt Transfer
	   Isochronous Transfer
	   Bulk Transfer
				

Event-Type: S=submission, C=callback, E=submission error

URB-Type and direction:

				Ci or Co   Control input or Control output
				Zi or Zo   Isochronous input or Isochronous output
				Ii or Io   Interrupt input or Interrupt output
				Bi or Bo   Bulk input or Bulk output
			

URB-Status: s=setup and 0=acknowledged

Each line in the capture file that we have created via usbmon represents an URB. We will use a simple query
(first line) and response (second line) to show an example of the structure produced by usbmon (color coded):

ffff880023078a80 2959991785 S Ci:1:003:0 s c1 23 0100 0100 0008 8 <
ffff880023078a80 2959991966 C Ci:1:003:0 0 8 = 4e4f5453 50505254

Now let's break this down:

	Submission(Query):
	Internal-Mem URB address/tag  Time Stamp  Event-Type  URB-Transfer-Type/direction   Bus    Dev   Endpoint
	ffff880023078a80              2959991785        S                  Ci:               1:    003:      0   

	URB-Status  bRequestType  bRequest  wValue  wIndex  wLength  wLength
	    s            c1          23      0100    0100    0008       8 <
				

	Callback(Response):
	Internal-Mem URB address/tag  Time Stamp  Event-Type  URB-Transfer-Type/direction   Bus    Dev   Endpoint
	ffff880023078a80              2959991966        C                  Ci:               1:    003:      0   

	URB-Status  Data-Length  Data-Tag    Data-Words (In this case, 4x2=8 bytes)
	    0             8          =       4e4f5453 50505254
				

In the Submission, the first value for wLength is a hex value, and the second is an int value.
Note the colors used to separate the values.

Step 5: Look at the verbose output of 'lsusb'

What we need to determine now are the Endpoints of interest. This command will tell us what we need to know. It may be helpful to send the output of this command to a text file for examination:

					[root@server5 ~]# lsusb -v > lsusb.txt
				

In my case, the target device in my text file looked like this (points of interest in red):

	  Bus 001 Device 003: ID 04e8:344f Samsung Electronics Co., Ltd
	  Device Descriptor:
	    bLength                18
	    bDescriptorType         1
	    bcdUSB               2.00
	    bDeviceClass            0 (Defined at Interface level)
	    bDeviceSubClass         0 
	    bDeviceProtocol         0 
	    bMaxPacketSize0        64
	    idVendor           0x04e8 Samsung Electronics Co., Ltd
	    idProduct          0x344f 
	    bcdDevice            1.00
	    iManufacturer           1 Samsung Electronics Co., Ltd.
	    iProduct                2 SCX-3400 Series
	    iSerial                 3 Z8BNB8KDCE00DQW
	    bNumConfigurations      1
	    Configuration Descriptor:
	      bLength                 9
	      bDescriptorType         2
	      wTotalLength           55
	      bNumInterfaces          2
	      bConfigurationValue     1
	      iConfiguration          0 
	      bmAttributes         0xc0
	        Self Powered
	      MaxPower                2mA
	      Interface Descriptor:
	        bLength                 9
	        bDescriptorType         4
	        bInterfaceNumber        0
	        bAlternateSetting       0
	        bNumEndpoints           2
	        bInterfaceClass       255 Vendor Specific Class
	        bInterfaceSubClass    255 Vendor Specific Subclass
	        bInterfaceProtocol    255 Vendor Specific Protocol
	        iInterface              0 
	        Endpoint Descriptor:
	          bLength                 7
	          bDescriptorType         5
	          bEndpointAddress     0x04  EP 4 OUT
	          bmAttributes            2
	            Transfer Type            Bulk
	            Synch Type               None
	            Usage Type               Data
	          wMaxPacketSize     0x0200  1x 512 bytes
	          bInterval              10
	        Endpoint Descriptor:
	          bLength                 7
	          bDescriptorType         5
	          bEndpointAddress     0x83  EP 3 IN
	          bmAttributes            2
	            Transfer Type            Bulk
	            Synch Type               None
	            Usage Type               Data
	          wMaxPacketSize     0x0200  1x 512 bytes
	          bInterval              10
	      Interface Descriptor:
	        bLength                 9
	        bDescriptorType         4
	        bInterfaceNumber        1
	        bAlternateSetting       0
	        bNumEndpoints           2
	        bInterfaceClass         7 Printer
	        bInterfaceSubClass      1 Printer
	        bInterfaceProtocol      2 Bidirectional
	        iInterface              0 
	        Endpoint Descriptor:
	          bLength                 7
	          bDescriptorType         5
	          bEndpointAddress     0x02  EP 2 OUT
	          bmAttributes            2
	            Transfer Type            Bulk
	            Synch Type               None
	            Usage Type               Data
	          wMaxPacketSize     0x0200  1x 512 bytes
	          bInterval              10
	        Endpoint Descriptor:
	          bLength                 7
	          bDescriptorType         5
	          bEndpointAddress     0x81  EP 1 IN
	          bmAttributes            2
	            Transfer Type            Bulk
	            Synch Type               None
	            Usage Type               Data
	          wMaxPacketSize     0x0200  1x 512 bytes
	          bInterval              10
	  Device Qualifier (for other device speed):
	    bLength                10
	    bDescriptorType         6
	    bcdUSB               2.00
	    bDeviceClass            0 (Defined at Interface level)
	    bDeviceSubClass         0 
	    bDeviceProtocol         0 
	    bMaxPacketSize0        64
	    bNumConfigurations      1
	  Device Status:     0x0001
	    Self Powered
				

We notice something interesting here... in most devices that I have seen, such as a scanner, there will normally be control endpoints or interrupt endpoints and they will be the ones receiving control messages. However, Samsung (or whoever built the guts of this thing) chose to manufacture this device with only bulk data endpoints. What this means to us is that control messages and bulk data streams will use the same type of endpoint. We also see that the capabilities for all 4 endpoints on this device are identical.

The messages that we are interested in are control messages, such as the requests to start a scan or stop a scan. When we press the scan button, what happens is, a request to query if this hardware address (button) has changed it's value is sent from the application via the device driver. Let's be more clear...

Remember that USB is a host initiated protocol. The device cannot inform us if the button has been pressed, so we will have to ask. The code that we will write will behave the same way as the Windows driver... our code will ask every X number of seconds if the button has been pressed, and we will ask that question exactly the way that the driver does.

So in order for us to know if the button has been pressed, we will have to:

1. Create a buffer of a given length.
2. Send a given command to a given endpoint on the device along with our buffer.
3. The endpoint that we query with our command will fill that buffer with an answer.
4. The buffer will be returned to us by the device endpoint and we can examine it's contents.

Next page