Manual APK Repackaging for exposing Secret on droids3 Android App
In this writeup, I will walk you through the steps I took to solve the droids3 challenge from PicoCTF 2019, which involves Android reverse engineering. This challenge quite different from the previous challenge because this one I had to modify the code the rebuild it again with modification.
Tools that I used:
Just like the previous challenge, we still have the same UI but this time the hint is “make this app your own” when the button pressed it says “don’t wanna”
so this time let’s go straight to send it to JADX and check the code.
Because the MainActivity is still same I just went to the FlagstaffHill Class and this time when the getFlag called it will call the nope method and always return “don’t wanna” while the real Flag might be on yep method so in the current state we need to somehow change the code on the getFlag() instead of calling nope(input) change it into yep(input) so the real flag will shown.
A rough idea of the steps I will take is something like this:
- Decompile the APK
- Go to FlagsaffHill smali code
- Change the nope(input) into yep(input) in getFlag()
- Rebuild the APK
- (Optional) Sign the modified APK
- run the modified APK and get the flag
Since the current JADX can only read the code not modify it, I have to use another tool called Apktool and manually do the step from above to make it work.
1. Decompile the APK
To Decompile the APK I’m using Apktool and just need to run this command on terminal
apktool d -r three.apk
which translate:
- “apktool” : is the name of the tools and base command
- “d” : for decode
- “-r” : mean no resource, so apktool will decode the APK without the resources
- “three.apk” : is the name of the APK that wants to decompile
after that it generates a new folder called three with a structured folder like this.
2. Go to FlagsaffHill smali code
then I import the folder into VSCode to make it easier and go into the FlagstaffHill.smali file which is located at smali/com/hellocmu/picoctf/FlagstaffHill.smali
Here it comes, the Smali Code which is quite hard to understand (for me :D) but still human-readable.
By the code from above, this is how I translate it:
- .method is an opening tag for a method/function
- .locals is for declaring a variable
- .param is for declaring parameters that needed for .method
- .invoke-static is for calling a static method
3. Change the nope(input) into yep(input) in getFlag()
Because the method that needs changes is only on getFlag() method, I only focus on this part
So to change the getFlag() from calling nope(input) to yep(input) I make small changes on this part inside getFlag() on line 25
4. Rebuild the APK
after finished modify the smali code, I need to rebuild the APK to make a new modified APK with previous changes, to do that I run this Apktool command
apktool b three -o three_modified.apk
which translate:
- “apktool” : is the name of the tools and base command
- “b” : means build (recompile)
- “three” : is for the directory that are generated from previous decompile and contains the modified smali code
- “-o” : means output
- “three_modified.apk” : is the name of the modified APK that will generated
After the modified APK is generated, I tried to send the APK into the emulator and run it not working with an error
‘INSTALL_PARSE_FAILED_NO_CERTIFICATES’
according to developer.android on Sign your app page:
Android requires that all APKs be digitally signed with a certificate before they are installed on a device or updated.
5. Sign the modified APK
turns out I need to sign the APK first before installing because the Android rejected it, and before sign I need to create a keystore first because signing require keystore.
to make a keystore there is 2 way that I know, first is using Android Studio and the other one is using keytool on terminal, and this time I’m gonna use the later which is keytool because I think it’s faster compared to the time needed to open Android Studio😂.
to make the keystore using keytool I run this command on terminal
keytool -genkey -v -keystore pico.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias pico
which translate:
- “keytool” : is the name of the tools and base command
- “-genkey” : to generate both public key and private key
- “-v” : is verbose output
- “-keystore pico.keystore” : to specify the keystore will be pico.keystore
- “-keyalg RSA” : to specify that the key will generated using RSA Algorithm
- “-keysize 2048” : to specify the size of the generated key in bits. 2048 because we use RSA Algorithm and use -genkey (Also I think 2048 is the default value)
- “-validity 10000” : means the generated key will valid for 10,000 Days
- “-alias pico” : to specify that the generated key alias is pico
after run the command it will prompt to create a keystore password the password must at least 6 characters.
after that several inputs needed to create the keystore, this time I just fill some input and leave some empty on the confirmation prompt the answer is “yes”
after that I will ask for a password the “pico” which is alias of keys that I create. This time I just press enter since I want the password to be same
after pressing “Enter” it will generate the keystore called pico.keystore on the directory that I ran the command with.
After that I just need to use the apksigner to sign the APK.
while checking on developer.android on apksigner page I found this:
Caution: If you sign your APK using apksigner and make further changes to the APK, the APK’s signature is invalidated. If you use zipalign to align your APK, use it before signing the APK.
and on developer.android on zipalign page:
Caution: You must use zipalign at a specific point in the build process. That point depends on which app-signing tool you use:
If you use apksigner, zipalign must be used before the APK file has been signed. If you sign your APK using apksigner and make further changes to the APK, its signature is invalidated.
If you use jarsigner (not recommended), zipalign must be used after the APK file has been signed.
so just to be certain I follow their recommendation to use zipalign first then apksigner.
for the zipalign I run this command on terminal:
zipalign -p 4 three_modified.apk three_aligned.apk
which translate:
- “zipalign” : is the name of the tools and base command
- “-p ” : for page alignment mode
- “4” : default value, align to 4 bytes for 32 and 64 bit system
- “three_modified.apk” : specify the origin apk
- “three_aligned.apk” : specify the output apk
after run the command it will generate a new APK called three_aligned.apk. this APK is the one that I will use to sign using apksigner using the previous generated keystore and to do that I run this command:
apksigner sign --ks-key-alias pico --ks pico.keystore three_aligned.apk
which translate:
- “apksigner” : is the name of the tools and base command
- “sign ” : to sign
- “ — ks-key-alias pico” : to specify the alias of the key in this case pico
- “ — ks pico.keystore” : specify the keystore that will be used, in this case pico.keystore
- “three_aligned.apk” : specify which APK that want to be signed
then it will prompt to input the password from that keystore
after this I just need to verify to make sure that the signing is a success by running this command
apksigner verify three_aligned.apk
which translate:
- “apksigner” : is the name of the tools and base command
- “verify” : to verify the sign
- “three_aligned.apk” : specify which APK that want to verify
Since it shows no output, I guess the signing Process is success.
6. Run the modified APK and get the flag
Finally, after going through the signing process for the modified APK, I tried to send the new signed APK (three_aligned.apk) to the emulator
It’s works, the APK is installed successfully, now the moment of truth, I put random text on edittext and press the button to show the flag.
And here comes the flag:
picoCTF{tis.but.a.scratch}
Reference:
OWASP Mobile - M7: Insufficient Binary Protection
HackTricks - Smali Decompilling