Guide: How to crack Android apps

Learn how to reverse engineer Android apps, alter them, and put them back together. No root needed.

Published: Fri, February 9, 2018, 22:40
Updated: Tue, December 8, 2020, 20:30
Category:
Software development
Tags:
Reverse engineering
Cracking
Android
Guide

tl;dr ๐Ÿ”—

This tutorial for how to crack Android apps is one of my more technical posts. If you aren't a developer you might want to skip this one. :) I'm assuming some basic knowledge of UN*X, Java and Android.

Why crack an app? ๐Ÿ”—

Sometimes I like to check if online services I use really are secure. I've presented quite a few cases to prove that they very often are not. Mostly I can use very simple techniques to check the security as there are so many basic security vulnerabilities out there. When it comes to apps I often use a HTTP proxy like Charles to take a look at the HTTP and HTTPS traffic. However, once in a while there are apps that use e.g. HTTP tunneling or certificate pinning. In those cases you need to go one step further to be able to listen to the network traffic.

Other reasons to decompile apps could be to recover lost source code, to inject language translations or even fix a bug. But hey, remember, don't do anything you are not allowed to. Don't break the law. This guide is just for educational purposes when you have legitimate reasons to do what you do.

Contents ๐Ÿ”—

These are the topics that I'll cover.

Online alternatives ๐Ÿ”—

Very often you don't have to get your hands too dirty getting the hands of a decompiled app. There are some good services out there that can provide you with most Android APKs, and then even some to decompile them.

Online APK archives ๐Ÿ”—

To get hold of an APK you can typically just google the package name. There are quite a few sites where to download them from. Some are more frequently updated than others. Note that you can get hold of different versions and the APK for different architectual platforms.

A word of wisdom: Don't download and run some random APK out there (at least do it in a sandboxed and/or emulated environment). There are quite a few sites that serves bogus or altered APKs. The app might look allright, but still have some malware injected. Don't blindly trust the ones that I recommend either. If the APK is signed with the same key as an APK that you got from Play Store you should be able to trust its origin (though there have been cases of private keys in the wild (even repackaged APKs uploaded to the vendor's own web site)).

Here's a few you might want to try out:

Online decompiler ๐Ÿ”—

The quickest and easiest way to decompile an APK is to just use an online service. You just upload the APK and get an archive with all the resources and decompiled files. javadecompilers.com is the one I have used, and I have been pretty happy with it.

As you might know, the APK file is really just a ZIP file, so you can typically just rename it to .zip and double click it or run unzip and you can start investigating the app. If it's a hybrid app you might not have to decompile it at all to get access to everything. Actually, the Gator Watch app was a hybrid app and gave away everything with little effort.

Getting the tools ๐Ÿ”—

Android - SDK, tools and emulators ๐Ÿ”—

You need to have at least the Android tools and SDK, but for most people I would recommend to just install Android Studio and follow the instructions to set it up as normal (but skip stuff like the SDK for Android TV and other stuff that will slow down your download).

Apktool - disassembling and reassembling APKs ๐Ÿ”—

Apktool can be installed manually, or if it's available via your package manager you can just install it using a command like apt-get install apktool.

Getting the APK ๐Ÿ”—

The first step of the reverse engineering is to get hold of the APK. I'll use my own Android app Developer Tools as an example app. It's open source and if you want you can get the source code and APKs from GitHub.

The command-line tool adb (Android Debug Bridge) is used for all communication with the device or emulator. You can find the tool in the Android's installation folder platform-tools.

 $ย # Lists all packages:
 $ adb shell pm list packages
 <loong list of apps />

 $ย # Simple way of searching for packages:
 $ย adb shell pm list packages |grep roysolberg
 package:com.roysolberg.android.smarthome
 package:com.roysolberg.android.datacounter
 package:com.roysolberg.android.developertools

 $ย # Get the path of a package:
 $ย adb shell pm path com.roysolberg.android.developertools
 package:/data/app/com.roysolberg.android.developertools-1/base.apk

 $ย # Get hold of the APK actual APK file:
 $ย adb pull /data/app/com.roysolberg.android.developertools-1/base.apk
 /data/app/com.roysolberg.android.developertools-...file pulled. 25.2 MB/s (2035934 bytes in 0.077s)
Note on App Bundles / multi-APK ๐Ÿ”—

It's increasingly common (and required for Play Store releases in the second half of 2021) that apps use Android App Bundles. This adds a layer of complexity when cracking apps.

When the app is an App Bundle you will in the above example see more than one APK file. Typically you will see base.apk (the common code), split_config.arm64_v8a.apk (config for the CPU architecture), split_config.xxxhdpi.apk (config for the screen resolution) and typically a split for the language and maybe some dynamic features.

You need copy all the APK files - either in separate adb pull commands or pull the whole app directory.

Decoding the APK ๐Ÿ”—

The next step is to unzip and decompile the APK. Apktool does this for us.

 $ย # Decode the pulled APK into a directory named base:
 $ apktool decode base.apk
 
 $ย # d works as an alias for decode:
 $ apktool d base.apk

Note on App Bundles / multi-APK ๐Ÿ”—

If you are interested in the core code and not the resource files you only have to consider the base.apk files and not the rest. But note that you need to either decompile and compile them (or at least unzip them and remove the META-INF folder before zipping again) if you need to resign the app as shown in a later step.

Altering the app ๐Ÿ”—

This is where the hard work starts. The code files are now fully readable, but the code is now in the smali format. You can think of smali as a sort of assembly language.

As an example we'll first change the language string app_name to Hacker Tools.

 $ย # Edit the main language file:
 $ย vi base/res/values/strings.xml

Then we'll change some hard coded text so that we have changed both resources and actual code.

 $ย # Search for file we want to change:
 $ย grep -nr 'originally' base/smali
 base/smali/com/roysolberg/android/developertools/ui/activity/MainActivity.smali:651:    const-string v4, "This app was originally just created for myself to make some development tasks a bit easier. I've released it to Play Store hoping that someone else might find it useful.\n\nIf you want to get in touch me, please send me a mail at dev-null@example.com.\n\nPlease note that I take no credit for the third party apps."

 $ # Edit the smali file and change the string value:
 $ vi base/smali/com/roysolberg/android/developertools/ui/activity/MainActivity.smali


Reading Java instead of smali ๐Ÿ”—

There's a way out if you rather want to read Java instead of smali. The excellent tool jadx provides both a command-line and GUI tool for converting dex to Java.

You can open the APK files directly in the the program and have all the code decompiled and converted. Reading Java is after all easier than reading the smali format. Just note that you cannot simply change the Java code and recompile it with jadx. You can always try to get a project up and running in Android Studio, but it will typically take some major effort as jadx seldom can fully decompile everything 100%.

Getting the app back together ๐Ÿ”—

There are quite a few steps getting everything together. We need to rebuild the app, sign it, zipalign it, and then install it. If the properly signed app is still installed it needs to first be uninstalled as our signature violates the existing one.

The command-line tool zipalign is needed to align the contents of the APK for Android to be able to run it. You can find the tool in the Android's installation folder build-tools/<some version number>.

ย $ # First build a new APK with the changes:
 $ย apktool build base -o base.unaligned.apk

 $ # Sign the app using the Android debug certificate generated from Android Studio installation:
 $ jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore ~/.android/debug.keystore -storepass android base.unaligned.apk androiddebugkey
 
 $ย # Align APK:
 $ย zipalign -v 4 base.unaligned.apk base.aligned.apk

 $ # If original app (with different signature) is installed it must be uninstalled.
 $ # Please note that you will lose any app data you have.
 $ adb uninstall com.roysolberg.android.developertools
 Success

 $ # Final step is to install the newly altered app (-r for reinstall (keeping the app's data)):
 $ adb install -r base.aligned.apk
 Success

 $ # To keep an eye on the log and what's going on you can use logcat:
 $ adb logcat

That's it! :-)

Note on App Bundles / multi-APK ๐Ÿ”—

If you have multiple APK files and you just signed the altered APK file with a new certificate you will need to sign every single APK file with jarsigner and then zipalign them.

Installing them will need the install-multiple option and all APK files as arguments:

adb install-multiple -r base.aligned.apk split_config.xxxhdpi.aligned.apk apk3.aligned.apk apk4.aligned.apk

A few addtional tips ๐Ÿ”—

Reading smali ๐Ÿ”—

It might take a little bit of getting used to, but reading smali isn't all too bad. If you have any concrete problems you'll find the answer with some googling. But a good tip is to create some small very simple Java classes yourself and check out what they look like in the smali format.

If you are having trouble navigating the smali code and understand the flow of an app you can use the following smali code. It will call Thread.dumpStack() which logs the current thread's call stack.

invoke-static {}, Ljava/lang/Thread;->dumpStack()V

If you need to know the value of a string - e.g. a parameter - you can use Log.d(String tag, String message) to log it to the system log.

 const-string/jumbo v0, "YourTag"
 invoke-static {v0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
Proguard ๐Ÿ”—

Very often - but not in the case of my Developer Tools app - the code will be shrinked and obfuscated using ProGuard. This makes the code a lot harder do read and understand. There aren't really any good ways around it, but doing the thread dump trick and taking your time to follow the code will eventually get you where you want to be.

I'm writing an e-book about cracking android apps. Sign up now and be notified when it's done and get 30% discount!

Wrapping it up ๐Ÿ”—

The regular Developer Tools app on the left and the cracked one on the right.If you have followed along the guide you would see the app change from the version on the left to something like the one on the right. One of the reasons I wrote this guide was for my own sake to have something to easily copy and paste from when doing some reverse engineering myself, but I thought this might be useful one for others as well. :)

Get notified when there are new posts! :-)