NDH2k11: Reversing an Android application

In this article I’ll present how I managed to validate the second Reverse Challenge of the prequals of the “Nuit du Hack 2011” that took place on the 2nd/3rd of april. You’ll find the Android application attached here.

Let’s have a look at the application. A simple “Enter Password” button opens a new window, prompting for a vocal password.


ndh2k11 App


I first used dex2jar to convert the Dalvik Executable bytecode into java Bytecode, and jd-gui to navigate through the java disassembled code.


ndh2k11 app code


The ReverseMe class is the main activity; the b class implements an OnClick Listener; the a class seems to encode/decode a given string; the c class contains methods to encrypt static arrays of bytes. Those arrays are interesting:

private static byte[] a = { 90, 5, 88, 88, 13, 13, 90, 90, 10, 4, 9, 11, 93, 90, 11, 15, 93, 95, 5, 93, 5, 8, 8, 88, 90, 95, 9, 14, 90, 8, 13, 94 };
private static byte[] b = { 91, 83, 83, 91, 80, 89, 99, 79, 88, 87 };
private static byte[] c = { 113, 120, 9 };
private static byte[] d = { 93, 82, 88, 78, 83, 85, 88, 18, 79, 76, 89, 89, 95, 84, 18, 93, 95, 72, 85, 83, 82, 18, 110, 121, 127, 115, 123, 114, 117, 102, 121, 99, 111, 108, 121, 121, 127, 116 };
private static byte[] e = { 111, 116, 125, 17, 13 };

When looking deeper in the Listener, a new Intent is created with the argument c.d(). The d() method calls the c.a() method on the static array of byte d. The a() method is used to xor the content of the given array of bytes:

private static String a(byte[] paramArrayOfByte)
byte[] arrayOfByte = new byte[paramArrayOfByte.length];
int i = 0;
while (true)
int j = paramArrayOfByte.length;
if (i >= j)
return new String(arrayOfByte);
int k = (byte)(paramArrayOfByte[i] ^ 0x3C);
arrayOfByte[i] = k;
i += 1;

We now want to modify the code of the application; unfortunately, jd-gui won’t allow you to do that. We will now use apktool to convert the dex bytecode into smali (pseudo-assembly source code), modify it, and repackage the application.

The following code in the Listener is used to create the speech recognition Intent; notice the prompt setting with the static string “Enter password”. We will use this prompt to print some information (like the content of the static arrays of bytes 😉 ):

ReverseMe localReverseMe = this.a;
if (paramView.getId() == 2131034114)
String str = c.d();
Intent localIntent1 = new Intent(str);
Intent localIntent2 = localIntent1.putExtra("android.speech.extra.LANGUAGE_MODEL", "free_form");
Intent localIntent3 = localIntent1.putExtra("android.speech.extra.PROMPT", "Enter password");
localReverseMe.startActivityForResult(localIntent1, 1234);

This code, in smali, looks like the following:

.locals 4
iget-object v0, p0, Lndh/prequals/rce/b;->a:Lndh/prequals/rce/ReverseMe;
invoke-virtual {p1}, Landroid/view/View;->getId()I
move-result v1
const v2, 0x7f050002
if-ne v1, v2, :cond_0
new-instance v1, Landroid/content/Intent;
invoke-static {}, Lndh/prequals/rce/c;->d()Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
const-string v2, "android.speech.extra.LANGUAGE_MODEL"
const-string v3, "free_form"
invoke-virtual {v1, v2, v3}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
const-string v2, "android.speech.extra.PROMPT"
const-string v3, "Enter password"
invoke-virtual {v1, v2, v3}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
const/16 v2, 0x4d2
invoke-virtual {v0, v1, v2}, Lndh/prequals/rce/ReverseMe;->startActivityForResult(Landroid/content/Intent;I)V

We will replace the highlighted line with a call to a(), b(), c(), d() and e() methods to see the content of the arrays:

invoke-static {}, Lndh/prequals/rce/c;->a()Ljava/lang/String;
move-result-object v3

Still using apktool, we repack the patched application into a new apk file. Our new application needs to be signed before installing; we’ll use keystore to create a new keystore, keytool to create a new key, and jarsigner to sign the application. Here is what the a array contains:


ndh2k11 android app screen


This looks like a md5… The b array contains “google_sdk”, c contains “MD5”, d contains “android.speech.action.RECOGNIZE_SPEECH” (used to initialize the Intent object), and e contains “SHA-1”. The c.a() method (returning the md5 hash) is called in the a class (in the b() method). This last method (a.b()) is called in the onActivityResult() method of the ReverseMe class, called after the speech recognition. Here is the code:

if ((paramInt1 == 1234) && (paramInt2 == -1))
ArrayList localArrayList = paramIntent.getStringArrayListExtra("android.speech.extra.RESULTS");
if ((!localArrayList.isEmpty()) && (a.b((String)localArrayList.get(0))))
TextView localTextView = this.b;
String str = a.a((String)localArrayList.get(0));
super.onActivityResult(paramInt1, paramInt2, paramIntent);

This code seeks the results from the speech recognition; if the a.b() method succeeds with the given recognized word, the result of a.a(word) is written in the TextView. So basically, we just have to revert the md5 hash we’ve found, say it to the phone, and it will give us the string we’re looking for. Luckily, there are loads of reverse md5 databases on the world wide web; f9dd11ff6857af73ac9a944dfc52f41b just corresponds to “salope” (bitch, in french). Let’s insult our phone!

Unfortunately, the speech recognition doesn’t work on my phone; after 10 minutes shouting at my phone, I didn’t get any result. So I just patched the ReverseMe class, replacing calls to a.b(localArrayList.get(0)) and a.a(localArrayList.get(0)) with a.b(“salope”) and a.a(“salope”) (in smali, that’s just 2 lines ‘const-string v0, “salope”‘ to add).

here is the result, which is a simple sha1 of “salope”. Could have guessed that by reading the a.a() method…


ndh2k11 reversed android app


Hope this will be useful to someone. Many thanks to Hackerzvoice for their work on the prequals!

The Hackerzvoice slides “Reversing Android” were very useful: http://www.hackerzvoice.net/repo_hzv/meetings/diordna-hzv.pdf

Tags: , , , , ,

One Response to “NDH2k11: Reversing an Android application”

  1. SchematicWizard Says:

    Ce post poutrasse sa mère. Bravo pour le hack =)

Leave a Reply