Skip to content

Level 3: KPA (Rev)

This is an Android reversing challenge.

The APK is corrupted such that it cannot be installed. Fortunately, it can still be extracted by apktool, which allows the compiled bytecode in classes.dex to be decompiled by JADX.

The decompilation reveals two important classes, com.tisc.kappa.MainActivity and com.tisc.kappa.sw.

java
package com.tisc.kappa;

public class sw {
    static {
        System.loadLibrary("kappa");
    }

    public static void a() {
        try {
            System.setProperty("KAPPA", css());
        } catch (Exception unused) {
        }
    }

    private static native String css();
}

The sw class loads a JNI library called kappa with a method css. In the a method, the native method css is called and its return value is stored in the system property KAPPA. In the lib directory we can find several subdirectories containing libkappa.so, which is the native library compiled for different architectures.

java
public void M(String input_string) {
        char[] charArray = input_string.toCharArray();
        String valueOf = String.valueOf(charArray);
        for (int i2 = 0; i2 < 1024; i2++) {
            valueOf = N(valueOf, "SHA1");
        }
        if (!valueOf.equals("d8655ddb9b7e6962350cc68a60e02cc3dd910583")) {
            ((TextView) findViewById(d.f3935f)).setVisibility(4);
            Q(d.f3930a, 3000);
            return;
        }
        char[] input = Arrays.copyOf(charArray, charArray.length);
        charArray[0] = (char) ((input[24] * 2) + 1);
        charArray[1] = (char) (((input[23] - 1) / 4) * 3);
    	// Other similar lines of code
        charArray[24] = (char) ((input[0] + 1) / 2);
        P("The secret you want is TISC{" + String.valueOf(charArray) + "}", "CONGRATULATIONS!", "YAY");
    }

The MainActivity class contains the M method that takes in an input string, checks it against some hash. If the hash compares correctly, some transformations are performed on the input, which is then printed out concatenated with the flag string.

Making an educated guess, we can assume that the input string should be the return value of the css function from earlier. Our next task is then to obtain this value.

There are a few ways to accomplish this:

  1. Analyze libkappa.so to find out how the css method works.
  2. Make small modifications to the Smali bytecode of the sw class such that instead of System.setProperty, the Log.v method is called instead, printing the result of css() to the Android logs. In theory, this is much easier because we don't need to reverse the css method.

I went with method 2 because I happened to have an Android phone available to run the APK.

Here's the Smali bytecode for the sw.a method:

.method public static a()V
    .registers 2

    :try_start_0
    const-string v0, "KAPPA"

    invoke-static {}, Lcom/tisc/kappa/sw;->css()Ljava/lang/String;

    move-result-object v1

    invoke-static {v0, v1}, Ljava/lang/System;->setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    :try_end_9
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_9} :catch_9

    :catch_9
    return-void
.end method

In theory, all we need to do is change Ljava/lang/System;->setProperty to Landroid/util/Log;->v, then rebuild the APK, the install and run it.

In reality, building an Android app from a broken APK is not so easy. Here's a quick overview of the issues I faced

  1. android:extractNativeLibs="true" needed to be set in the application tag of AndroidManifest.xml

    a. But AndroidManifest.xml is stored in a binary format in the APK, so I used this library to convert between the two.

  2. Once the app opened it crashed immediately because Android wasn't happy about it not using a theme derived from AppCompat. This was particularly annoying because the answers on StackOverflow did not work. I ended up just copying the Smali code from sw.a into the constructor of MainActivity so it could at least print the result before crashing.

  3. Lots of other issues that I forgot

Final MainActivity.smali:

.class public Lcom/tisc/kappa/MainActivity;
.super Landroidx/activity/b;
.source "SourceFile"


# direct methods
.method public constructor <init>()V
    .locals 2
    
    const-string v0, "KAPPA"

    invoke-static {}, Lcom/tisc/kappa/sw;->css()Ljava/lang/String;

    move-result-object v1

    invoke-static {v0, v1}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I


    invoke-direct {p0}, Landroidx/activity/b;-><init>()V

    return-void
.end method

After running the APK, we finally get the result of the css method: ArBraCaDabra?KAPPACABANA!. Now, all we need to do is run MainActivity.M with ArBraCaDabra?KAPPACABANA! as the input and get the flag: TISC{C0ngr@tS!us0lv3dIT,KaPpA!}