In the spirit of our 26 October
meeting on hacking, I wanted to share this hacking story with everyone.
I like writing
APIs for inexpensive robot toys like the
AR.Drone and the
Neato XV-11. In a recent undergraduate robotics
class, a couple of students and I got found an open-source
project for driving the Brookstone Rover from an Android device. We bought a
Rover 2.0, but we had no luck in getting this code to work with it.
Following the advice in
Violent Python, I figured I'd try some wireless snooping to see what was in the messages being passed from the handheld device to the Rover. I bought the recommended
Hawking Technology Hi -Gain Wireless-150N USB Network Adapter, plugged it into my Ubuntu machine (actually, an iMac running Ubuntu under VMWare), and installed and ran
scapy. This showed some traffic, but it was difficult to work with. Some googling revealed that
Wireshark was the tool of choice for this sort of thing, so I installed it and set up a filter to look at messages to/from IP address 192.168.1.100 (the Rover's fixed network address.) Looking at the items tagged "continuation or non-http traffic", I saw lots of traffic between this address and 192.168.1.X, where X was the ad-hoc address assigned to the handheld device by the rover -- 2, 3, 4, etc.) Most of these messages started with the string
MO_O, as I expected from the code in RoverOpen.
Running the app a few times revealed a pattern where the handheld device would send the Rover a message starting with
MO_O 0 ..., the Rover would reply with
MO_O 1, the handheld would send back,
MO_O 2 ..., and the Rover would reply with
MO_O 3 .... The 0 (first) message was always the same, but the 3 message ended in different bytes every time. This looked like some kind of
handshaking to me. I knew that the Rover AC-13 (the predecessor of the 2.0) used an open password system (username = AC-13, password = AC-13), but this seemed like some kind of encryption. Perhaps I needed a different strategy.
Looking at a
teardown page for the Rover 2.0, I saw that it had a
UART that might allow me to talk open a console to the Rover. I bought a USB / UART adapter
cable, soldered the wire ends to a three-pin female R/C connector, connected the Rover to my iMac, and turned on the Rover. Sure enough, this revealed a new
/dev/tty.* file. I ran
/usr/bin/screen on this file at the standard 115200 baud rate, and was able to see the Linux boot sequence for the Rover in my terminal window. I was able to run a few Linux commands like ls and cd, but a quick glance around the file system failed to reveal any useful source code that would allow me to reverse-engineer the encryption /handshaking. There was also an annoying output of a single digit to the console once every second, which interfered with my typing into the console. Based on the fact that this number eventually dropped to 1 before the batteries ran out, it must have been a single-digit representation of the battery level that you can retrieve from the Rover wirelessly -- perhaps a debugging printout left in the firmware.
I figured that a look at some more up-to-date source code running on the handheld device might reveal what was going on. So I downloaded the free
Rover 2.0 app from Google Play onto my Android device. Then I downloaded the free
ES File Exporer app, which allowed me to save the .apk file for the Rover 2.0 app. Plugging my Android device into a Windows 7 machine revealed a volume in which I could find the
.apk file (it might have worked on OS X or Ubuntu, but I found it most reliable on Windows.)
So now I had the .apk file. I turned it into a
.jar file using
dex2jar and started looking for a good Java
decompiler. After trying several, I found that the free online trial version from
SecureTeam gave me the most legible Java source code (fewest labels, goto's, etc.) Sure enough, the sensibly-named WifiCar.java was using
Blowfish encryption to respond to the "challenge" from the Rover. Curiously, the BlowFish class was using a P-array of all zeros instead of the digits of Pi, which I guess is still good enough to foil random key hacking.
By looking back-and-forth between the decompiled Java source and the Wireshark messages, I was able to write a little Java class to do some basic things on the Rover -- spin the treads, raise/lower the camera, and turn the lights on and off. To understand the media (video, audio) messages coming back from the Rover (which begin with
MO_V), it helped to look also at the
documentation for the
Foscam web camera that provides the core functionality of the Rover.
As expected, the video was coming in the form of
JPEG bytes, which I could save to disk and then open using any image-viewing program. At this point I translated my little Java classes into Python and decided to try my luck with the audio messages. These proved a little trickier. Audio turned out to be encoded using
ADPCM, at a rate of 8192 Hz (a standard rate used as the default in e.g. Matlab), sent in chunks of 160 samples, with some ADPCM parameters tagged on at the end. Saving the audio samples to a file and playing them back in Matlab revealed audible signals with a strong low-frequency noise component.
With the full functionality of the Rover 2.0 at my disposal in Python, I wrote a little program that uses
PyGame to drive it around via a PS3 controller and
OpenCV to display the images. You can download the whole set of files from
here. Of course, the real excitement of a Python API is the potential for autonomous behavior via machine vision, speech recognition, etc. So although this hack proved to be a lot more work than we'd originally thought, I'm hoping that it will open the Rover 2.0 as an inexpensive platform for exploring robotics.