how to find the rooted device programmatically?
Asked Answered
M

4

6

Before installing my application,i want it to check whether the device is rooted or not.I have used the following code

private static boolean isRooted()

                 return findBinary("su");
        }
    public static boolean findBinary(String binaryName) {

        boolean found = false;
        if (!found) {

            String[] places = {"/sbin/", "/system/bin/", "/system/xbin/", "/data/local/xbin/",
                    "/data/local/bin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/"};
            for (String where : places) {
                if ( new File( where + binaryName ).exists() ) {

                    found = true;
                    break;
                }
            }
        }
        return found;
    } 

It is working properly.But i have heard that the filename "su" can be changed and also a file with the name "su" can be created in the nonrooted devices.In that cases,this source is not dependable.so i want to know some other way to find the rooted device other than searching for "su". I have used the following code

   Public static boolean checkRootMethod1()

     {
        String buildTags = android.os.Build.TAGS;

        if (buildTags != null && buildTags.contains("test-keys")) {

            return true;
        }

        return false;
    }

It is not working properly.For rooted devices it works as expected.But for SOME unrooted devices also it shows as rooted.Since the output is variying for differnt devices,i cannot find a solution..any help would be appreciated

Magnetics answered 2/7, 2014 at 5:39 Comment(4)
look into this..#3424695Gobioid
there is no real solution because you can root your device on so many ways. try to get the most spread methodStrategy
Don't know much about root development, still an idea. Try to access root permission, if that fails that means the device isn't rooted or the user won't be giving you root permissions. Either be the case, the device isn't rooted for you. Will it work?Debus
just a wild guess here: Try creating a file in a directory, which requires root access. If you succeed, you are rooted. If not - you aren't rooted, or root access has been denied.Ironwork
T
24

If you want to restrict usage of your app in the rooted device then you have to think of 2 points:
1) Restrict downloading of the app in the rooted device.
2) Restrict sideloading of the app in the rooted device.

Follow below steps to restrict downloading from the play store:
1) Go to play store console.
2) On the left side menu, go to release management.
3) In that, go to device catalog.
4) Then you will get 3 tab options, go to Excluded devices.
5) You will get an option to specify exclusion rules. click on manage exclusion rules.
6) You can see a chooser for SafetyNet exclusion. choose the option: exclude devices that don't pass basic integrity, as well as devices that are uncertified by google.

Follow below steps to restrict the sideloading of the app:
1) Obtain an API key using: https://developer.android.com/training/safetynet/attestation.html#obtain-api-key

2) Add safetynet dependency in your gradle file.
implementation 'com.google.android.gms:play-services-safetynet:17.0.0'

3) I have put below code in my BaseActivity which my other activities extend, so If a hacker with the rooted device tries to sideload and tries to enter at any activity then below code executes.

    private void ifGooglePlayServicesValid() {
        if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getApplicationContext())
                == ConnectionResult.SUCCESS) {
            // The SafetyNet Attestation API is available.
            callSafetyNetAttentationApi();

        } else {
            // Prompt user to update Google Play services.
        }
    }

    private void callSafetyNetAttentationApi() {
        SafetyNet.getClient(this).attest(generateNonce(), SAFETY_NET_CHECK_API_KEY)
            .addOnSuccessListener(this,
                response -> {
                    // Use response.getJwsResult() to get the result data.
                    String jwsResponse = decodeJws(response.getJwsResult());
                    try {
                        JSONObject attestationResponse = new JSONObject(jwsResponse);
                        boolean ctsProfileMatch = attestationResponse.getBoolean("ctsProfileMatch");
                        boolean basicIntegrity = attestationResponse.getBoolean("basicIntegrity");
                        if (!ctsProfileMatch || !basicIntegrity) {
                            // this indicates it's rooted/tampered device
                        }
                    } catch (JSONException e) {
                        // json exception
                    }
                })
            .addOnFailureListener(this, e -> {
                // An error occurred while communicating with the service.
            });
    }

    public String decodeJws(String jwsResult) {
        if (jwsResult == null) {
            return null;
        }
        final String[] jwtParts = jwsResult.split("\\.");
        if (jwtParts.length == 3) {
            return new String(Base64.decode(jwtParts[1], Base64.DEFAULT));
        } else {
            return null;
        }
    }

    private byte[] generateNonce() {
        byte[] nonce = new byte[16];
        new SecureRandom().nextBytes(nonce);
        return nonce;
    }

SAFETY_NET_CHECK_API_KEY is the key obtained in the 1st step.

The Attestation API returns a JWS response which looks like:

{
  "timestampMs": 9860437986543,
  "nonce": "R2Rra24fVm5xa2Mg",
  "apkPackageName": "com.package.name.of.requesting.app",
  "apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
                                  certificate used to sign requesting app"],
  "ctsProfileMatch": true,
  "basicIntegrity": true,
}

The JWS response contains ctsProfileMatch and basicIntegrity that indicate the device status.

enter image description here
Reference: https://developer.android.com/training/safetynet/attestation.html

Trap answered 9/10, 2019 at 12:51 Comment(3)
Hi great answer, can you tell me callSafetyNetAttentationApi() method is async or blocking ? To use it any base activity is great only if it checks in async mode.Parlor
Also just found out that this has a daily quota limit and is not suitable for apps with large user base.Parlor
The documentation explicitly says SafetyNet API is NOT designed for root checks.Producer
R
2
public static boolean checkRooted()
{
    try
    {
        Process p = Runtime.getRuntime().exec("su", null, new File("/"));
        DataOutputStream os = new DataOutputStream( p.getOutputStream());
        os.writeBytes("pwd\n");
        os.writeBytes("exit\n");
        os.flush();
        p.waitFor();
        p.destroy();
    }
    catch (Exception e)
    {
        return false;
    }

    return true;
}
Revolting answered 13/11, 2016 at 7:16 Comment(0)
A
0

try below code:-

 /**
   * Checks if the device is rooted.
   *
   * @return <code>true</code> if the device is rooted, <code>false</code> otherwise.
   */
  public static boolean isRooted() {

    // get from build info
    String buildTags = android.os.Build.TAGS;
    if (buildTags != null && buildTags.contains("test-keys")) {
      return true;
    }

    // check if /system/app/Superuser.apk is present
    try {
      File file = new File("/system/app/Superuser.apk");
      if (file.exists()) {
        return true;
      }
    } catch (Exception e1) {
      // ignore
    }

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

  // executes a command on the system
  private static boolean canExecuteCommand(String command) {
    boolean executedSuccesfully;
    try {
      Runtime.getRuntime().exec(command);
      executedSuccesfully = true;
    } catch (Exception e) {
      executedSuccesfully = false;
    }

    return executedSuccesfully;
  }

see below link:-

Determine if running on a rooted device

Determining if an Android device is rooted programatically?

Allain answered 2/7, 2014 at 5:41 Comment(3)
This doesn't look like a very reliable way of detecting rooting. There are tools available that will hide the presence of su/Superuser in order to make root detection more difficult.Photoplay
@nani my new check linkAllain
yep michael.that is y i am looking for someother way.finding buildtags too gives me unreliable solution.Magnetics
E
0

Previously, we detected rooted/jailbroken devices using the SafetyNet Attestation API. however, this API is now deprecated, thus we must switch to the Play Integrity API.

Play Integrity API will provide below information's

  1. Whether the app has been installed from your Google Play Store listing or not? This helps you ensure that your users are not running tampered versions of your app.
  2. Whether the app is licensed, and was purchased by the user from the Play Store - after making payment, or is it a pirated version?
  3. Whether the device itself is a trusted device or is it a rooted, tampered, or otherwise a device that is not considered safe.

SafetyNet Attestation - https://developer.android.com/training/safetynet/attestation

Play Integrity API - https://developer.android.com/google/play/integrity/overview

Edme answered 14/3, 2023 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.