Reverse engineering a chinese USB e-massage app

Once I stumbled upon an interesting product, a massage device, which was powered solely by USB. Furthermore, it used a Micro-B plug, and was supposed to be connected to a smartphone, via OTG (imagine how much of a power drain that can be!). Sadly at the time of the writing of this article I couldn't find this product available anywhere on the internet, and their site seemed to be down as well. The only available information is their companion app on Google Play.

At first glance, this might seem your average dirt cheap chinese setup: if the hardware won't short and fry itself, then the app will steal and sell all of your available data, so I decided to mitigate at least the second risk and find out how the app works; more precisely, how it communicates with the end device. With reverese engineering such things, we have basically two options:

USB Micro female to USB male adapters were surprisingly hard to come by, so I decided on the second option. Android apps are generally easy to decompile and modify, so after using the apktool-dex2jar-jdgui trio, I had something which closely resembled to source code.

The app was partially obfuscated, but after a glance at the package names, I could narrow down where most of the driver logic would be:

com.developer.cd432rs.eMassage.devicecontrol.UsbControlService

Android USB host has a pretty well defined interface, so I could further narrow down my search knowing what transfer methods are present there.

private void o() {
	if (this.m != null) {
		System.out.println("Send command + BackgroundControllActivity sendCommand()");
		this.m.controlTransfer(33, 9, 769, 256, this.n, this.n.length, 0);
		Log.d("Command Send", p());
		return;
	} 
	System.out.println("mUsbConnection null");
}

If you take a look at the documentation, you can treat the first four magic numbers... well as magic numbers; only the first one has a bitfield-y meaning behind it. The next two parameters specify the sent data and its length, the last one is timeout, which is irrelevant in this case. To sum it up:

Transfer typeControl
bmRequestType33 (H2D, Class, Interface)
bRequest9
wValue0x0301 (769)
wIndex0x0100 (256)

Also this app has most of its log messages intact, so with adb, you can log the data of each sent command, as p() is basically a hexdump method:

private String p() {
	String str = "";
	for (byte b1 = 0; b1 < this.n.length; b1++) {
		str = str + String.format("0x%02X", new Object[] { Byte.valueOf(this.n[b1]) }) + " ";
	} 
	return str;
}

The next question is: where did this this.n come from. It's not a hard question, and the log messages trivialize it even further. Here's the init method:

private void l() {
	System.out.println("init!!!");
	this.n = new byte[6];
	this.n[0] = (byte)5;
	this.n[1] = (byte)118;
	this.n[2] = (byte)2;
	this.n[3] = (byte)0;
	this.n[4] = (byte)2;
	this.n[5] = (byte)3;
}

It's a really short protocol, so take a look what each byte does (converted to hex):

05 76 02 00 02 03

There are also two more apps from the same developer (this and this). The first one seems like an earlier version, and maybe a little less obfuscated, as more method names were unmangled. The second is a BLE app, and I'm not sure what purpose it serves, since it's unlikely that the end device is BLE capable.

With that information, you can probably write a similar controller app for this device now. Reverse engineering it was surprisingly easy but a fun experience neverthless.