Just a guy with a love for tech

Fun with USB Rocket Launchers and Python

Adam L October 10, 2016

USB LauncherI’ve had this USB Rocket Launcher gathering dust in my cupboard for some time but never really used it all that much, It’s primarily aimed at Windows users and has no software for other operating systems or documentation on how it works.

So last weekend I brought it into my workplace for some office warfare, and since our office is open plan this made it an ideal battleground, fueled by some Python.

UPDATE: Code has been posted to TCC’s GitLab, you can get it here: https://git.thecodecache.net/aleyshon/USB-Sentry

In order to make this work from within Python we needed to know what command were being sent to the device, so that we could replay them at our leisure.

To do this I used some software called USBPCap along with Wireshark to dump out the packets being sent.

The device I have uses the Vendor ID of 0x2123 and a Product ID of 0x1010. (DreamCheeky Thunder)

All commands sent to the device had a Request Type of 0x21 (Host to Device) and a Request of 0x09 (SET_CONFIGURATION). The device never returns any data. It is one way communication.

All payloads sent to the Rocket Launcher were always 8 bytes long and always started with 0x02 or 0x03, Followed by a single varying byte, Like this:

<pre class="lang:default decode:true">0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00
0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00

Interesting! It seems the other six bytes were not used by any of the commands.

Eventually I had managed to capture all the commands being sent, one at a time and built up a little data sheet about it’s protocol, which was very simple:

<pre class="lang:default decode:true" title="Turret Protocol">Turret Down
0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00

Turret Up
0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00

Turret Left
0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00

Turret Right
0x02,0x08,0x00,0x00,0x00,0x00,0x00,0x00

Turret Stop
0x02,0x20,0x00,0x00,0x00,0x00,0x00,0x00

Fire
0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00

LED On
0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00

LED Off
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00

With this data in hand, it was time for some Python! We opted to use the pyUSB library for interfacing with the device.

Here was the final code we came up with, it picks a random number between 1 and 6 and performs an action associated with that number, we will be uploading this to GitLab shortly.

<pre class="lang:python decode:true " title="The final code">import os
import sys
import time
import usb.core
import random

class sentry:
    def __init__(self):
        # First try to find the USB device.
        self.dev = usb.core.find(idVendor=0x2123, idProduct=0x1010)
        if self.dev is None:
            raise ValueError('Launcher not found.')
        if self.dev.is_kernel_driver_active(0) is True:
            self.dev.detach_kernel_driver(0)
        self.dev.set_configuration()
       
    def mainloop(self):
        while(True):
            
            # Pick a random number between 1 and 6.
            action = random.randint(1,6)
            
            # Turn the turrentLED On.
            self.turrentLED(0x01)
            
            if(action == 1):
                print 'Moving Left'
                self.turretLeft()
                self.sleepRandom()
            elif(action == 2):
                print 'Moving Right'
                self.turretRight()
                self.sleepRandom()
            elif(action == 3):
                print 'Moving Up'
                self.turretUp()
                self.sleepRandomShort()
            elif(action == 4):
                print 'Moving Down'
                self.turretDown()
                self.sleepRandomShort()
            elif(action == 5):
                print 'Fire!!'
                self.turretFire()
                time.sleep(4)
            else:
                print 'Flash LED'
                for x in range(0, 2):
                    self.turrentLED(0x01)
                    time.sleep(0.5)
                    self.turrentLED(0x00)
                    time.sleep(0.5)
            
            # Turn the LED Off.
            self.turrentLED(0x00)
            
            # Stop the turret from moving.
            self.turretStop()
            
            # Wait a second until next action
            time.sleep(1)
                
    def turretUp(self):
        self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00]) 
    
    def turretDown(self):
        self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00])
    
    def turretLeft(self):
        self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00])
    
    def turretRight(self):
        self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x08,0x00,0x00,0x00,0x00,0x00,0x00])
    
    def turretStop(self):
        self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x20,0x00,0x00,0x00,0x00,0x00,0x00])
    
    def turretFire(self):      
        self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00])
    
    def turrentLED(self, cmd):
        self.dev.ctrl_transfer(0x21, 0x09, 0, 0, [0x03, cmd, 0x00,0x00,0x00,0x00,0x00,0x00])
    
    def sleepRandom(self):
        r = random.randint(1,2)
        print 'Wating for {0} seconds'.format(r)
        time.sleep(r)
        
    def sleepRandomShort(self):
        r = random.random()
        print 'Waiting for {0} seconds'.format(r)
        time.sleep(r)
        
if __name__ == '__main__':
    # We will need to be root to send custom crafted USB packets.
    if not os.geteuid() == 0:
        sys.exit("Script must be run as root.")
    sentry().mainloop()

Back to top