Статья Android/Xposed/Cydia: Ищем root и то, что может скрыть его

deadroot

deadroot

Well-known member
06.01.2019
60
134
Привет,

Пару лет назад нужно было скрывать что на Android девайсе есть root. Было проведено изучение как определяют root права мобильные SDK (в основном рекламные, так как им нужно строить свои системы аналитики и антифрода для препятствия работе накрутчиков и скликивальщиков , но и остальные были проверены в тоннах Smali кода). Вообще много для каких задач нужно проверять наличие расширенных прав. Так делают банковские приложения для защиты, некоторое проприетарное ПО для того, чтобы скрыть свою работу или действия от динамического анализа (про статический анализ не буду говорить, так как скачать apk и засунуть его в анализатор типа ничего не стоит, хотя MobSF умеет и в динамический).

Вообщем, получилось найти, выделить и додумать как бы я определял (если бы очень хотел найти того, кто прячет root) 9 основных методов, а именно:
  1. su Binary
  2. busybox Binary
  3. check Su Exists
  4. su Managers
  5. detect Root Hiders
  6. dangerous Build.prop values
  7. test-keys
  8. rw System Folders
  9. Xposed or Cydia
Сейчас расскажу о способах детекта root-прав поподробнее и с примерами кода, которые помогут вам определить есть ли у вас (или не у вас) дополнительные привелегии различными способами :)


su Binary, busybox Binary
Самый простой и самый распространенный это, конечно же проверять наличие бинарников su и busybox (без su онbusybox не зайдет), поэтому метод один и тот же и искать будем там, куда их только не засунут, а именно посмотрите на pathsArray (может быть, список и не полный, он нам хватало).

Java:
    private boolean binaries(String filename) {
        List<String> pathsArray = Arrays.asList(
                "/data/local/",
                "/data/local/bin/",
                "/data/local/xbin/",
                "/sbin/",
                "/system/bin/",
                "/system/sd/xbin/",
                "/system/xbin/",
                "/data/.super"
        );

        boolean result = false;
        StringBuilder val = new StringBuilder();
        for (String path : pathsArray) {
            String completePath = path + filename;
            File f = new File(completePath);
            boolean fileExists = f.exists();
            if (fileExists) {
                val.append(path).append("\n");
                result = true;
            }
        }
        if (!val.toString().isEmpty()) values.put(filename + " Binary", val.toString());
        return result;
    }
После того, как проверили наличие бинарника su можно проверить вообще он есть или нет. Вдруг куда его еще засунули, а мы не нашли?

Java:
    private boolean checkSuExists() {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            boolean exist = in.readLine() != null;
            if (exist) {
                values.put("check Su Exists", "Runtime.getRuntime().exec(new String[] { \"/system/xbin/which\", \"su\" })");
            }
            return exist;
        } catch (Throwable t) {
            return false;
        } finally {
            if (process != null) process.destroy();
        }
    }
su Managers
Тут все понятно. Есть не такое обширное количество различных приложений-менеджеров root прав. Берем из список и проверяем.

Java:
    private boolean suManagers() {
        return suManagers(null, "su Managers");
    }

    private boolean suManagers(String[] additionalRootManagementApps, String key) {
        List<String> packages = Arrays.asList(
                "com.noshufou.android.su",
                "com.noshufou.android.su.elite",
                "eu.chainfire.supersu",
                "com.koushikdutta.superuser",
                "com.thirdparty.superuser",
                "com.yellowes.su",
                "eu.chainfire.supersu.pro",
                "com.m0narx.su"
        );
        if (additionalRootManagementApps != null && additionalRootManagementApps.length > 0){
            packages.addAll(Arrays.asList(additionalRootManagementApps));
        }
        return pmManager(packages, key);
    }
detect Root Hiders
Не мы одни такие хитрые. Есть же и такие приложения, кто прячет наличие root-менеджеров, которые скрывают root ;) Давайте и их искать!

Java:
    private boolean rootHiders() {
        return rootHiders(null, "detect Root Hiders");
    }

    private boolean rootHiders(String[] additionalRootCloakingApps, String key) {
        List<String> packages = Arrays.asList("com.devadvance.rootcloak",
                "de.robv.android.xposed.installer",
                "com.saurik.substrate",
                "com.devadvance.rootcloakplus",
                "com.amphoras.hidemyroot",
                "com.formyhm.hideroot",
                "com.loserskater.suhidegui"
        );
        if (additionalRootCloakingApps != null && additionalRootCloakingApps.length>0){
            packages.addAll(Arrays.asList(additionalRootCloakingApps));
        }
        return pmManager(packages, key);
    }
dangerous Build.prop values
Дальше можно увеличивать количество и качество нашей паранойи и начать смотреть в Build.prop. В этом файле есть пара параметров, по наличию или статусу которых можно теоритически что-то начать подозревать. А именно
  1. ro.debuggable=1 (дебажат?)
  2. ro.secure=0 (тоже зачем выключили? не понятно)
  3. ro.build.selinux=1 (тут все встает на свои места)
Java:
    private boolean buildPropChecker() {

        final Map<String, String> badBProps = new HashMap<>();
        badBProps.put("ro.debuggable", "1");
        badBProps.put("ro.secure", "0");
        badBProps.put("ro.build.selinux", "0");

        boolean result = false;

        String[] lines = propsReader();
        if (lines == null) {
            return false;
        }
        StringBuilder val = new StringBuilder();
        for (String line : lines) {
            for (String key : badBProps.keySet()) {
                if (line.contains(key)) {
                    if (line.contains(String.format("[%s]", badBProps.get(key)))) {
                        val.append(line).append("\n");
                        result = true;
                    }
                }
            }
        }
        values.put("dangerous Build.prop values", val.toString());
        return result;
    }
test-keys
По аналогии с предыдущим пунктом проверим и наличие test-keys в android.os.Build.TAGS. При наличии такого параметра можно тоже можно начать думать что тут что-то не чисто.

Java:
    private boolean roBuildChecker() {
        StringBuilder val = new StringBuilder();
        if (android.os.Build.TAGS != null && android.os.Build.TAGS.contains("test-keys")){
            val.append("'test-keys' find in android.os.Build.TAGS");
            values.put("test-keys", val.toString());
        }
        return android.os.Build.TAGS != null && android.os.Build.TAGS.contains("test-keys");
    }
rw System Folders
Перейдем еще к одному способе детекта, который косвенно может сказать о том, что на девайсе больше прав, чем нужно, а именно то, что на системеые директории есть права на запись, которых быть не должно. Некоторые директории спорны, конечно, но никто не мешает модифицировать этот список.

Java:
    private boolean rwRules() {
        String[] lines = mountReader();
        if (lines == null) return false;

        for (String line : lines) {

            String[] args = line.split(" ");

            if (args.length < 4){
                continue;
            }
            String mountPoint = args[1];
            String mountOptions = args[3];

            List<String> path = Arrays.asList(
                    "/system",
                    "/system/bin",
                    "/system/sbin",
                    "/system/xbin",
                    "/vendor/bin",
                    "/sbin"
            );

            StringBuilder val = new StringBuilder();
            for(String pathToCheck: path) {
                if (mountPoint.equalsIgnoreCase(pathToCheck)) {
                    for (String option : mountOptions.split(",")){
                        if (option.equalsIgnoreCase("rw")){
                            val.append(pathToCheck);
                            values.put("rw System Folders", val.toString());
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }
Xposed or Cydia
И мой самый любимый способ я решил оставлить на последок! Если все предыдущее можно скрывать при наличии Xposed или Cydia, то вот скрыть их самих не совсем понятно как (понятно). Но перед тем, чтобы рассказать как можно скрыть наличие Xposed/Cydia (в другой статье), расскажу их можно задетектить практически со стопроцентной вероятностью.

Так как Xposed Framework вклинивается в работу zygote ( ), на котором строится вся работа системы, то достаточно посмотреть в... stackTrace любого процесса.
А давайте посмотрим есть ли su, какая разница что проверять -- stacktrace то пройдет по всей системе

Java:
    private boolean additionSystemRootFramework() {
        try {
            Runtime.getRuntime().exec("su");
        } catch (Exception ignored) {}
        String stackTrace = Log.getStackTraceString(new Throwable());
        StringBuilder val = new StringBuilder();
        if (stackTrace.contains("xposed")) val.append("xposed \n");
        if (stackTrace.contains("substrate")) val.append("substrate \n");
        if (!val.toString().isEmpty()) {
            val.append("finding in StackTrace");
            values.put("Xposed or Cydia", val.toString());
        }
        return stackTrace.contains("xposed") || stackTrace.contains("substrate");
    }
На этом оставновимся и если кому-то интересна эта тема, то в будущем расскажу о том, как "защититься" от такого рода проверок.

А пока могу посоветовать собрать из исходников приложение, которое было написано для того, чтобы проверять правильно ли мы обходили эти же проверки ;)
Приложение доступно по ссылке:
А если лень собирать и вы доверяете всему, что в интернете, то можете скачать сразу собранное приложение: (собирали для себя, так что там все чисто, но кто поверит же)
 
Последнее редактирование:
Vertigo

Vertigo

Lex mea est Vulgate Linux
Gold Team
15.02.2017
1 160
3 406
Необычная статья,зачёт и так держать.
 
Sunsobolev

Sunsobolev

Happy New Year
07.09.2019
4
1
Давно где то читал что как то вычисляют рут, статья что надо. Спасибо за статью
 
Мы в соцсетях: