Skip to main content

timer picoCTF 2023 Solution

Reverse engineer an Android app to locate the flag hidden within the compiled application code.

Published: April 26, 2023Updated: August 25, 2026

Description

The TIMER Android APK hides its flag within the Java source. Reverse the application to recover the hard-coded string before the countdown completes.

Install jadx (the easiest path is your package manager; otherwise grab the latest release).

Decompile timer.apk and search the decompiled sources for picoCTF or timer-related strings.

bash
wget https://artifacts.picoctf.net/c/449/timer.apk
bash
# Pick whichever your platform supports:
bash
sudo apt install jadx              # Debian/Ubuntu
bash
brew install jadx                  # macOS
bash
# Or grab the newest build from the releases page (URL in the context).
bash
jadx-gui timer.apk

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Pick the right tool first: jadx
    Observation
    The download is an .apk, an Android archive of Dalvik bytecode. That decompiles cleanly back to Java with jadx, so start there rather than with something heavier like Ghidra or apktool.
    For nearly every Android CTF the right starting tool is jadx, which decompiles Dalvik bytecode straight to Java. Reach for apktool, dex2jar, or Ghidra only if jadx fails or the app contains native .so libraries.
    Learn more

    APK files are ZIP archives containing compiled Android app code. The code itself is in Dalvik bytecode (inside classes.dex), which is a compact bytecode format for Android's Dalvik/ART virtual machine. Unlike native binaries, Dalvik bytecode decompiles cleanly back to human-readable Java, making Android apps significantly easier to reverse engineer than native C/C++ code.

    Tool ranking when reversing an APK:

    1. jadx first. Highest-fidelity Java decompilation. Try it before anything else. Get it from your distro, brew install jadx, or the jadx releases page.
    2. apktool second. When jadx gives unreadable output, drop down to smali (Dalvik assembly).
    3. dex2jar third. Converts .dex to a regular .jar for the Java tools you already know.
    4. Ghidra last, and only for native .so libraries bundled in lib/.

    For full Ghidra workflow when you do reach a native library, see Ghidra Reverse Engineering.

  2. Step 2Locate the flag in BuildConfig
    Observation
    Grepping the picoCTF prefix across the decompiled sources is the shortest path. Android's build tools bake constants such as VERSION_NAME into the generated BuildConfig class at compile time, so a recursive grep finds hard-coded strings without running anything.
    After decompiling with apktool (or grepping the raw DEX), search for 'picoCTF' in the output. The flag is stored as the VERSION_NAME constant inside BuildConfig.smali, not in any runtime logic in MainActivity.
    bash
    apktool d timer.apk
    bash
    grep -r 'picoCTF' timer/
    bash
    # OR: skip apktool entirely and search the raw bytecode
    bash
    unzip -o timer.apk -d timer_raw
    bash
    strings timer_raw/classes3.dex | grep picoCTF

    Expected output

    picoCTF{t1m3r_r3v3rs3d_succ355fully_17496}
    What didn't work first

    Tried: Unzip the APK and search the raw classes.dex with grep before running any decompiler.

    Grepping the raw .dex gives nothing readable, because Dalvik bytecode is not text and the literals live inside the DEX string pool. Running strings on classes.dex does surface them, but grepping decompiled output is more reliable and shows the class and field around the match.

    Tried: Search for the flag only inside MainActivity.smali, assuming the countdown timer logic is where the flag is returned.

    MainActivity holds the UI and countdown logic and never touches the flag. It sits in BuildConfig as the VERSION_NAME constant, a generated class the build system fills in at compile time. Grep one class file and you miss it; grep the whole decompiled tree.

    Learn more

    Android's build system generates a BuildConfig class at compile time that records build-level constants such as the application ID, build type, and versionName. In this challenge the challenge author placed the flag there as the version name. After apktool decompiles the APK, the class appears as Dalvik assembly at:

    smali_classes3/com/example/timer/BuildConfig.smali

    The relevant section looks like this in smali:

    .field public static final VERSION_NAME:Ljava/lang/String; = "picoCTF{t1m3r_r3v3rs3d_succ355fully_17496}"

    Because the flag is a static string constant compiled directly into the bytecode, no execution is needed. A plain grep or strings search finds it immediately.

    Why apktool here instead of jadx? Both tools work. jadx decompiles to Java and also exposes BuildConfig.VERSION_NAME. apktool produces smali (Dalvik assembly) which is lower-level but keeps every field intact and is easier to grep. For challenges that hide the flag in build metadata rather than runtime logic, either approach reaches the same answer in one search command.

    When static analysis is not enough. If the flag were computed at runtime (encrypted byte arrays, reflection, native libraries), you would need dynamic analysis. That is when you switch to Frida to hook the running app and read values after they are decrypted in memory. This challenge does not require that.

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.
  • 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.
  • 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.

Flag

Reveal flag

picoCTF{t1m3r_r3v3rs3d_succ355fully_17496}

No dynamic analysis required. The flag is stored as the VERSION_NAME constant in BuildConfig.smali and is recovered with a simple grep after decompiling.

Key takeaway

An APK is a ZIP of Dalvik bytecode that decompiles cleanly to Java, which makes static analysis far easier than on a stripped native binary. Secrets left in string constants, build metadata, or resources come back verbatim without ever running the app, and jadx or apktool expose the whole class hierarchy as searchable text. The same holds for Java JARs, .NET assemblies, and .pyc files: bytecode hides less than developers assume.

Related reading

Useful tools for Reverse Engineering

Where to go next