我的应用程序有一个特定的功能,只能在根可用的设备上工作。与其让这个特性在使用时失败(然后向用户显示适当的错误消息),我更希望能够先静默地检查根目录是否可用,如果不可用,则首先隐藏相应的选项。
有办法做到这一点吗?
我的应用程序有一个特定的功能,只能在根可用的设备上工作。与其让这个特性在使用时失败(然后向用户显示适当的错误消息),我更希望能够先静默地检查根目录是否可用,如果不可用,则首先隐藏相应的选项。
有办法做到这一点吗?
当前回答
忘记所有那些检测根应用程序和子二进制文件。检查根守护进程。这可以从终端完成,你可以在应用程序中运行终端命令。试试这一行。
if [ ! "$(/system/bin/ps -A | grep -v grep | grep -c daemonsu)" = "0" ]; then echo "device is rooted"; else echo "device is not rooted"; fi
您也不需要root权限来实现这一点。
编辑:现在使用这种方法更好的检测!
if [ $(ps -A | grep -e ^shell -e ^root | grep -v "\[" | tr -s ' ' | cut -d ' ' -f 9 | grep -c su) ] || [ $(which su) ]; then echo 'rooted'; else echo 'not rooted'; fi
其他回答
如果你已经在使用Fabric/Firebase Crashlytics,你可以打电话
CommonUtils.isRooted(context)
这是该方法的当前实现:
public static boolean isRooted(Context context) {
boolean isEmulator = isEmulator(context);
String buildTags = Build.TAGS;
if (!isEmulator && buildTags != null && buildTags.contains("test-keys")) {
return true;
} else {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
return true;
} else {
file = new File("/system/xbin/su");
return !isEmulator && file.exists();
}
}
}
public static boolean isEmulator(Context context) {
String androidId = Secure.getString(context.getContentResolver(), "android_id");
return "sdk".equals(Build.PRODUCT) || "google_sdk".equals(Build.PRODUCT) || androidId == null;
}
另外两个方法,如果你想检查一个设备在你的应用程序中是否具有根功能:
检查是否存在“su”二进制文件:从Runtime.getRuntime().exec()运行"which su" 在/system/app/ SuperUser.apk目录下查找SuperUser.apk
RootTools库提供了简单的方法来检查根:
RootTools.isRootAvailable()
参考
更新2017
你现在可以用谷歌Safetynet API做到这一点。SafetyNet API提供了认证API,它可以帮助您评估应用程序运行的Android环境的安全性和兼容性。
这种认证可以帮助确定特定设备是否被篡改或修改过。
认证API返回如下所示的JWS响应
{
"nonce": "R2Rra24fVm5xa2Mg",
"timestampMs": 9860437986543,
"apkPackageName": "com.package.name.of.requesting.app",
"apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
certificate used to sign requesting app"],
"apkDigestSha256": "base64 encoded, SHA-256 hash of the app's APK",
"ctsProfileMatch": true,
"basicIntegrity": true,
}
解析此响应可以帮助您确定设备是否已扎根
根设备似乎导致ctsProfileMatch=false。
您可以在客户端执行此操作,但建议在服务器端解析响应。 一个基本的客户端服务器架构与安全网API将看起来像这样
使用c++和ndk是最好的方法来检测根,即使用户使用的应用程序隐藏了他的根,如RootCloak。我用RootCloak测试了这段代码,即使用户试图隐藏它,我也能够检测到根。 所以你的cpp文件是这样的:
#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();
}