This is the solution of the OWASP Uncrackable Android Level1. The binary can be found under https://github.com/OWASP/owasp-mstg/tree/master/Crackmes.

 

I started the analysis with loading the apk file into Jadx-GUI. I opened the MainActivity first.

This is a very simple application. The onCreate contains two checks. The first one tests if the device is rooted, the second tests if the application is debuggable. The verify method reads the text from the input and tests its validity. This test occurs in the

if (a.a(obj)) {

line. Since there is no a class among the imports, this class resides in the same package, under sg.vantagepoint.uncrackable1.

The string, which is compared with the input, is calculated runtime. The calculation is a AES, the first parameter of the sg.vantagepoint.a.a.a is the key, the second is the value which will be encrypted.

 

We can solve this challenge several ways:

  1. We can run the application on a rooted device and hook the method, which calculates the secret string and print it out. In this case we have to deal with the root detection.
  2. We can debug the application and print out the secret string. In this case we have to deal with the root detection and the debug detection.
  3. We can create a separate application, copy the relevant classes into the new application and calculate the secret string in it.
  4. We can create a python script, which calculates the secret string.

In this post I will use the hook method to solve the challenge. The tutorial for creating Xposed hook can be found here. I used Android Studio to create the hook. I have two comments regarding Android Studio. First, I disabled the Instant Run option. Second, I set the XposedBridgeApi jar file to provided. By default it is compiled, which causes problems for Xposed framework.

 

I installed the application onto a rooted device. I got the following error message:

First let us deal with the root detection. Look at the onCreate method in the MainActivity. We might hook the c.a, c.b, c.c and b.a methods, but there is a better way. If these tests detect a problem, then method a of the MainActivity is called. We only have to remove the logic from this method. There are two ways to do this. The first one is patching the application: We decompile the apk file with apktool, update the smali code, build the apk again with apktool and finally sign it. Since we also use hooking to solve the challenge, I used hooking method instead. I followed the tutorial to create the hook.

If we set the result to false in the beforeHookMethod, then the original method will not be executed and the device is not detected as rooted:

The next step is dumping the secret string, which is compared with the input during verification. We can query the result of a method in the afterHookedMethod. The output is a byte array, so we have to convert it into a String object and put it into the log.

My hook class looks like this:

owasphook.java

package owasp.uncrackable;

import java.util.Objects;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;


public class OwaspHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

        if (!loadPackageParam.packageName.equalsIgnoreCase("sg.vantagepoint.uncrackable1")) {
            return;
        }

        // Hook class
        XposedBridge.log("HOOKED: " + loadPackageParam.packageName);

        // Bypass restrictions
        XposedHelpers.findAndHookMethod("sg.vantagepoint.uncrackable1.MainActivity", loadPackageParam.classLoader,
                "a", String.class, // method name: a, parameter: String
                new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult(false);
            }

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            }
        });

        // Dump secret string
        XposedHelpers.findAndHookMethod("sg.vantagepoint.a.a", loadPackageParam.classLoader,
                "a", byte [].class, byte [].class, // method name: a, parameter: byte [], byte []
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    }

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        byte[] bArr = new byte[0];
                        bArr = (byte []) param.getResult();
                        XposedBridge.log("SECRET: " + new String(bArr));
                    }
                });
    }
}

I started to watch the device log and tried to verify the string. This dumped the secret string:

And the result: