Baby Android 2 - author: overllama - rev

WriteUp: m1nds

This is the second challenge on APK. We used the same command to extract the file.

apktool d baby_android-2.apk
cd baby_android-2 && tree -L 1
.
├── ActivityMainBinding
├── AndroidManifest.xml
├── apktool.yml
├── kotlin
├── lib
├── META-INF
├── original
├── res
├── smali
├── smali_classes2
├── smali_classes3
├── smali_classes4
└── unknown

Using the jadx decompiler, we decompiled some of the smali files. We want to see what is happening in MainActivity. To do so, we use JADX decompiler to retrieve a Java code from SMALI files. The MainActivity was located in `smali_classes4/byuctf/babyandroid/MainActivity$1.smali. So we used the command :

jadx smali_classes4/byuctf/babyandroid/MainActivity\$1.smali

The command then creates a directory named MainActivity$1 with the outputs of decompilation.

package byuctf.babyandroid;

import android.view.View;
import android.widget.TextView;

/* loaded from: /tmp/jadx-15504538600247676588.dex */
class MainActivity$1 implements View.OnClickListener {
    final /* synthetic */ MainActivity this$0;

    MainActivity$1(MainActivity this$0) {
        this.this$0 = this$0;
    }

    @Override // android.view.View.OnClickListener
    public void onClick(View view) {
        String flagAttempt = MainActivity.access$000(this.this$0).getText().toString();
        TextView banner = (TextView) this.this$0.findViewById(R.id.banner);
        if (FlagChecker.check(flagAttempt)) {
            banner.setText("That's the right flag!!!");
        } else {
            banner.setText("Nope! Try again if you'd like");
        }
    }
}

We can see from the decompiled code that some kind of checks are done using the static function FlagChecker.check. Decompiling the code that gives information on the FlagChecker class (located in smali_classes4/byuctf/babyandroid/FlagChecker.smali) gives us this :

package byuctf.babyandroid;

/* loaded from: /tmp/jadx-12705296425172830130.dex */
public class FlagChecker {
    public static native boolean check(String str);

    static {
        System.loadLibrary("babyandroid");
    }
}

We clearly see that a dynamic library is loaded within the Java code. This library is located in lib/x86_64/libbabyandroid.so

file lib/x86_64/libbabyandroid.so
lib/x86_64/libbabyandroid.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=90037cbe182cf81ad3d59cd28947da7543276d3d, stripped

We can use Ghidra to decompile this dynamic library. The check function can easily be retrieved :

undefined Java_byuctf_babyandroid_FlagChecker_check
                    (_jstring *param_1,undefined8 param_2,uchar *param_3)

{
  long lVar1;
  char *pcVar2;
  long in_FS_OFFSET;
  int iStack_58;
  undefined uStack_29;
  basic_string<> abStack_28 [24];
  long lStack_10;
  
  lStack_10 = *(long *)(in_FS_OFFSET + 0x28);
  _JNIEnv::GetStringUTFChars(param_1,param_3);
  std::__ndk1::basic_string<>::basic_string<>((char *)abStack_28);
  lVar1 = FUN_001206f0(abStack_28);
  if (lVar1 == 0x17) {
    for (iStack_58 = 0; iStack_58 < 0x17; iStack_58 = iStack_58 + 1) {
      pcVar2 = (char *)FUN_00120710(abStack_28,(long)iStack_58);
      if (*pcVar2 !=
          "bycnu)_aacGly~}tt+?=<_ML?f^i_vETkG+b{nDJrVp6=)="[(iStack_58 * iStack_58) % 0x2f]) {
        uStack_29 = 0;
        goto LAB_00120608;
      }
    }
    uStack_29 = 1;
  }
  else {
    uStack_29 = 0;
  }
LAB_00120608:
  std::__ndk1::basic_string<>::~basic_string(abStack_28);
  if (*(long *)(in_FS_OFFSET + 0x28) == lStack_10) {
    return uStack_29;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

The code basically checks for the flag using a special iteration We iterate on each characters in reverse order using i * i, with ‘i’ ranging from 0 to 0x17 excluded. To decode the flag, we just have to iterate on the characters using this iteration from left to right.

def solve():
    reference = "bycnu)_aacGly~}tt+?=<_ML?f^i_vETkG+b{nDJrVp6=)"
    length = 0x17
    result = []

    for i in range(length):
        idx = (i * i) % 0x2f
        result.append(reference[idx])

    flag = "".join(result)
    print(flag)

if __name__ == "__main__":
    solve()
python3 solve.py
byuctf{c++_in_an_apk??}