Co-Author: Lalu Raynaldi Pratama Putra

Have you ever wondered how easily a hacker could take control of your digital life? Perhaps you've seen a friend's social media account get compromised, or maybe you've even experienced a hack firsthand. This article aims to unlock the first door to understanding Mobile App Hacking for Android.

Are you ready to learn the secrets? 🕵️


The Foundation: OWASP MASVS and MASTG

First things first, the OWASP (Open Worldwide Application Security Project) develops standards and guidelines for application security. Their Application Security Verification Standard (ASVS) provides a framework for testing app security and offers developers secure coding practices.

  • MASVS (Mobile Application Security Verification Standard) is the industry benchmark for secure mobile app development. Developers use it to build secure apps, and testers use it to identify vulnerabilities.
  • MASTG (Mobile Application Security Testing Guide) is a comprehensive manual that outlines techniques for assessing security controls defined in MASVS, often by exploiting weaknesses listed in the OWASP Mobile Application Security Weakness Enumeration (MASWE).
Figure 1. OWASP MASVS (left) and MASTG (right).

Cracking the UnCrackable Apps

"MAS Crackmes", also known as UnCrackable Apps, is a collection of mobile reverse engineering challenges. In this article, we'll crack the Android UnCrackable L1.apk.

Figure 2. MAS Crackmes aka. UnCrackable Apps

Prerequisites

Before we begin, ensure you have the following tools:

  1. Android Emulator - Download
  2. Android Debug Bridge (ADB) (optional) - Download
  3. JADX (GUI for static analysis) - Download
  4. Android Studio - Download

Step 1: Obtaining and Installing the APK

Download the APK here: UnCrackable-Level1.apk.

To install it:

  • Drag-and-drop the APK into the emulator (simple way), or
  • Use ADB for installation (because we're feeling fancy 😎):
$ adb install UnCrackable-Level1.apk
Figure 3. The Android UnCrackable L1 Main page

Next, we'll perform static analysis using JADX GUI to examine the code without executing the application.

Open the APK:

$ jadx-gui UnCrackable-Level1.apk

Step 2: Find the Entry point

Check AndroidManifest.xml to locate the <activity> class (entry point):

Figure 4. AndroidManifest.xml file on JADX GUI

Look for android.intent.action.MAIN and android.intent.category.LAUNCHER.

  • android.intent.action.MAIN it indicates, this <activity> class start as a main entry point.
  • android.intent.category.LAUNCHER it indicates, this <activity> should appear in the home screen's launcher, or in anything else that considers itself to be a launcher.

The entry point is sg.vantagepoint.uncrackable1.MainActivity.

💡
When you create a new Android project with default settings, the MainActivity class is automatically generated as the app's entry point.

Step 3: Inspecting onCreate()

Inside the MainActivity class, the onCreate() method is the first to be executed.

Figure 5. onCreate() method in MainActivity class.

It does the following:

A. Checks if the device is rooted:

if (c.a() || c.b() || c.c()) {
    a("Root detected!");
}
    • The c class verifies root status.
    • Obfuscation (e.g., class c) makes reverse engineering harder, aligning with MASVS-RESILIENCE-3.
🔐
Obfuscation is the obscuring of the intended meaning of communication by making the message difficult to understand, usually with confusing and ambiguous language. Android is using R8 to obfuscate code.

B. Checks if the app is debuggable:

if (b.a(getApplicationContext())) {
    a("App is debuggable!");
}
🔐
Tip: Always set debuggable=false in production apps.

C. Sets the UI layout:

setContentView(R.layout.activity_main);

This code tells us which layout is being used to show the UI to the user. Which is in this case is the activity_main file.

Figure 6. The activity_main.xml, file that construct the UI of the MainActivity page

We can easily spot the button to trigger the verification process, and this button will call the verify method as it stated in the android:onClick tag. 

💡
In 2019, Android introduce new version of UI creation using Jetpack Compose. Jetpack Compose UI is generally more secure than XML-based UI for the following reasons:
✔️ It benefits from obfuscation and dynamic UI rendering, making reverse-engineering harder.
✔️ Its compiled nature reduces the exposure of UI structure compared to plaintext XML files.
✔️ Sensitive logic and resources can be hidden more effectively in Kotlin code than in XML.

However, security ultimately depends on developer practices:
✔️ Avoid hardcoding sensitive data in both Compose and XML.
✔️ Use ProGuard or R8 for obfuscation.
✔️ Encrypt sensitive resources when needed.
✔️ Regularly update libraries to avoid vulnerabilities in dependencies.

So, where is the verify method? It should be in the MainActivity class where this activity_main.xml is being called.

Figure 7. The verify(view) method that is being called when button “Verify” is clicked

Step 4: Uncovering the Secret in verify()

The button on the UI calls the verify(view) method:

if (a.a(obj)) {
    create.setTitle("Success!");
    str = "This is the correct secret.";
} else {
    create.setTitle("Nope...");
    str = "That's not it. Try again.";
}

It checks if obj matches the secret string hidden in the code.

To find the secret string, look into the a.a(obj) method and its dependencies.

Figure 8. Inside a class, where the secret is hidden.

The decryption process involves:

bArr = sg.vantagepoint.a.a.a(
    b("8d127684cbc37c17616d806cf50473cc"), 
    Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0)
);
  1. AES Key (first argument): Hardcoded in hexadecimal (8d127684...)
  2. Base64-encoded Encrypted Data (second argument).

Now, let's take a look closely at the sg.vantagepoint.a.a.a(byte, byte) function.

Figure 9. Inside sg.vantagepoint.a.a.a(byte, byte) function, doing the decryption method using the AES algorithm.

This function:

  • Takes an AES key (bArr or we called it “first argument”) and encrypted data (bArr2 or “second argument”).
    • The first argument: A byte[] representing the key used for decryption.
    • The second argument: A byte[] representing the encrypted data (cipher text) to be decrypted.
  • Configures an AES cipher in ECB mode with PKCS padding.
  • Decrypts the encrypted data and returns the plaintext as a byte[].
🔐
The above code is a basic AES decryption method, but it uses insecure ECB mode and has potential padding mismatches. For better security, consider using CBC or GCM mode and ensure proper key and IV management. Refer to this guide.

Step 5: Putting It All Together

Copy the decryption logic into a test class (e.g., UncrackableApp1Test) to reveal the secret:

Figure 10. UncrackableApp1Test class, putting it all together. (Source code: https://gist.github.com/mzennis/3c6aa9d4a5a9194b8792b932b2f6808d)

Conclusion: The Secret Code

After running the code, you'll reveal the secret:

"I want to believe."

Figure 11. The secret code! 🎊

Figure 12. We did it! 🕶️

Key Takeaways

  1. Obfuscation makes reverse engineering harder but is not foolproof.
  2. Avoid hardcoding secrets (keys, credentials) in your app.
  3. Use secure encryption algorithms (AES-CBC/GCM) and proper key management.
  4. Regularly test your apps against OWASP MASVS and follow best practices for mobile security.

Thanks for reading this far! ✨ This is only the first step toward understanding Mobile App Hacking for Android. I hope this guide sparks curiosity and new ideas!

Share this post