I was developing an app which had requirement to implement root detection logic, so by researching I found some detection logic in JAVA and had implemented following class.
class RootDetection {
public boolean isDeviceRooted() {
return checkForBinary("su") || checkForBinary("busybox") || checkForMaliciousPaths() || checkSUonPath()
|| detectRootManagementApps() || detectPotentiallyDangerousApps() || detectRootCloakingApps()
|| checkForDangerousProps() || checkForRWPaths()
|| detectTestKeys() || checkSuExists();
}
private boolean detectTestKeys() {
String buildTags = android.os.Build.TAGS;
String buildFinger = Build.FINGERPRINT;
String product = Build.PRODUCT;
String hardware = Build.HARDWARE;
String display = Build.DISPLAY;
System.out.println("Java: build: " + buildTags + "\nFingerprint: " + buildFinger + "\n Product: " + product + "\n Hardware: " + hardware + "\nDisplay: " + display);
return (buildTags != null) && (buildTags.contains("test-keys") || buildFinger.contains("genric.*test-keys") || product.contains("generic") || product.contains("sdk") || hardware.contains("goldfish") || display.contains(".*test-keys"));
}
private boolean detectRootManagementApps() {
return detectRootManagementApps(null);
}
private boolean detectRootManagementApps(String[] additionalRootManagementApps) {
ArrayList<String> packages = new ArrayList<>();
packages.addAll(Arrays.asList(knownRootAppsPackages));
if (additionalRootManagementApps != null && additionalRootManagementApps.length > 0) {
packages.addAll(Arrays.asList(additionalRootManagementApps));
}
return isAnyPackageFromListInstalled(packages);
}
private boolean detectPotentiallyDangerousApps() {
return detectPotentiallyDangerousApps(null);
}
private boolean detectPotentiallyDangerousApps(String[] additionalDangerousApps) {
ArrayList<String> packages = new ArrayList<>();
packages.addAll(Arrays.asList(knownDangerousAppsPackages));
if (additionalDangerousApps != null && additionalDangerousApps.length > 0) {
packages.addAll(Arrays.asList(additionalDangerousApps));
}
return isAnyPackageFromListInstalled(packages);
}
private boolean detectRootCloakingApps() {
return detectRootCloakingApps(null);
}
private boolean detectRootCloakingApps(String[] additionalRootCloakingApps) {
ArrayList<String> packages = new ArrayList<>();
packages.addAll(Arrays.asList(knownRootCloakingPackages));
if (additionalRootCloakingApps != null && additionalRootCloakingApps.length > 0) {
packages.addAll(Arrays.asList(additionalRootCloakingApps));
}
return isAnyPackageFromListInstalled(packages);
}
private boolean checkForBinary(String filename) {
for (String path : suPaths) {
String completePath = path + filename;
File f = new File(completePath);
boolean fileExists = f.exists();
if (fileExists) {
return true;
}
}
return false;
}
private boolean checkForMaliciousPaths() {
for (String path : maliciousPaths) {
File f = new File(path);
boolean fileExists = f.exists();
if (fileExists) {
return true;
}
}
return false;
}
private static boolean checkSUonPath() {
for (String pathDir : System.getenv("PATH").split(":")) {
if (new File(pathDir, "su").exists()) {
return true;
}
}
return false;
}
private String[] propsReader() {
InputStream inputstream = null;
try {
inputstream = Runtime.getRuntime().exec("getprop").getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
String propval = "";
try {
propval = new Scanner(inputstream).useDelimiter("\\A").next();
} catch (NoSuchElementException e) {
}
return propval.split("\n");
}
private String[] mountReader() {
InputStream inputstream = null;
try {
inputstream = Runtime.getRuntime().exec("mount").getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
if (inputstream == null) return null;
String propval = "";
try {
propval = new Scanner(inputstream).useDelimiter("\\A").next();
} catch (NoSuchElementException e) {
e.printStackTrace();
}
return propval.split("\n");
}
private boolean isAnyPackageFromListInstalled(List<String> packages) {
PackageManager pm = activity.getPackageManager();
for (String packageName : packages) {
try {
pm.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
}
}
return false;
}
private boolean checkForDangerousProps() {
final Map<String, String> dangerousProps = new HashMap<>();
dangerousProps.put("ro.debuggable", "1");
dangerousProps.put("ro.secure", "0");
String[] lines = propsReader();
for (String line : lines) {
for (String key : dangerousProps.keySet()) {
if (line.contains(key)) {
String badValue = dangerousProps.get(key);
badValue = "[" + badValue + "]";
if (line.contains(badValue)) {
return true;
}
}
}
}
return false;
}
private boolean checkForRWPaths() {
String[] lines = mountReader();
for (String line : lines) {
String[] args = line.split(" ");
if (args.length < 4) {
continue;
}
String mountPoint = args[1];
String mountOptions = args[3];
for (String pathToCheck : pathsThatShouldNotBeWrtiable) {
if (mountPoint.equalsIgnoreCase(pathToCheck)) {
for (String option : mountOptions.split(",")) {
if (option.equalsIgnoreCase("rw")) {
return true;
}
}
}
}
}
return false;
}
private boolean checkSuExists() {
Process process = null;
try {
process = Runtime.getRuntime().exec(new String[]{"which", "su"});
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
return in.readLine() != null;
} catch (Throwable t) {
return false;
} finally {
if (process != null) process.destroy();
}
}
}
but now to increase security I want to do this root detection logic in native C++ JNI code. I managed to migrate package detection code to JNI C but am not able to find anything regarding these 3 functions
checkForDangerousProps(),checkForRWPaths(),checkSuExists()
these 3 use Runtime.getRuntime().exec which am not able to find. can someone help me in converting this 3 logics to JNI C one from above code? Help would be really appreciated.
Pls guys help.