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
|
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.
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.
These are the topics that I'll cover.
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.
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:
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.
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 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.
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)
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.
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
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.
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
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%.
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! :-)
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
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
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.
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. :)