/**
* Checks if the phone is rooted.
*
* @return <code>true</code> if the phone is rooted, <code>false</code>
* otherwise.
*/
public static boolean isPhoneRooted() {
// 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 (Throwable e1) {
// ignore
}
return false;
}
//Pass true to <Shell>.start(...) call to run as superuser
Shell shell = null;
try {
shell = Shell.start(true);
} catch (IOException exception) {
exception.printStackTrace();
}
if (shell == null)
// We failed to execute su binary
return;
if (shell.isRoot()) {
// Verified running as uid 0 (root), can continue with commands
...
} else
throw Exception("Unable to gain root access. Make sure you pressed Allow/Grant in superuser prompt.");
if [[ "`adb shell which su | grep -io "permission denied"`" != "permission denied" ]]; then
echo "Yes. Rooted device."
else
echo "No. Device not rooted. Only limited tasks can be performed. Done."
zenity --warning --title="Device Not Rooted" --text="The connected Android Device is <b>NOT ROOTED</b>. Only limited tasks can be performed." --no-wrap
fi
#include <string.h>
#include <jni.h>
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include "android_log.h"
#include <errno.h>
#include <unistd.h>
#include <sys/system_properties.h>
JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod1(
JNIEnv* env, jobject thiz) {
//Access function checks whether a particular file can be accessed
int result = access("/system/app/Superuser.apk",F_OK);
ANDROID_LOGV( "File Access Result %d\n", result);
int len;
char build_tags[PROP_VALUE_MAX]; // PROP_VALUE_MAX from <sys/system_properties.h>.
len = __system_property_get(ANDROID_OS_BUILD_TAGS, build_tags); // On return, len will equal (int)strlen(model_id).
if(strcmp(build_tags,"test-keys") == 0){
ANDROID_LOGV( "Device has test keys\n", build_tags);
result = 0;
}
ANDROID_LOGV( "File Access Result %s\n", build_tags);
return result;
}
JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod2(
JNIEnv* env, jobject thiz) {
//which command is enabled only after Busy box is installed on a rooted device
//Outpput of which command is the path to su file. On a non rooted device , we will get a null/ empty path
//char* cmd = const_cast<char *>"which su";
FILE* pipe = popen("which su", "r");
if (!pipe) return -1;
char buffer[128];
std::string resultCmd = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
resultCmd += buffer;
}
pclose(pipe);
const char *cstr = resultCmd.c_str();
int result = -1;
if(cstr == NULL || (strlen(cstr) == 0)){
ANDROID_LOGV( "Result of Which command is Null");
}else{
result = 0;
ANDROID_LOGV( "Result of Which command %s\n", cstr);
}
return result;
}
JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod3(
JNIEnv* env, jobject thiz) {
int len;
char build_tags[PROP_VALUE_MAX]; // PROP_VALUE_MAX from <sys/system_properties.h>.
int result = -1;
len = __system_property_get(ANDROID_OS_BUILD_TAGS, build_tags); // On return, len will equal (int)strlen(model_id).
if(len >0 && strstr(build_tags,"test-keys") != NULL){
ANDROID_LOGV( "Device has test keys\n", build_tags);
result = 0;
}
return result;
}
#include <jni.h>
#include <string>
/**
*
* function that checks for the su binary files and operates even if
* root cloak is installed
* @return integer 1: device is rooted, 0: device is not
*rooted
*/
extern "C"
JNIEXPORT int JNICALL
Java_com_example_user_root_1native_rootFunction(JNIEnv *env,jobject thiz){
const char *paths[] ={"/system/app/Superuser.apk", "/sbin/su", "/system/bin/su",
"/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
"/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};
int counter =0;
while (counter<9){
if(FILE *file = fopen(paths[counter],"r")){
fclose(file);
return 1;
}
counter++;
}
return 0;
}
您将从java代码中调用该函数,如下所示
public class Root_detect {
/**
*
* function that calls a native function to check if the device is
*rooted or not
* @return boolean: true if the device is rooted, false if the
*device is not rooted
*/
public boolean check_rooted(){
int checker = rootFunction();
if(checker==1){
return true;
}else {
return false;
}
}
static {
System.loadLibrary("cpp-root-lib");//name of your cpp file
}
public native int rootFunction();
}
if(GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context, 13000000) == ConnectionResult.SUCCESS) {
Log.e(TAG, "The SafetyNet Attestation API is available");
// TODO(developer): Change the nonce generation to include your own, used once value,
// ideally from your remote server.
String nonceData = "Safety Net Sample: " + System.currentTimeMillis();
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
Random mRandom = new SecureRandom();
byte[] bytes = new byte[24];
mRandom.nextBytes(bytes);
try {
byteStream.write(bytes);
byteStream.write(nonceData.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
byte[] nonce = byteStream.toByteArray();
SafetyNetClient client = SafetyNet.getClient(context);
Task<SafetyNetApi.AttestationResponse> task = client.attest(nonce, API_KEY_FROM_STEP_2_LINK);
task.addOnSuccessListener(context, attestationResponse -> {
/*
TODO(developer): Forward this result to your server together with
the nonce for verification.
You can also parse the JwsResult locally to confirm that the API
returned a response by checking for an 'error' field first and before
retrying the request with an exponential backoff.
NOTE: Do NOT rely on a local, client-side only check for security, you
must verify the response on a remote server!
*/
String jwsResult = attestationResponse.getJwsResult();
Log.e(TAG, "Success! SafetyNet result:\n" + jwsResult + "\n");
if (jwsResult == null) {
Log.e(TAG, "jwsResult Null");
}
final String[] jwtParts = jwsResult.split("\\.");
if (jwtParts.length == 3) {
String decodedPayload = new String(Base64.decode(jwtParts[1], Base64.DEFAULT));
Log.e(TAG, "decodedPayload : " + decodedPayload);
}
});
task.addOnFailureListener(context, e -> {
// An error occurred while communicating with the service.
String mResult = null;
if (e instanceof ApiException) {
// An error with the Google Play Services API contains some additional details.
ApiException apiException = (ApiException) e;
Util.showLog(TAG, "Error: " +
CommonStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " +
apiException.getStatusMessage());
} else {
// A different, unknown type of error occurred.
Log.e(TAG, "ERROR! " + e.getMessage());
}
});
} else {
Log.e(TAG, "Prompt user to update Google Play services.";
}
{ "nonce": "6pLrr9zWyl6TNzj+kpbR4LZcfPY3U2FmZXR5IE5ldCBTYW1wbGU6IDE2MTQ2NzkwMTIzNjc=", "timestampMs": 9860437986543, "apkPackageName": " your package name will be displayed here", "ctsProfileMatch": true, "apkDigestSha256": [ "base64 encoded, SHA-256 hash of the certificate used to sign requesting app" ], "basicIntegrity": true, "evaluationType": "BASIC" }