So, after all those theory-related posts, it is time to actually do something. On this post, i will tamper with a simple application for Android. Let us begin:
The Test Application
As referred on the post about tools there is a website from which you can download APKs, APKMirror. However, i will do the proof-of-concept based on a simpler application. I have dug out my weak Android expertise and put together a simple application (check it on my GitHub) with a weak authentication (hardcoded credentials). The specifications for the emulator are:
- Android 6.0
- Marshmallow, API 23
Preparing the Environment
The development environment i used was Android Studio 2.3 (with SDK tools). All the coding and reversing was done within a VM using VMWare Fusion Professional Version 8.5.6 (5234762). Don’t forget to enable Intel VT-x/EPT support since emulators require this. While this is not a development blogue i will leave some considerations here for future reference and in case someone gets stuck.
Creating an Emulator and Deploying the Application
The easiest way i could find to do this was to create a dummy project on Android Studio (2.3) and then create the emulator. In terms of environment variables i have defined:
ANDROID_SDK_ROOT -> C:\Users\[YOUR_USERNAME]\AppData\Local\Android\sdk
Assuming you are at the window of the project, you should see a button with “AVD Manager”.
- Click the icon
- Create Virtual Device
- You can choose any device. Choices only matter if you need the application to run with a good resolution (AFAIK).
- On the next screen you should be prompted to choose the Android image. You may need to click “download” to obtain the image. In this case i am choosing Marshmallow, API 23 for x86.
- Then you are prompted to choose a name for the emulator. I will use “test” and i am leaving everything as default (i.e. just put a name and click “Finish”)
- Now you should see a list of the devices you have configured. Click on the green arrow to launch the emulator.
If everything goes smooth, you should see the emulator. Also, use adb to check for active devices:
adb devices -l
You may see:
If this is the case, you will not be able to deploy the application. The workaround for this is going to (on the emulator):
- Enable developer options (Settings->About.. and tap 7 times on the screen)
- Go to “Developer Options”-> “Revoke USB debugging authorisations”
- Kill the adb server with “adb kill-server” and then restart it with “adb start-server”
- Then enable and disable debugging. You should see a prompt to authorise USB debugging. Authorise it. When you list devices you should now see:
Now, the application can be deployed with (-g grants all runtime permissions):
adb -s emulator-5554 install -g [PATH_TO_APK]\App.apk
You should see “Success” as the last message. If you now check the emulator should be on the list of applications.
The Base Application
The application is a simple interface that takes a username and a password as input and tests the parameters against internal values:
What’s that? I have mad Android Skills? Well, thank you. In order to make this more realistic, i will sign the application. For this you need JavaDK. We first generate the keystore and the key (password legitlegit):
keytool -genkey -v -keystore hackme_testapp_legit.p12 -alias hackme_testapp_legit -keyalg RSA -keysize 2048 -storetype pkcs12 -validity 365
Once you fill in some details about your “company” you will have a keystore on your desktop containing a certificate valid for a year (365 days). The alias for the key in this case is hackme_testapp_legit. In order to create a release APK, go to (on Android Studio): Build->Generate Signed APK. Fill in the information about the keystore and click Next. On the last screen, mark V1 (Jar Signature) and V2 (Ful APK Signature). Build type should be release. Click Finish. Your APK is built and should be on the application folder with the name [application name]-release.apk.
Once more, in order to make things more realistic, we can generate another keystore and key for the rogue apk. Same command as before but you can call both the keystore and the alias hackme_testapp_evil.p12 and hackme_testapp_evil (password evilevil).
Changing the Application
- I want to change used images and strings (resource manipulation)
- Find the credentials within the decompiled code (Java) and smali code
- Patch the application so we can have a successful login regardless of the password
- Demonstrate how to debug the application
Getting the “original” application
d2j-dex2jar.bat app-release.apk -o app-release.jar
apktool d app-release.apk -o app-release
Strings displayed on Android activities are classified as resources. As such, they can be found inside the res folder. If you use Windows search within the res folder you will find the strings on res\values\strings.xml. Let us change “HackMe” to “Hacked” and “Successful Login” to “Ain’t nobody got time fo failure”. As for the images, they may be on mipmap-something or drawable-something folders, or both. The first are typically for launcher icons while the second are for activity images. Since i suck at Android, i ended up using launcher images for activity images so you will find everything on mipmap folders. No science here, just replace what you want with what you want but keep in mind the names should be the same. Also, for mipmaps, png images are used so, adjust your potential JPEGS. I am disregarding image ratios here with the argument “what is the worst that can happen?”. We have pimped the application. I will rebuild the application once i am done with the next part.
Find the Password and Disrupting Workflow
So now we need to find the credentials. We can either look at the decompiled code (i.e. Java) or smali. Since this is a small application leveraging no anti-reversing tricks, it is a piece of cake. Open JD-GUI and drag-and-drop the Jar we generated previously:
In Android terms, the main application should be a subfolder within com. This happens because, the terminology to fully qualify an Android application package is [reversed company domain].[application name]. In this case, the company domain would be hackme[.]com and the application would be testapp.
As you can see, and if you click through those class files, only three files are of interest:
These files contain classes that inherit from AppCompatActivity and given the fact that we have three screens on the application, this is highly indicative that each of those files represent the Activities for the screens, success screen and failure screen, respectively. Also, according to the decoded Manifest.xml file, there are indeed three activities. Let us look at the HackMeMain.class file:
- Recreating the application:
- Use JD-GUI to export the Java files (File->Save All Sources)
- Create a dummy Android project with Android Studio and then replace all the resources, manifest, packages and code with the ones we managed to obtain.
- Modify the Java code
- Use Android studio do create and sign a new APK
- Modifying the smali code and rebuilding the application
The first approach is more time consuming and should be avoided if the smali is readable. If you look within the folder created by the apktool, you will see a smali folder. This folder contains the smali code associated with the application. We can look at smali using IDA Pro but, you must provide the .dex file. You can obtain this by opening the original APK with with an archive browser (e.g. Winrar, 7-Zip) and pulling off the .dex file. You can also open the APK file with IDA (with Administrator privileges) and choose the .dex file. When looking at IDA, you have to:
- Search for the methods starting with the class name you want: HackMeMain
- Choose the method you want: HackMeMain_onCreate@VL
apktool.bat b [APPLICATION_FOLDER] -o ModifiedApp.apk
And we sign using our malicious key:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore hackme_testapp_evil.p12 ModifiedApp.apk hackme_testapp_evil
adb -s emulator-5554 install -g [PATH_TO_MODIFIED_APK]\ModifiedApp.apk
Debugging in this case, where we can import the decompiled application to Android studio is relatively simple. Also, in this case, the credentials are hardcoded so if you can read Java code, you should be able to understand the verification mechanism without going through a debugging process. In any case, let us assume that the algorithm is much more complex and you would like to step through the verification using a debugger. Before debugging the application you can deploy using either adb or Android studio. Mind that if the application is protected using anti-reversing frameworks like Proguard, you will not be able to deploy the application through Android Studio. For those cases, you need adb. Once it is deployed you can attach the debugger through Android Studion. The Proguard case will make more sense when i dive into such topic. For now, let us keep it simple. With the project on Android Studio:
- Click on the grey bar at a location aligned with the instruction where you want execution to stop:
- Run->Run ‘[application name]’ and select the device. Press OK
- Confirm on the emulator that the application was launched
- On top, click “Attach debugger to Android Process” and select the application. Keep the debugger type as Auto. According to the documentation, if you don’t have native code like C or C++, the debugger will only debug Java code, otherwise, it will switch accordingly (called Dual mode). You should see this:
- Insert the username and the password and click Login. You should see:
From this point on, just jump around using the typical instructions: Step Over, Step Into, Step Out, etc. The Variables window allows you to inspect the fields of the Java objects that are within the context of the analysed code.
The example i have presented here was very simplistic. In the absence of an obuscator/anti-reversing mechanism, you disrupt the workflow of an application by modifying the Smali code or by creating a whole new application with Android studio and modifying to taste. Keep in mind you must sign the application before deploying it. If ProGuard was enabled on Android Studio the reversing process would have been much less smoother. I will dive into that subject on another post later. In any case, this should help you understanding the basics. From here, it is a matter of scaling/increasing effort and time to achieve your purpose.