Reverse Engineering:
Writing a Linux driver for an
unknown device
Ľubomír Rintel <lkundrak@v3.sk>
OSSConf 2013, Žilina
BTC: 1A28Etzh7zsK2Bq36qvPKJi18s53M9B2FU
Our device
●

Unknown to Linux

●

No documentation

●

No Google hits for chip

●

Desperate users in
Ubuntu forums
The Plan
●

Make it work in Windows

●

Capture what happens

●

Find image data

●

Mimic the behavior in userspace

●

Transform into a kernel module
USB
USB Architecture
●

Network of Host, Hubs and Devices
USB Addresses
●

Bus & Device number

Host
Device 1:1
Hub

Device 2:1
Hub

Device 2:2
Flash Drive

Device 3:1
Mouse
USB Addresses
$ lsusb
Bus 001
Bus 002
Bus 002
Bus 003
$ lsusb
...

Device
Device
Device
Device
-v

001:
001:
002:
001:

ID
ID
ID
ID

1d6b:0002
1337:abcd
1337:0123
dead:b4b3

Linux Foundation 2.0 root hub
Trololol USB 1.1 Hub
Trololol Flash Drive
Random Mouse
USB Device
●

Self-describing

●

Endpoints
●

CONTROL

●

INTERRUPT

●

BULK

●

ISOCHRONOUS

●

Endpoints grouped into Interfaces

●

Interfaces grouped into Configurations
Our device
Device
Alternate setting 0
Endpoints:

Alternate setting 1
Endpoints:

0x81

Isochronous IN

0x81

Isochronous IN

0x82

Bulk

IN

0x82

Bulk

IN

0x83

Bulk

IN

0x83

Bulk

IN

0x84

Interrupt

IN

0x84

Interrupt

IN
The Plan
●

Make it work in Windows

●

Capture what happens

●

Find image data

●

Mimic the behavior in userspace

●

Transform into a kernel module
Windows & VirtualBox
Wireshark & usbmon
What did we see
●

Number of CONTROL requests

●

ISOCHRONOUS packets once capture starts
RGB

R

R

R

R

R

R

R

R

G

G

G

G

G

G

G

G

B

B

B

B

B

B

B

B
YUV2
Y

Y

Y

Y

U1 U1 U1 U1

Y

Y

Y

Y

V1 V1 V1 V1

Y

Y

Y

Y

U2 U2 U2 U2

Y

Y

Y

Y

V2 V2 V2 V2
LibUSB
●

We could replay the traffic

●

In userspace – no kernel hacking needed

●

C, Python & Perl bindings

●

Now we need to find start & end of the picture
Test image
0xff00ff00

0xaaaaaaaa

0x00ff00ff
0x00000000
0x80808080
Frame format
88 01 00 00
88 01 00 01
...

88 01 02

cf

...

cf

88 03 00 00
...

00 00 00 00 • 15

Frame number
● Even/odd
● Chunk number 0 – 0x2cf = 719
●

88 02 80 00
88 02 82

xx xx xx xx • 240

740 x 480 YUV2 Interlaced (NTSC)
To kernel!
●

Booooring!

●

A module

●

USB framework
●

●

Video4Linux2
●

●

Linux Device Drivers: http://lwn.net/Kernel/LDD3/
LWN Series: http://lwn.net/Articles/203924/

Videobuf2
●

LWN Article: http://lwn.net/Articles/447435/
USB

Our code

Hardware

Video4Linux2

Videobuf2

Userspace

Architecture
Video4Linux2
●

Provide a device with known API
●
●

read(), write()

●

ioctl()

●

●

open(), close()

mmap()

Negotiate format with userspace
Videobuf2
●

Manages buffers of frames

●

Connects to Video4Linux2
●

read(), write(), mmap()

●

some ioctl()s
–
–

Start/stop capture
Exchange buffers with userspace
USB framework
●
●

Setup the device
Allocate buffers for exchange of data with
device

●

Handle start/stop

●

Isochronous callbacks
●

Copy data from USB buffers to Videobuf2 buffers
USB

Our code

Hardware

Video4Linux2

Videobuf2

Userspace

Architecture
All done!
Questions?

Found this useful? My Bitcoin address is:
1A28Etzh7zsK2Bq36qvPKJi18s53M9B2FU

Reverse Engineering: Writing a Linux driver for an unknown device