Description
Can you handle APKs? Download the android apk here.
Setup
Download mobpsycho.apk and unzip it in a separate directory (APK unzip dumps lots of files).
wget https://artifacts.picoctf.net/c_titan/53/mobpsycho.apk && \
mkdir mobpsycho_dir && cd mobpsycho_dir && \
unzip ../mobpsycho.apkSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
xxd -r -p reverse-hex pattern at the heart of this solve, plus the recognition cues for hex-encoded strings hidden inside other formats.Step 1Find the flag file
ObservationThe download is an APK, and Android apps keep raw resources, text and config and assets, under res/ inside the ZIP. Scan that directory with find and strings.Search the extracted tree by filename first, then by content. The flag lives at res/color/flag.txt. Note that grepping for the literal string 'flag' inside the files finds nothing here: the flag is stored hex-encoded, so the giveaway is the byte pattern 7069636f, which is 'pico' in hex.bashfind . -type f -name 'flag*'bashgrep -rl 7069636f resWhat didn't work first
Tried: Run strings on the APK file directly before unzipping it
Running strings on the .apk floods you with ZIP metadata and DEX fragments, and the flag is buried or missing entirely, because compression means those bytes are not ASCII on disk. Unzip first so strings sees the uncompressed resource files.
Tried: Grep the extracted tree for the string 'flag' or 'picoCTF' and conclude the flag is not in the APK
The flag is stored as hex text, so neither 'picoCTF' nor 'flag' appears anywhere in the file contents. Search by filename, or grep for the hex of the prefix (7069636f), and res/color/flag.txt shows up immediately.
Learn more
An APK (Android Package Kit) is simply a ZIP archive containing everything an Android app needs: compiled Dalvik bytecode (
classes.dex), resources, assets, a manifest, and native libraries. Because it is a standard ZIP, any tool that can unzip an archive can explore its contents without needing a real Android device.find . -type f -name 'flag*'is the cheapest first pass: it walks the whole extracted tree by filename and costs nothing. When a name search comes up empty,find ... -exec strings {} + | grep ...appliesstringsto every regular file and pipes the union intogrep, which is the safer alternative to a top-levelstrings *: that glob skips dotfiles, expands at most one level, and chokes on directories. Scoping either search tores/avoids draggingclasses.dexinto the output.- The
res/directory holds Android XML resources, drawables, and raw files, a common hiding spot for CTF secrets. - The
assets/directory is another frequent location for embedded files that are not compiled into the DEX. - For deeper analysis, tools like jadx or apktool decompile DEX bytecode back to readable Java/Smali.
- The
Step 2Decode the hex
Observationflag.txt is an unbroken run of hex character pairs with no offsets or spaces, which is a plain hex dump. xxd -r -p converts it back to ASCII.flag.txt contains hex; pipe it through xxd -r -p (or CyberChef's From Hex) to recover the ASCII flag.bashxxd -r -p res/color/flag.txtExpected output
picoCTF{ax8mC0RU6ve_NX85l4ax8mCl_a3e...}What didn't work first
Tried: Run xxd -r res/color/flag.txt without the -p flag
Without -p, xxd -r expects its own address-offset layout. flag.txt is a continuous hex string with no offsets, so you get garbled or empty output. -p tells xxd the input is plain hex with no columns.
Tried: Open flag.txt in a text editor and read it as the flag
flag.txt reads as a long string of hex digits, which is not a valid flag. Each pair encodes one character, so the flag is what those pairs decode to. The raw string gets rejected.
Learn more
Hiding data as hexadecimal is a simple obfuscation technique: each byte of the original string is represented as two hex digits (e.g., the letter 'p' becomes
70). The value is human-unreadable at a glance but trivially reversible.xxd -r -preverses a plain hex dump back to binary. The-rflag means "reverse" (hex to binary) and-pmeans the input is in plain/continuous hex format without address offsets. This combination is the standard Linux one-liner for hex decoding.CyberChef's From Hex recipe performs the same operation visually, making it useful when you want to see intermediate steps or chain multiple decodings (e.g., hex then base64 then ROT13). Real malware samples often layer encodings precisely to slow down analysts.
The decoded output is pure ASCII printable text from
pthrough}: that's the entire flag, copy it as-is. If you see\0or other null bytes inside the output, that's a sign the input hex had odd-length bytes, stray spaces, or trailing whitespace thatxxd -r -pmishandled, not part of the flag itself.
Interactive tools
- 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.
- 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.
Flag
Reveal flag
picoCTF{ax8mC0RU6ve_NX85l4ax8mCl_a3e...}
The decoded hex string inside res/color/flag.txt is the flag.