Blog: Android
Tearing down and reverse engineering Android (toys)
Today, I’m going to go onto a different track. I’m going to be discussing breaking a toy apart. I saw a TV advert for the ApPen which sort of intrigued me. It connects to a device and acts as a touch pen and can provide some extra controls.
I’m a Yorkshireman buying so something called ApPen, which I’d pronounce as ‘appen, appealed to me, plus my kid could do with some pen holding practice. So I looked around for the cheapest price and spent a grand total of seven British Pounds on the toy.
And here it is, the green pads are just finger holds, not buttons even though they look like them:
On the other side of the pen is a small speaker grille.
A spare “head” came in the box. Let’s get this one out of the way first: it’s just a “squidgy” pen head that you could find on many cheap tablet pens that have enough “feel” to be picked up by the device’s digitiser as a “touch”. The head can be depressed until it is almost flush with the plastic.
The button has two positions: 1 and 2, and the instructions tell you to toggle them depending on whether it works. More on this later.
So, the important bit is the standard 4-way male audio jack: it works through the headphone socket. There is a lot of stuff that can be done through the headphone socket: a two way data flow can happen through the analogue audio stream (like the cassettes we used to use on computers in the 80s) using the audio out and microphone lines. We can even pass digital data by altering the voltage on the ground connector, which is how the “remotes” on most headsets work.
Also, depending on the hardware, we can even create a console connection through it.
Setting it up on a Tablet
So, with all these possibilities, this was looking like an interesting thing to play with. So, I get one of my test/dev tablets, which I’d rooted (I used a Medion Lifetab, as it was there and sitting unused) and downloaded the software through the Play store. To do this I had to accept some weighty permissions:
The screenshot was taken on a Hudl as that was at hand whilst writing this up. Those are scary permissions: they can allow the app to read a significant amount of data about you and use it for its own purposes. It can read the contact details for active calls, read and write to you4 SD card (and hence, all your photos), it can allow in-app purchases from Play, it can enumerate the apps running on your device and finally it can use accounts on your device – i.e. it can post to Google Plus/Facebook/Twitter as if you were doing it.
Needless to say, that ApPen is going nowhere near the family tablet.
Oh well, I’m here now, time to see how it works, so I follow the app’s prompts, plug it in to the tablet and… nothing, not a sausage. It simply didn’t work. There was a thin tinny sound coming from the speaker grille though.
So, it appears that not only does the app require a ridiculous amount of permissions, it is a dud. But, unlike most people I have a lot of tablets, so I try it on one of my Hudls and… nothing again.
Right I thought, it’s time to see whether this is actually trying to do anything, let’s have a look at the code.
Looking at the App
Android apps are built into .apk files. This is a simple zip file with roughly the same format as a Java .jar file (because they’re based on them). The .apk files of installed applications are usually stored in /data/app (this can change with multiple users or offloading to the SD-card). /data/app is owned by the system user and not visible to the shell user, although its files are world readable.
That’s easy to get around. I’ve rooted my device after all; so I enabled ADB and connected the device to my laptop to get the package filename, then I can pull it off the device:
shell@android:/ $ su
su
shell@android:/ # cd /data/app
cd /data/app
shell@android:/data/app # ls *appen*
ls *appen*
it.giochipreziosi.appen-1.apk
shell@android:/data/app # exit
exit
shell@android:/ $ exit
exit
c:\>adb pull /data/app/it.giochipreziosi.appen-1.apk
4185 KB/s (41529714 bytes in 9.690s)
I now have the app’s file locally and I can apply some tools to read it. The first thing to do is to attempt to decompile it.
There are several ways that Android apps can be written, but the most common and most device neutral is to use the Android SDK. Using this the apps are written in Java, which is compiled into Java bytecode, which is then further compiled into Dalvik bytecode for running on the Android device’s Dalvik virtual machine.
Dalvik is a virtual machine (e.g. the Java runtime, Flash runtime, .NET runtime etc.) that has been customised for mobile usage.
From our perspective this is irrelevant, but what we can take from this is that there is a defined process for taking Java code and compiling it into an executable file. Because there is a defined process it means we can reverse it. We could use the baksmali disassembler to disassemble this but this is a bit too low level. As Java bytecode is quite high level we can actually decompile it to get something quite close to the original source code.
First we need to convert the Dalvik opcodes into the Java bytecodes, fortunately there is a program to do this for us: dex2jar.
So we can run this and it will convert all the .dex (Dalvik Executable) files in the .apk to .class (Java class files) and do some other tweaking to return a standard Java .jar file:
dex2jar it.giochipreziosi.appen-1.apk -> it.giochipreziosi.appen-1-dex2jar.jar
Now we have it converted, we could potentially run this in a Java VM, although it would probably not work well as the Android libraries wouldn’t be present; instead we can now decompile it by loading into the jd-gui Java decompiler.
There are two things that this immediately shows us:
- The class com.Zirak.APPen.AppenDetectorActivity appears to be the code to detect the device.
- It has a compiled library of unity3d.player in the .jar; this implies that the app has been written using Unity (a.k.a Unity 3D). This will get more complex (see later).
So now, we can see how it detects the pen, to cut a lot of code analysis short, it’s in the method com.Zirak.APPen.AppenDetectorActivity.HeadsetReceiver.onReceive (editing out superfluous code for brevity):
{
int i=1;
[…]
localInteger1 = Integer.valueOf(paramIntent.getIntExtra(“state”, 0));
[…]
localInteger2 = Integer.valueOf(paramIntent.getIntExtra(“microphone”, 0));
[..]
if ((localInteger1.equals(Integer.valueOf(i))) && (localInteger2.equals(Integer.valueOf(i) ))) {}
for (;;)
{
final Boolean localBoolean = Boolean.valueOf(i);
Log.v(“APPenDetectorActivity”, “APPen is connected: ” + localBoolean);
if (localBoolean.booleanValue()) {
this.m_AudioManager.setStreamVolume(3, this.m_AudioManager.getStreamMaxVolume(3), 0);
}
new Handler(Looper.getMainLooper()).post(new Runnable()
{
public void run()
{
UnityPlayer.UnitySendMessage(“APPenDetector”, “APPenConnectionStatusChanged”, localBoolean.toString());
}
});
This is part of the code of a BroadcastReceiver, a type of object in Android that receives broadcast intents (a message) from the system. A bit of digging tells us that it’s intended to receive ACTION_HEADSET_PLUG intents. We can look this up in Android’s API documentation and can see that it provides the following extra information:
- state – 0 for unplugged, 1 for plugged.
- name – Headset type, human readable string
- microphone – 1 if headset has a microphone, 0 otherwise
So, in essence the code is saying: wait for an ACTION_HEADSET_PLUG intent, if we receive one that has state and microphone equal to 1; then send a message to the Unity subsystem, to set APPenDetector.APPenConnectionStatusChanged to 1.
We’ll go into the Unity end of this in a bit. Makes sense really doesn’t it? So why doesn’t this work?
This is something to do with a bit of a design flaw on ApPen’s part and the difference between hardware. I can explain it better by showing you an extract from the system log when the ApPen is connected, first from a Lifetab:
D/SurfaceFlinger( 145): Screen acquired, type=0 flinger=0x405a73a8
V/WiredAccessoryManager( 394): newName=Headset newState=2 headsetState=2 prev h
eadsetState=0
V/WiredAccessoryManager( 394): device Headset connected
D/CallManager( 610): <–mStateReceiver–> state=1,microphone=0
D/PhoneApp( 610): mReceiver: ACTION_HEADSET_PLUG
D/PhoneApp( 610): state: 1
D/PhoneApp( 610): name: Headset
D/PhoneApp( 610): updateProximitySensorMode: state = IDLE
D/MISC ( 1073): Received broadcast Intent { act=android.intent.action.HEADSET
_PLUG flg=0x40000010 (has extras) }
And now, from a Nexus 4:
bits=SW_HEADPHONE_INSERT SW_MICROPHONE_INSERT mask=14
V/WiredAccessoryManager( 537): newName=h2w newState=1 headsetState=1 prev heads
etState=0
D/audio_hw_primary( 174): out_set_parameters: enter: usecase(1: low-latency-pla
yback) kvpairs: routing=0
D/audio_hw_primary( 174): out_set_parameters: exit: code(1)
D/audio_hw_primary( 174): out_set_parameters: enter: usecase(0: deep-buffer-pla
yback) kvpairs: routing=0
D/audio_hw_primary( 174): out_set_parameters: exit: code(1)
V/APPenDetectorActivity( 4244): APPen is connected: true
V/WiredAccessoryManager( 537): device h2w connected
The headsetState is 1 on the Nexus 4; but 2 on the Lifetab, a quick look at the source code for WiredAccessoryManager shows us that this value is a bit fireld with the most bits being:
private static final int BIT_HEADSET_NO_MIC = (1 << 1);
private static final int BIT_USB_HEADSET_ANLG = (1 << 2);
private static final int BIT_USB_HEADSET_DGTL = (1 << 3);
private static final int BIT_HDMI_AUDIO = (1 << 4);
In translation, a status of 2 means that BIT_HEADSET_NO_MIC is set. I can also tell you that if you attach a normal phone headset you’ll get the same response, even though the headset will still work on both devices.
I can’t be certain on this behaviour, but I can make an educated decision: the Lifetab and the Hudl are both based on the Rockchip RK3188 which is a chipset design for use in tablets and compact computers. The chipset does not support a GSM radio and has never been used in a phone. I suspect that detecting whether headphones have a microphone wasn’t a priority in its kernel driver and wasn’t fully implemented. This may be because of patents or may simply be an oversight.
So, the ApPen should never work on a Rockchip device, even though it does “work” due to a design flaw in the software and a lack of hardware testing.
But, how does it work?
I said I’d get back to this, I just took a bit of a detour. To actually find out how it takes a reading we have to look in the Unity code, not in the application.
Unity is a system for writing games and other similar rich media content in a similar way to Flash or Silverlight, but it is tuned more for games than for serious apps or silly animations. It runs on top of the mono virtual machine. Mono is an open source implementation of the .NET virtual machine and environment.
I said this would get complex didn’t I?
We’ve looked at Dalvik bytecode, Java bytecode and now we’re going to look at .NET (aka MSIL) bytecode.
Fortunately we don’t need to do any translation first, and we can open it directly within ilspy, which will allow us to decompile the code. I’ve done a bit of work with Unity in the past, so I know that we are looking for something that will have a path of Data/Managed/Assembly-UnityScript.dll.
After a bit of digging we find this in the apk, under the assets directory. The easiest way to extract this it to use apktool (we could use Androguard too, but I didn’t have that installed on this host and I’m lazy). So I extracted the apk to a directoy and loaded the DLL into ilspy:
We can now delve into it to find out what it uses.
To cut a long story of code analysis and path finding short it reads the value of the “weight” of the pen by reading the property APPen.APPenVolume. This is assigned by APPen.Update():
num = RuntimeServices.UnboxSingle(this.GetAveragedVolumeIOS());
[…]
APPen.APPenVolume = this.NormalizeData(this.newVolume, APPen.minValue, APPen.maxValue, (float)0, (float)100);
Notice how it is using a method for iOS, on Android.
So, what is it?
So, code aside. What the heck is the pen and how does it work? What it is is a glorified hands free headset with a small tinny speaker and a simple driver to read the volume. There is a microphone under the head which picks up changes in the sound of it being pressed/squashed, a “pressure sensor” of sorts.
There are two ways of proving this hypothesis:
- Record the input from the pen
- Attempt to use a headset instead of the pen
Let’s try the first. For this we’ll use the open source Audacity application as it produces a nice graphic to show what is happening:
I’ve added red bars to show where I’ve pressed the pen down and green bars to show where I released it. We can see it’s just monitoring the amplitude of sound made by the movement of the microphone.
So, let us test this by using a hands free set instead of the pen for the Nexus 4. The app’s drawing screen uses the pressure of the pen to thicken the line, to this end we will be drawing two lines with a finger:
- A normal line
- A line whilst simultaneously blowing into the microphone of the headset
In theory this should produce one thin line and one thick line. Let us try it:
I added the 1 and 2 in paint later just to highlight the effect, as a photo of me blowing into a hands free kit wouldn’t be exciting.
The button
What does the button do? Quite frankly I’m not sure; the website states that some devices such as the LG Optimus G Pro, the Sony Xperia Ray and a host of Wiko devices need it in the “Up” position, but without explaining why.
Recording with the switch up shows a low amplitude signal. So I doubt I’ll ever work it out without cracking the case open.
In Conclusion
So what are you paying for: basically a cheap hands free headset in the shape of a pen, with some dodgy application which requests shed loads of permissions and has some form of dodgy in-app purchases.
The device itself could be a good idea with better software, but as published it’s next to useless and doesn’t even work on a number of devices.
It presents no security risk other than the lightening of your wallet in buying something that will end up never being used.
Amendment – the guts
I wasn’t going to crack it open; but I was waiting for something to finish processing and saw the device on my desk, so I thought “why not?” I grabbed my trusted metal spudger and aggressively gently pulled it apart with quite a bit of minimal damage.
And here’s the insides:
It’s all held together by 3 plastic pins. What you can see is pretty much wires: wires from the cable to the switch, to the speaker and to the masking tape at the nib of the pen.
Peeling back the masking tape shows us the tiny circuit board:
So, how this works is to use the plastic nib to move a slider, most likely a potentiometer, which will alter the resistance of the signal. Finally note the way that the resistor has been soldered – there’s a risk that the pins could touch, as it’s only held together with masking tape.
Finally, if you thought the nib of the pen had any special magic, well, I took that apart too:
And, that’s it: a rubber end and a middle inner, just like the cheap tablet pens you can get from £1 shops.