Secarma Labs
Published in

Secarma Labs

Bypassing Android’s RootBeer Library — Part 1

In my previous post, I made a comparison between the different well-known and open-source root-detection bypass tools for Android. In that post, I encouraged analysts to learn how to reverse engineer an application and bypass an application’s protection manually.

This post is a follow up on how to bypass the different checks used by RootBeer library by changing the application’s process through code manipulation.

Before you could modify an application’s code, you need to first have a copy of the APK file. After downloading the application (RootBeer Sample) from the Play Store, the following series of commands can be used to extract the APK file from the Android device:

If you’re like me and do not like typing series of commands, the easiest way to retrieve an APK file from a device is by using Frida Android Helper.

Retrieving an Application’s APK File with Frida Android Helper

Once you have a copy of the APK file, decompile it using apktool:

Decompiling the APK File with apktool

Tip 1: Sometimes, rebuilding a decompiled application results in an error. One way to fix that error is by removing the file 1.apk (shown above) before rebuilding the app.

Tip 2: If an error related to “resources” shows during the building process, try excluding the resources during the decompilation by using the -r flag (shown below).

Excluding Resources During Decompilation

Reading smali code is not as easy as reading java code. So if you’re not comfortable with smali, you can open the APK file in jadx-gui to view its java equivalent and use it as a reference to gain better understanding:

Using jadx-gui to Analyse an Application’s Code

Looking at the RootBeer (com.scottyab.rootbeer.RootBeer) class, there exists a function called isRooted() which, as per its name, is responsible for identifying whether the device is rooted:

Snippet of the RootBeer Class

The equivalent smali code of this class is located in /decompiled/smali/com/scottyab/rootber/RootBeer.smali. From this smali code, the isRooted() function is located on line 1084 (as shown below):

Snippet of the isRooted Function

On line 1158, it can be seen that the isRooted() function returns whatever value the variable v0 holds. To force this function to return the value of false, just change the value of the variable v0from 0x1 to 0x0 (shown in line 1155):

Forcing isRooted() Function to Return “False”

After doing the necessary changes, rebuild the application using apktool:

Rebuilding the Modified Application

Before installing the application, make sure to sign it using your own certificate or a debug certificate. To sign the application easily, you can use uber-apk-signer:

Signing the Application with a Debug Certificate

Using the modified application, it can be seen that we’ve successfully forced the result to “NOT ROOTED” (see the right image below). However, nothing changed with the different checks used by RootBeer; some of the checks still failed:

Result of Modifying the APK File

This happened because we only modified one function of the application and forced it to return as “NOT ROOTED”. To pass all the checks used by the RootBeer library, we need to modify and bypass all the relevant functions.

So how can we find all these functions? If we look at the RootCheckTask (com.scottyab.rootbeer.sample.CheckRootTask) class, there’s a function called doInBackground() which can be used to identify the different functions/checks used by RootBeer. This list of functions can be used as a reference to determine which smali code/files to modify:

A Snippet of the Different Functions Used by RootBeer

The following lists the changes that were made to the relevant classes and functions to bypass all of RootBeer’s checks.

Note: bold text in the code snippets below signifies the changes that were made.

RootBeer (com.scottyab.rootbeer.RootBeer) Class

  • detectRootManagementApps()inserted return v0.
  • detectPotentiallyDangerousApps() inserted return v0.
  • detectTestKeys()changed const/4 v0, 0x1 to const/4 v0, 0x0.
  • checkForBusyBoxBinary()changed move-result v0 to const/4 v0, 0x0.
  • checkForSuBinary() changed move-result v0 to const/4 v0, 0x0.
  • checkSuExists()inserted return v0.
  • checkForRWPaths() —inserted return v1.
  • checkForDangerousProps() — changed const/4 v4, 0x1 to const/4 v4, 0x0.
  • checkForRootNative() — changed const/4 v1, 0x1 to const/4 v1, 0x0.
  • detectRootCloakingApps() — changed const/4 v0, 0x1 to const/4 v0, 0x0.
  • checkForMagiskBinary() — changed move-result v0 to const/4 v0, 0x0.

Utils (com.scottyab.rootbeer.util) Class

  • isSelinuxFlagInEnabled() — inserted return v0.

After doing the above changes, the last thing to do is to rebuild, resign, and re-install the modified application:

Rebuilding, Resigning, and Re-installing the Modified Application

Though the process of modifying the application’s code took quite some time, it’s worth the effort as it resulted in all the checks being bypassed:

Successfully Bypassed All RootBeer’s Checks

Final Thoughts

The way I modified the application’s code (e.g. inserting return v0 after a few lines of the beginning of a function) is not the only way to do it. We all think differently and each of us could come up with different ways on how to solve a problem. So it doesn’t matter how you do your modifications as long as you’re getting the results that you’re aiming for.



The Latest Cyber Security Research From Secarma Consultants

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store