// HackTricks · Mobile

Google CTF 2018 - Shall We Play a Game?

Google CTF 2018 - Shall We Play a Game?

The original Google CTF repository preserves the 2018 challenges, and community write-ups preserve this APK and its reversing workflow.[1][2]

Upload the APK to an isolated emulator service such as Appetize.io, or install it on a disposable local emulator/device, to observe its behavior:[3]

Appetize.io emulator running the Shall We Play a Game APK

The game requires 1,000,000 wins to reveal the flag.

Following the Android pentesting workflow, decode the APK with Apktool and inspect decompiled Java with JADX.[2]

Reading the java code:

Google CTF 2018 - Shall We Play a Game?: Reading the java code

The function that prints the flag is m().

Smali changes

Call m() the first time

To make the application call m() when this.o != 1000000, invert the branch condition:

 if-ne v0, v9, :cond_2

to:

 if-eq v0, v9, :cond_2

Before

After

Follow the Android pentesting workflow to rebuild and sign the APK, then run it again:

Appetize.io emulator showing the modified APK after changing the Smali condition

The displayed flag is not fully decrypted because the per-win transformation must run 1,000,000 times; merely bypassing the comparison does not reproduce those iterations.[2]

Another approach is to leave the branch instruction intact and change its operands:

Alternative Smali change: keep the branch instruction and change the compared registers

Another way is instead of comparing with 1000000, set the value to 1 so this.o is compared with 1:

Smali changes - Call m() the first time: Another way is instead of comparing with 1000000, set the value to 1 so this.o is compared with 1

A fourth approach is to move the value of v9 (1,000,000) into v0 (this.o):

Smali changes - Call m() the first time: A forth way is to add an instruction to move to value of v9(1000000) to v0 (this.o)

Smali changes - Call m() the first time: A forth way is to add an instruction to move to value of v9(1000000) to v0 (this.o)

Solution

Make the application run the win/decryption loop 1,000,000 times after the first win. Create the :goto_6 loop and jump back while this.o has not reached 1,000,000:[2]

Call m() the first time - Solution: Make the application run the loop 100000 times when you win the first time. To do so, you only need to create the :goto 6 loop and make the...

The original experiment succeeded on a physical device but not its emulator. That is an observation about that setup rather than an inherent requirement; emulator CPU speed, watchdogs, or service limits can make the million-iteration loop appear to hang.

References