Как найти рутованное устройство программно?
Перед установкой моего приложения я хочу проверить, является ли устройство рутованным или нет. Я использовал следующий код
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;
}
Он работает должным образом. Но я слышал, что имя файла "su" можно изменить, а также файл с именем "su" может быть создан на нерутированных устройствах. В этом случае этот источник не является надежным. Поэтому я хочу знать какой-то другой способ найти корневое устройство, кроме поиска "su". Я использовал следующий код
Public static boolean checkRootMethod1()
{
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
return false;
}
Он не работает должным образом. Для рутованных устройств он работает как положено. Но для НЕКОТОРЫХ нерутированных устройств он также отображается как рутированный. Так как выходные данные меняются для разных устройств, я не могу найти решение... любая помощь будет оценена
4 ответа
Если вы хотите ограничить использование вашего приложения на корневом устройстве, вам нужно подумать о 2 пунктах:
1) Ограничить загрузку приложения на корневом устройстве.
2) Ограничьте загрузку неопубликованных приложений на корневом устройстве.
Выполните следующие шаги, чтобы ограничить загрузку из магазина воспроизведения:
1) Перейдите в консоль магазина воспроизведения.
2) В меню слева перейдите к управлению выпусками.
3) При этом перейдите в каталог устройств.
4) Затем вы получите 3 варианта вкладки, перейдите в Исключенные устройства.
6) Вы можете увидеть средство выбора исключения из сети SafetyNet. выберите вариант: исключить устройства, не прошедшие базовую целостность, а также устройства, не сертифицированные Google.
5) Вы получите возможность указать правила исключения. нажмите на управление правилами исключения.
Выполните следующие шаги, чтобы ограничить загрузку неопубликованных приложений:
1) Получите ключ API, используя: https://developer.android.com/training/safetynet/attestation.html
2) Добавьте зависимость safetynet в свой gradle файл.
implementation 'com.google.android.gms:play-services-safetynet:17.0.0'
3) Я поместил ниже код в мою BaseActivity, который расширяет мои другие действия, поэтому, если хакер с рутированным устройством пытается выполнить боковую загрузку и пытается войти в любое действие, выполняется следующий код.
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 - это ключ, полученный на 1-м шаге.
API аттестации возвращает ответ JWS, который выглядит следующим образом:
{
"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,
}
Ответ JWS содержит ctsProfileMatch и basicIntegrity, которые указывают состояние устройства. Ссылка: https://developer.android.com/training/safetynet/attestation.html
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;
}
Ранее мы обнаруживали устройства с root-правами и взломанными устройствами с помощью API аттестации SafetyNet. однако этот API устарел, поэтому нам необходимо переключиться на Play Integrity API.
Play Integrity API предоставит приведенную ниже информацию.
- Было ли приложение установлено из вашего списка Google Play Store или нет? Это поможет вам гарантировать, что ваши пользователи не используют подделанные версии вашего приложения.
- Является ли приложение лицензионным и было куплено пользователем в Play Store - после оплаты, или это пиратская версия?
- Является ли само устройство доверенным устройством или оно является рутированным, подделанным или иным образом не считается безопасным устройством.
Аттестация SafetyNet — https://developer.android.com/training/safetynet/attestation.
Play Integrity API – https://developer.android.com/google/play/integrity/overview.
Попробуйте ниже код:-
/**
* 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;
}
см. ссылку ниже:-