how to find the rooted device programmatically?
在安装我的应用程序之前,我希望它检查设备是否已root。我已使用以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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",并且可以在非root用户的设备中创建一个名称为" su"的文件。在这种情况下,此源不可靠。除了搜索" su"外,我还想知道其他方法来找到有根的设备。
我使用了以下代码
1 2 3 4 5 6 7 8 9 10 11 12 | Public static boolean checkRootMethod1() { String buildTags = android.os.Build.TAGS; if (buildTags != null && buildTags.contains("test-keys")) { return true; } return false; } |
它不能正常工作。对于有根设备,它按预期工作。但是对于某些无根设备,它也显示为有根。由于不同设备的输出各不相同,所以我找不到解决方案。任何帮助将不胜感激<铅>
如果您想限制在根设备上使用应用程序,则必须考虑两点:
1)限制在根目录设备中下载该应用程序。
2)限制根设备中应用的侧载。
请按照以下步骤限制从Play商店下载:
1)进入商店控制台。
2)在左侧菜单上,转到发布管理。
3)在那,去设备目录。
4)然后,您将获得3个选项卡选项,转到"排除的设备"。
5)您将获得一个指定排除规则的选项。点击管理排除规则。
6)您可以看到SafetyNet排除项的选择器。选择选项:排除未通过基本完整性的设备以及未经google认证的设备。
请按照以下步骤限制应用的侧面加载:
1)使用以下网址获取API密钥:https://developer.android.com/training/safetynet/attestation.html#obtain-api-key
2)在gradle文件中添加safetynet依赖项。
3)我在我的其他活动扩展的BaseActivity中放置了下面的代码,因此,如果拥有根设备的黑客尝试侧加载并尝试输入任何活动,则将执行下面的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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.
Attestation API返回一个JWS响应,如下所示:
1 2 3 4 5 6 7 8 9 | { "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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public static boolean checkRooted() { try { Process p = Runtime.getRuntime().exec("su", null, new File("/")); DataOutputStream os = new DataOutputStream( p.getOutputStream()); os.writeBytes("pwd\ "); os.writeBytes("exit\ "); os.flush(); p.waitFor(); p.destroy(); } catch (Exception e) { return false; } return true; } |
尝试以下代码:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /** * Checks if the device is rooted. * * @return <wyn>true</wyn> if the device is rooted, <wyn>false</wyn> 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; } |
请参见以下链接:-
确定是否在有根设备上运行
确定Android设备是否以编程方式植根?