How to prevent Rooted Android Phones from Installing my app?

23.9k views Asked by At

The purpose in this context is to prevent false high scores(my app is a game) from being reported in LeaderBoard. This occurred for Flappy Birds - see this link - http://www.androidpit.com/forum/589832/flappy-bird-high-score-cheat-set-your-own-high-score

Since a root user can do anything he wants with his mobile, I suppose none of the other work around will work and the only solution is to prevent rooted users from installing the app. Am I right? Is there a way to do it?

PS: My game doesn't need internet connection always, hence reporting the scores as and when it happens to another server is not viable. The high scores are reported to leaderboard only when internet connection is available.

6

There are 6 answers

3
MysticMagicϡ On BEST ANSWER

I had a similar requirement. I couldn't achieve that app should not be installed on rooted device, but I used a work around for that:

  • Check if your device is rooted in your activity's onResume.
  • If its rooted, just show him alert "This device is rooted. You can't use this app.", and exit from application.

Example:

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    if(new DeviceUtils().isDeviceRooted(getApplicationContext())){
        showAlertDialogAndExitApp("This device is rooted. You can't use this app.");
    }
}


public void showAlertDialogAndExitApp(String message) {

    AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
    alertDialog.setTitle("Alert");
    alertDialog.setMessage(message);
    alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    Intent intent = new Intent(Intent.ACTION_MAIN);
                    intent.addCategory(Intent.CATEGORY_HOME);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                    finish();
                }
            });

    alertDialog.show();
}

DeviceUtis.java was a Utility class which returned if a device is rooted or not.

public class DeviceUtils {

    public Boolean isDeviceRooted(Context context){
        boolean isRooted = isrooted1() || isrooted2();
        return isRooted;
    }

    private boolean isrooted1() {

        File file = new File("/system/app/Superuser.apk");
        if (file.exists()) {
            return true;
        }
        return false;
    }

    // try executing commands
    private boolean isrooted2() {
        return canExecuteCommand("/system/xbin/which su")
                || canExecuteCommand("/system/bin/which su")
                || canExecuteCommand("which su");
    }
}

We had used 5 methods for testing, and I have just shown 2 here. You can use any of methods you find good.

Hope this helps.

P.S: I have put this call in all activity's onResume as user (with intention of hacking) can install application, navigate to some other activity, and then root device.

5
aggsol On

There is no need to block users with rooted phones as it normal user behaviour. So, what kind of danger or damage do you fear if you have no online connection for highscores, in-app purchases or the like in your game?

The player wants to cheat her way to the last level or to the top of the local(!) leaderboard? Where is the damage?

By preventing your game from running on rooted devices gains you nothing but repell legitimate users of your app.

Edit:

Use the cloud save service to save the player's highscores. if offline it will be encrypted and stored on the device. The next time online you read the highscore and send it to the play service. The play service provides an anti piracy feature you also might want.

1
Prashant Jajal On

With Kotlin Extention you can check easily that, is device is rooted or not. below is the code which may help you out

DeviceUtils.kt

object DeviceUtils {
    fun isDeviceRooted(context: Context?): Boolean {
        return isRooted1 || isRooted2
    }

    private val isRooted1: Boolean
        get() {
            val file = File("/system/app/Superuser.apk")
            return file.exists()
        }

    // try executing commands
    private val isRooted2: Boolean
        get() = (canExecuteCommand("/system/xbin/which su")
                || canExecuteCommand("/system/bin/which su")
                || canExecuteCommand("which su"))

    private fun canExecuteCommand(command: String): Boolean {
        return try {
            Runtime.getRuntime().exec(command)
            true
        } catch (e: Exception) {
            false
        }
    }
}

Extention.kt

fun Activity.checkDeviceRoot(): Boolean {
    return if (DeviceUtils.isDeviceRooted(this)) {
        AlertDialog.Builder(this)
                .setMessage("Your device is rooted. you can not use this app into rooted device.")
                .setCancelable(false)
                .setPositiveButton(R.string.alert_ok) { _, _ ->
                    exitProcess(0)
                }.show()
        true
    } else {
        false
    }
}

How to use this extention:

class MyActivity : Activity{
    ...
    override 
    fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_splash)

        if(checkDeviceRoot())
            return
        ....
        ....
    }
}

Hope This answer will help you out.

0
Abdullqadir On

If you are using Firebase crashlytics in your project. you can use this method where ever is suitable for you. it is recommended to use it in onResume of your activity and then show a dialog to exit the application. I have tested this on the Nox emulator and worked fine. However, through my research for this purpose, I did not find a way that covers all the cases the user can always do some workaround to use the application.

CommonUtils.isRooted()
1
Karthikraja K On
private static boolean canExecuteCommand(String command) {
        boolean executedSuccesfully;
        try {
            Runtime.getRuntime().exec(command);
            executedSuccesfully = true;
        } catch (Exception e) {
            executedSuccesfully = false;
        }

        return executedSuccesfully;
    }
0
Kalpesh Wadekar On

We have an option in playstore console of SafetyNet exclusion, which we can use to prevent app to appear on playstore for downloading on rooted devices.

There is Safety Net Attestation API of Google play services by which we can assess the device and determine if it is rooted/tampered.

To whom who want to deal with rooted device, please go through my answer: https://stackoverflow.com/a/58304556/3908895