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.
Setup
Download the APK file.
wget <url>/droids2.apkSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Decompile the APK with jadx
ObservationThe 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.bashjadx droids2.apk -d droids2_java/bashgrep -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.
Step 2Read the password-construction logic in FlagstaffHill
Observationjadx 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.Step 3Enter the password in an Android emulator to get the flag
Observationsesame() 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.bashemulator -avd <your_avd_name> &bashadb install droids2.apkbashadb shell am start -n com.hellocmu.picoctf/.MainActivityWhat 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.