Kinect:DIY Kinect Hacking(一)(原创)

1. Introduction

每个人都看过 Xbox 360 Kinect hacked in a matter of days after our "open source driver" bounty - here's how we helped the winner and here's how you can reverse engineer USB devices as well!

USB是一个非常复杂的协议,比Serial or Parallel, SPI and even I2C更加难懂. USB只使用2条电线,但它们不像串行一样是作为“接收”和“传输”。相反,数据是bidirectional and differential - 数据发送依赖与俩根数据线D+和D-之间的电压差异。如果你想知道更多有关USB的技术,你需要阅读 Jan Axelson's USB Complete books , they're easy to follow and discuss USB in both depth and breadth.

USB is also very structured。这很适合逆向工程, because it means that at least the format of packets is agreed upon and you won't have to deal with check-sums. 坏消息是,你必须有软件来协助你解码这些复杂的数据包。好消息是,现在每台电脑都会有USB host core,它们会为我们做大量艰辛的工作,并且会有很多软件库可以协助我们。

今天,我们将开始我们的逆向工程来破解Kinect的马达。

 

2. Verify the VID & PID

首先开始的是查看USB设备有效的“接口”信息和“配置”信息。最佳方式是使用lsusb(Linux)或者system_profiler(Mac),这是一个“list usb”程序可用于Linux和mac.悲剧的是,windows里并没有这些工具,所以找一台linux或mac吧,你只需要一分钟吧。

 在linux里,运行 lsusb-vv(ultra verbose).在mac里,运行 system_profiler SPUSBDataType

Kinect:DIY Kinect Hacking(一)(原创)_第1张图片

这里有一堆的东西像USB Keys和一些安装程序,但这是一个好的开始。需要注意的是,Kinect事实上有四个USB设备-一个集线器,一个摄像头,一个麦克风(音频)和一个马达. 这个集线器只是简单的把三个独立的芯片组合为一个单一的缆线设备。我们将会研究马达设备,因为它是最简单的。请注意Vendor ID=0x045e 和 Product ID = 0x2b0. 每种USB设备都必须拥有唯一的VID和PID。VID指的是制造商。在这个例子里,VID 0x45e指的是微软。所有的微软产品都会有这个VID值。每个产品都会有不同的PID,所以所有的Kinect马达的PID值都为0x02b0,俩个Kinect的马达PID不会不同,它们都拥有同样的PID。The VID/PID are used as a way to have the proper driver find the product。这个优于串行COM接口,因为串行COM接口可以更改名称, but VID/PID are burned into the device firmware。

 

3. Determine the Descriptors

你已经知道VID/PID是用来确定设备的描述符(descriptor)。描述符是一种“菜单”,描述了设备可以做什么,设备如何传输数据。一般情况下,每个设备都有一个描述符。一些时候一个设备会有1个以上的描述符,并且你可以选择你想要的一个,但是这种情况并不多见,所以我们忽略它。一个很好的方法来获取描述符,不需要编写任何软件,你只需要在linux系统的电脑上运行 lsusb-vv。我们并没有发现同样的软件在Windows或Mac上。所以找一台朋友的Linux电脑。(Try the "USB Prober" tool from Apple for Mac OS X.)

这里是马达输出的lsusb信息。

Device Descriptor:

bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x045e Microsoft Corp.
idProduct 0x02b0
bcdDevice 1.05
iManufacturer 1 Microsoft
iProduct 2 Xbox NUI Motor
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 18
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Device Status: 0x0000
(Bus Powered)

让我们看看我们得到了什么。你可以在上部看到VID和PID。接下来,我们会看到bNumConfigurations(how many different desciptors we have),且它的数值1。Next, look at the Interface Descriptor in particular,bNumEndpoints的值为0,这意味着马达没有端点(Endpoint)。

Endpoint are a type of USB 'data pipe' - 这里有四种类型。

Bulk Endpoints are for transferring a lot of data, like a disk drive. It's OK if it takes a little longer but we want big packets. This endpoint goes only in one direction (so to read and write you'd want two)

Interrupt Endpoints are for transferring tiny amounts of data very quickly, like for a USB mouse. In this case, the device has to be responsive so we want fast movement. This endpoint goes only in one direction

Isochronous Endpoints(同步端点) are for transferring a fair amount of data where the data must show up at the same time and if it can't it should just be dropped. This is for stuff like Audio and Video where timing is key. This endpoint goes only in one direction (so bidirectional audio for headphone and mic would have two EPs)

Control Endpoints(控制端点) are this weird not-quite-an-Endpoint Endpoint. They are used to transfer small amounts of data to say turn a device on or off. They're very 'cheap' to develop, and every device has one even if its not mentioned.

举例,一个串行端口有2个Interrupt endpoints来传出数据和传入数据,然后一个control endpoint来设置传输速率。

For more details we really do suggest reading everything at lvr.com about USB as it's complex.

马达设备没有Endpoints,但是这并不意味着你不能与它进行通信。这只是表示它只使用一个双向的Control Endpoint。这并不意外,马达是很慢的且不需要大量的数据来控制。

对比下 视频/摄像头 设备:

Device Descriptor:

bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x045e Microsoft Corp.
idProduct 0x02ae
bcdDevice 1.0b
iManufacturer 2 Microsoft
iProduct 1 Xbox NUI Camera
iSerial 3 A00366A08793039A
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 16mA
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 0x81 EP 1 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0bc0 2x 960 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0bc0 2x 960 bytes
bInterval 1
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

该设备拥有2个Isochronous Endpoints,它们都是IN类型(data going IN to the Computer).This makes sense:Kinect有一个IR深度摄像头和一个普通的VGA摄像头。俩个摄像头对应俩个端点。当然,这里没有提到一个Control endpoint,这个Control endpoint 被用于设置光圈(aperture),伽马校正,任何内置过滤器,等等。

 

4. Driver-maker

 好了,现在回到我们的马达上。我们准备开始发送数据来通过Control endpoint。对于Mac和Linux类型的电脑,驱动不需要发送或接收数据直接通过USB。

对于Windows电脑,这里必须有某种驱动程序来为我们抢占硬件设备。通常,驱动程序是非常复杂的,就像一个插入操作系统的接口。 Like the cameras would show up as a camera device, the microphones as an audio device. 我们还没有准备一个详细的驱动程序,我们将要做的是一个“壳驱动(shell driver)”,这个壳驱动没有操作系统的能力,但可以让我们从软件发送一些命令给硬件。

再次提醒, Mac/Linux people have this built into the OS kernel so skip this part if you don't use windows.

至于我们壳驱动,我们使用一个USB库 libusb,这是用于Windows系统的,  libusb-win32 go there and download it.

我们运行inf-wizard (这个会制作我们自己的壳驱动)

Kinect:DIY Kinect Hacking(一)(原创)_第2张图片

最重要的部分是输入匹配的VID和PID,我们前面所发现的部分。

Kinect:DIY Kinect Hacking(一)(原创)_第3张图片

Kinect:DIY Kinect Hacking(一)(原创)_第4张图片

现在,当你插入Kinect的时候,it will attach itself the the LibUSB-win32 device driver。

Kinect:DIY Kinect Hacking(一)(原创)_第5张图片

We didn't make matching drivers for the audio or camera so those are still driver-less.

 

5. Installing Python & PyUSB

现在我们需要开始发送命令到USB设备。我们所知道的最快最容易的方法是使用LibUSB库并结合一个脚本语言,如:Python。There are LibUSB bindings for C and C++ and Per。但我碰巧更喜欢Python。

If you don't have python installed, do that now.

接下来, install PyUSB by downloading it and running python setup.py install in the expanded directory。

Kinect:DIY Kinect Hacking(一)(原创)_第6张图片

 

6. Attaching to the device

让我们开启第一个简单的例子,这段程序将会把自己附加到有问号标志的设备上。

import usb.core

import usb.util
import sys

# find our device
dev = usb.core.find(idVendor=0x045e, idProduct=0x02B0)

# was it found?
if dev is None:
raise ValueError('Device not found')

# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()

print "all done"

注意,我们寻找我们之前所发现的VID/PID设备。我们不发送任何数据。当Kinect没有加入电脑时你会得到一个错误信息。

Kinect:DIY Kinect Hacking(一)(原创)_第7张图片

如果Kinect已经插入,那么这里不会错误。

Kinect:DIY Kinect Hacking(一)(原创)_第8张图片

 

7. What message to send?

 (续)

你可能感兴趣的:(Kinect:DIY Kinect Hacking(一)(原创))