Reverse Engineering an Android Application

Waleed Alhajri
13/02/2021


Introduction
This blog will explain how to perform reverse engineering on an android application and how to restore the source code for the application. This method will eventually help us to conduct better penetration testing on the mobile application.
What is Reverse Engineering?
It is a way to take the application apart to restore its first form, which will help us understand its components and how the application is working.
There are two methods to take an Android application apart:

Decompile
This method will restore the application to a replica of the source code, and we will be able to understand its components and how it works, but it will be hard to re-compile it again.

Disassemble
Using this method, we will take the application apart to some extent with the ability to edit its behavior and re-build it again, but all this will be in Smali instruction (hard to read).
How to Build an Android Application
Below I will explain how to transfer the source code of an Android application to a working APK installed inside an Android phone. There is more to this process, but I will focus on the parts that the developer wrote for simplicity.
⦁ The source code is written in Java will be compiled to become Java Bytecode, and its extensions will be changed from .java to .class

⦁ Then the Java Bytecode will become Dalvik Bytecode using the Dex compiler. Keep in mind that a single .dex file can only hold 65536 methods, including the Android framework, third-party library, and functions that the developer has written.

⦁ In the end, all of the above will be compress with the resources files and other files to make an APK.
The below picture describes the above steps:
Android Application Contents
Android application is a compressed file that can be unzipped to reveal its files by typing the following command
unzip <android applicaion>
Android Files
Below are the files you should expect when you decompress an APK file
AndroidManifest.xml: here are everything about the application like
⦁ Package name
⦁ Target and minimum API level
⦁ App configuration
⦁ App components
⦁ Permissions

META-INF: contain metadata about the application
⦁ classes.dex: this file contains the compiled source code
⦁ assets: a folder containing the following
⦁ Pictures
⦁ Fonts
⦁ Videos files

Lib: include the native library that the application uses

Res: this is the resources folder, and you can find in it stuff like
⦁ Shapes
⦁ Colors
⦁ Pictures

UnCrackable Challenge
Trying to solve this challenge from OWASP_MSTG, we will try one of the methods of reverse engineering. Let start by downloading the APK from their page.
After downloading the application, we need to install it on an Android phone preferred to be rooted.
adb install UnCrackable-Level1.apk
adb: a tool that enables us to control an Android phone through the command-line
Now we need to run the application.
At first, we can see that the application is implementing root detection, and we only have the option of clicking the "OK" button, which will close the application. Let see how is this feature is implemented using Jadx to decompile the application
jadx-gui UnCrackable-Level1.apk
Jadx: a tool that decompiles the application, restoring it to its first form (Source Code)
At first, we need to identify the starting point of the application by going to the AndroidManifest.xml file, and then we need to find the Activity which has the following line android.intent.action.MAIN Inside it as this is the starting point
From the value of the android:name, we can find the right activity
In the life cycle of the activity, the first method that should be started is the onCreate method, and inside this method, there is an if statement that checks three things. If any of it is true we will see the alert dialog that will force us to exit the application.
If we trace these three methods by doing the following
In an abstract way we can say that these three functions check for tools and methods used in getting root access on an Android phone if any of these returns true value, we will get the alert dialog
Now back to the MainActivity if any of these methods return true a method called (a) will be executed and looking to the red box we can see that the application will not close unless the "OK" button was clicked and also we can't cancel the dialog cause the value of the method on line 25 is set to false, but if somehow we were able to change this value we can bypass this restriction
To change any value at runtime first we need make the application debuggable. To make an application debuggable first we need to disassemble the application
apktool d UnCrackable-Level1.apk -o base
apktool: a tool that helps us in the process of disassembling an application and also rebuild it.
d: disassemble
o: write the output inside a folder
Now inside the AndroidManifest.xml we have to add the following
android:debuggable=true

Now we have to rebuild the application like this
apktool b base/ -o base.apk
b: reassemble
o: name the output APK
Now before installing the application on an Android phone, we need to create a signing key since Android will only install an application that its developer has signed
keytool -genkey -v -keystore WH_keys.keystore -alias WH -keyalg RSA -keysize 2048 -validity 10000
keytool: a tool to generate a keys that could be used for signing
genkey: generate a key
v: verbose
keystore: key name
alias: alias name
keyalg: algorithm to use
keysize: key size
validity: validity time
We then need to enter the key information
Now we will use the key to sign the application
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore WH_keys.keystore base.apk Wh
jarsigner: use the previously generated key to sign the application
verbose: for more verbosity
sigalg: wanted algorithm
digestalg: wanted hashing method
keystore: name and location of the keystore generated previously
base.apk: name of the application to sign
Wh: key nickname
Lastly, we need to align the application by using the following tool
zipalign -v 4 base.apk debuggable-crackme.apk
v: verbose
4: switch to do 32-bit alignment
Now we need to install the modified application
After the application start, we will see that the application has detected our changes by displaying the following alert dialog
Also, while the application is running, we can check if the application is debuggable by doing the following
adb jdwp
Jdwp: will list all debuggable processes
now we can check application running on this process
frida-ps -Uai | grep  ID
Frida: tool used for dynamic analysis, I explained how to installed it and use it in this article
Now we need to run the application on debug mode
adb shell am start -D "owasp.mstg.uncrackable1/sg.vantagepoint.uncrackable1.MainActivity"
Looking on the phone we can see that the phone is waiting for the debugger to attach to it
First thing we need the application process number
adb jdwp
after this we need to pull the process to a local port on our machine, I chose this port 1234
adb forward tcp:1234 jdwp:11561
forward: forward our traffic from the local port to the internal process
tcp: local port on your local machine (you need to make sure that the port is not used)
jdwp: the application process number
now we need to just connect the debugger using JDB to the application, but we need to give it suspend which is one of the JDB option to stop the application at the moment of connection
(echo suspend && cat) | jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=1234
The goal from all this is to change the value of setCancelable from false to true so we can ignore the dialog. But first, we need to know the classpath so we can set a breakpoint on it, we can see by tracing the method using Jadx like the below picture that the method setCancelable is called from the following class android.app.AlertDialog
But if we try to put a breakpoint on it, it will say that the method is not found
And if we look at the Android documentation, we will see that the class AlertDialog is inheriting it method from a class called Dialog
And it contains the method setCancelable
So instead of writing this
stop in android.app.AlertDialog.setCancelable
we can write the following
stop in android.app.Dialog.setCancelable
Now the debugger has identified the method, now we can write resume until we hit the breakpoint
Now we need to type locals and replace the the value of the flag from false to true then we type resume
We continue this cycle until the alert dialog appears on the phone
Now we only have to press the dimmed place on the screen and the alert dialog will disappear
This way we were able to bypass the security control placed on the application, the next step we need to know the secret text stored inside the application. But first, we need to remove previous breakpoints so we don't stop on them
Now if we went back to the source code, we can see that the entered text is being given to a function called a.a and if it returns true it will print a success message. Let see how this function is validating the input
Inside the class "a" there is a method "a" which we at the end compare two values of the stored text with what we entered in the input field and the comparison is happing on the last line of this method
To intercept this comparison, we need first to put a breakpoint on the a.a method and then entered any text and press VERFIY button
After we get stopped by the place breakpoint then we need to put another breakpoint on the equals method, but how to know which classpath to type from the code below we can see that the equals is part of str which is an object of the class String
if we searched the String class in Android documentation we are going to see that the classpath for this function is java.lang.String.equals
Now since we know the classpath we can put a breakpoint like this
stop in java.lang.String.equals
Now we only need to type resume then locals until we find the secret text
Now let check if this text is the secret text by entering it into the input field, but first we need to remove all the breakpoints
This way we were able to get the code
Conclusion
In reverse engineering, there is no single method that will work every time also there is no right or wrong way. There is a lot of methods and tools and I think the best way to get hang of this field is to stick to one method or tool until you master it and then move to the next one until you get it. Also, OWASP_MSTG is a very good starting point.

Share this blog
Follow us
Advance your skills by reading the latest blog created by our team.
Other Blogs