Skip to main content

droids2 picoCTF 2019 Solution

Reverse engineer an Android APK to find the password that unlocks the flag.

Published: April 2, 2026Updated: August 25, 2026

Description

Find the flag in droids2.apk. The app asks for a password. Decompile it, reverse the Java logic to derive the password, enter it in an emulator, and the app hands you the flag.

Download the APK file.

bash
wget <url>/droids2.apk

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Decompile the APK with jadx
    Observation
    The challenge is an APK with a password prompt and no source. The checking logic is compiled into DEX bytecode, which jadx can reconstruct into readable Java.
    Run jadx on the APK to produce Java source. Look inside the decompiled output for a class named FlagstaffHill. Its getFlag method is where the password check lives.
    bash
    jadx droids2.apk -d droids2_java/
    bash
    grep -r 'FlagstaffHill' droids2_java/

    Expected output

    droids2_java/sources/com/hellocmu/picoctf/FlagstaffHill.java
    What didn't work first

    Tried: Using apktool instead of jadx to get readable Java source

    apktool disassembles to smali, a readable Dalvik assembly, not Java. Smali is much harder going: register names like v0 and v1 replace variables, and control flow becomes goto labels. When you want reconstructed Java to trace password logic, jadx is the right tool.

    Tried: Running grep for 'password' or 'flag' directly on the APK binary before decompiling

    The APK is a ZIP holding compiled .dex bytecode, so grepping the raw binary catches some literals but misses anything computed. Here the password is assembled at runtime from array elements and index arithmetic, so it never exists as one literal string. Decompile with jadx first to see the construction.

    Learn more

    jadx re-creates Java source from the compiled .dex bytecode inside the APK. The output is not always identical to the original source, but the logic is preserved accurately enough to reverse engineer passwords and algorithms.

  2. Step 2Read the password-construction logic in FlagstaffHill
    Observation
    jadx puts the validation code in a class called FlagstaffHill, which the grep output confirms. Reading getFlag there shows how the expected password is assembled out of the witches array.
    Open the decompiled FlagstaffHill.java. The getFlag method declares a String array called witches containing six witch names: weatherwax, ogg, garlick, nitt, aching, and dismass. It then computes integer indices through arithmetic (e.g. second = 3 - 3, third = (3 / 3) + second) and concatenates the selected names with dots to form the expected password. Evaluate each arithmetic expression to find the actual index values, then read off the names in order.
    Learn more

    The witches array: {"weatherwax", "ogg", "garlick", "nitt", "aching", "dismass"} (indices 0-5).

    Evaluating the arithmetic gives: second = 0, third = 1, fourth = 2, fifth = 5. The concatenation order selects indices 5, 1, 0, 4, 3, 2, producing the password: dismass.ogg.weatherwax.aching.nitt.garlick.

    The method then calls sesame(input) if your input matches, which returns the flag. The key insight is that all of this logic is plain Java - no native library is involved.

  3. Step 3Enter the password in an Android emulator to get the flag
    Observation
    sesame() only runs and returns the flag when the right password is supplied at runtime. So the password derived from the index arithmetic has to be typed into the running app, not extracted statically.
    Start an Android emulator (e.g. via Android Studio AVD Manager or the standalone emulator). Install droids2.apk, launch it, enter dismass.ogg.weatherwax.aching.nitt.garlick as the password, and submit. The app calls sesame() internally and displays the flag on screen.
    bash
    emulator -avd <your_avd_name> &
    bash
    adb install droids2.apk
    bash
    adb shell am start -n com.hellocmu.picoctf/.MainActivity
    What didn't work first

    Tried: Trying to extract the flag with adb shell without entering the password in the UI

    sesame() returns the flag only when the right password is passed in at runtime; it is not stored as a constant on disk or in SharedPreferences. adb shell cat and adb pull will not find a flag file, because the app has to execute the verification branch to produce it. Drive the UI, or automate input with adb shell input text, to trigger sesame().

    Tried: Installing the APK on a physical Android device instead of an emulator

    A physical device works in principle, but most players do not have a rooted one to hand and the challenge assumes an emulator. More to the point, misread the password by one character (garlick versus garlic, dots versus underscores) and the app just shows nothing. The emulator lets you paste text exactly via adb shell input text, so a typo does not masquerade as a decompilation error.

    Learn more

    Alternatively, you can patch the smali bytecode with apktool (change the call from nope to yep, or copy yep's body into nope), recompile, sign, and install the patched APK to bypass the password check entirely. But simply entering the derived password is simpler when the logic is fully readable from the Java decompilation.

Interactive tools
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
  • File Magic IdentifierIdentify file types from magic numbers. Paste hex bytes or drop a file to detect PNG, JPEG, ZIP, PDF, ELF, PCAP, SQLite, and dozens of other formats.
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.

Flag

Reveal flag

picoCTF{what.is.your.favourite.colour}

The password dismass.ogg.weatherwax.aching.nitt.garlick is derived by evaluating the index arithmetic in FlagstaffHill.getFlag(). Entering it in the app triggers sesame() which returns the flag.

Key takeaway

Android APKs compile to DEX bytecode rather than native machine code, so jadx can reconstruct readable Java from any APK without the original source. A password check written entirely in Java is fully visible once decompiled, which makes hardcoded secrets and obfuscated-but-deterministic logic trivially reversible. The same goes for anything JVM-based: JARs, Android libraries, and obfuscated commercial apps all give way to bytecode decompilation.

Related reading

Useful tools for Reverse Engineering

Where to go next