When performing a penetration test on an Android or iOS application the developer can implement what are called binary protections that hinder an attacker from easily analysing an application. Some of the more common protections are SSL pinning, code obfuscation and root detection. This article explains how to bypass the latter, namely root detection on Android.
Rooting or jailbreaking a device impacts the security of applications in two ways:
- It could allow malicious applications or attackers to perform actions as a root user which compromises the security of other applications running on the phone.
- Attackers can perform static and dynamic analysis of an application which helps find more vulnerabilities.
To prevent a user from compromising the security of an application and to make it harder for an attacker to analyse, application developers can implement a check that detects whether the application is running on a rooted device. If the device is rooted the application can either warn the user and continue running the application or decide to prevent the user from running the application all together:
When performing a penetration test on a mobile application that prevents execution when it detects a rooted device, bypassing this protection is necessary before we can proceed with dynamic analysis. Fortunately there are several ways to defeat root detection, some more complicated than others and some methods that don’t always work. So choosing the correct method is the first step in a successful root detection bypass. However before deciding on the appropriate bypass we have to understand the techniques used to detect a rooted device. The following are the most common techniques and are discussed further in this article.
- Check the BUILD tag for the “test-keys” string.
- Check for the existence of the “Superuser.apk” application.
- Search for other applications that are usually installed on a rooted device
The article above discusses several methods for bypassing root detection that involve modifying the Android device or emulator to trick the application into thinking its not running in a rooted environment. Another technique is simply installing an application that tries to automate these tasks such as Hide my Root or the RootCloak module which uses the Xposed framework.
Unfortunately these techniques don’t always work because some applications use different methods to check for a rooted device. If these techniques fail then we are left with two options:
- Write a custom Xposed Framework or Cydia Substrate module.
- Patch the application by modifying the smali byte code.
The rest of this article will focus on the latter and leave the Exposed and Cydia Substrate frameworks for a different article.
The application used as an example below is from a recent client mobile application penetration test so some of the code and images have been sanitized, but still reflects patching a real world application.
Keep in mind that our goal is to patch the application so that when it runs it skips the check for root detection and allows the app to run on a rooted device so that we can continue to with dynamic analysis. The steps necessary for patching an application can be summarized as follows:
- Install the application and extract the APK file from the device/emulator.
- Decompile the application so that we can look through the smali files for where the root detection check/s are performed.
- Modify the smali so that these checks are skipped.
- Recompile the application with the modifications and see if we are successful!
The first step to patching an Android application is to get your hands on the Android Application Package (APK). This contains all the code, resources and settings necessary to install the application. During the installation process Android stores the APK file in the
/data/app directory. We can extract it by using ADB to first browse to this directory to find out the application file name and then use the following command to extract it:
adb pull /data/app/[NAME_OF_APP.apk] ./
Once we have the APK we can then reverse engineer the app to discover how the developers have implemented root detection. We can achieve this by using apktool:
java -jar ~/programs/apktool_2.0.0rc3.jar d -rf [APPNAME].apk
r parameter is important as it tells the apktool to only decode the
classes.dex file into smali and leave the other resources alone. I mention this as when patching the smali we want to change as little as possible and from experience this makes the building process much more reliable and less prone to errors. On the other hand if you are in the information gathering stage you should not use the
r parameter so that you can investigate other files such as the manifest file.
After running the apktool in decode mode you should be left with a folder that contains the smali files for the application. In this case the code has also been put through an obfuscation process, most likely with a tool called Proguard. This will make life a little harder but nothing to worry about :)
The next step is to find out where the rooted device check/s are being done so that we can modify the smali to skip them. If reading smali code is not for you then using dex2jar and jd-gui will convert it all to Java which can be easier to read. However once you have found where you want to modify you will still have to modify the smali and not the Java code. This is because the Java code generated by dex2jar is only an approximation of the original Java source code and would fail during the rebuild process.
Finding where the check\s are done may take some time. To speed things up you can search for words such as
rooted or words that appear on the error message when you start the application. In my case searching for the word
rooted revealed this code:
If we look closer at this code we can see that there is a function call on line 753 and then an if statement on line 757. If the value of
v0 is equal to zero then the device is not rooted and we continue running the application. Otherwise we halt the application.
If that was too much to take in then here is the dex2jar generated version of this code:
So to patch the root detection check so that it always returns zero, we have to change line 757 to
if-nez v0, :cond_0. This is reversing the check so that it skips the rooted device code if
v0 is not equal to zero. There are obviously many ways to modify the smali to achieve the same goals but i leave it up to you to play around with the alternative solutions. This link to the Dalvik opcodes may become useful too :)
The last step is to build the modified app back into an APK. We can do this with the following command:
java -jar ~/programs/apktool_2.0.0rc3.jar b [APPFOLDERNAME] -o [APPNAME]_mod.apk
b is for build and will produce an unsigned APK assuming you have not made any errors when modifying the smali.
Before you can install the modified app onto your rooted device/emulator using the adb command:
adb install [APPNAME]_mod.apk