Запуск службы с правами Root или добавление разрешений с правами root

в настоящее время я разрабатываю приложение, которое считывает SMS/электронные письма во время вождения. Многие пользователи пожелали поддержку WhatsApp / KakaoTalk.

однако, поскольку нет "официального" способа получения их сообщений, будет только три варианта, все требующие root:

более простой способ сканирования их базы данных в данном intervall.

  • легко реализовать.
  • однако не батарея эффективная
  • также сообщения не читаю немедленно.

другим способом было бы запустить службу с правами root и зарегистрировать приемник, который слушает их push-уведомления. Это должно быть сделано с root, так как оба пакета требуют разрешения на основе подписи для получения их push-уведомлений.

  • труднее реализовать
  • лучший пользовательский опыт

еще одна вещь пришла мне на ум: можно ли вручную добавить разрешения на APK после установки? В этом случае я мог бы добавить разрешения c2dm в свой пакет.

  • это очень легко
  • однако я немного боюсь изменения разрешений моего приложения, так как это полностью противоречит принципу песочницы Android.
  • тем не менее, если это будет возможно, дайте мне знать!

проблема в том, как ровно я запускаю службу с правами root (это действительно возможно)? я знаю, как для запуска команд оболочки или двоичных файлов с root, но я понятия не имею, как начать часть APK как root.

кроме того, можно ли интегрировать BroadcastReceiver в двоичный файл? У меня на самом деле нет опыта работы с C/C++, особенно в среде android.

вы можете мне помочь с этим? Спасибо.

edit: как я сказал в комментарии, я не хотите использовать AccesibilityService, так как он не соответствует моим потребностям (например, это даст me "2 непрочитанных сообщения" если более одного непрочитано, также оно не включает полное тело).

edit2: просто чтобы уточнить: я знаю, как запускать команды с root. Что мне нужно знать, так это как зарегистрировать Broadcastreceiver, который получает определенную трансляцию "нормальные" приемники не получают, так как сама трансляция требует разрешения на основе подписи, которого у меня нет.

7 ответов


Это далеко не тривиально, но должно работать, когда приложения, которые вы хотите контролировать, используют базы данных sqlite или, более общие, пишут сообщения в файл, когда они прибывают.

вам действительно нужно будет иметь корневой доступ к устройству, поскольку это нарушает систему безопасности android:

напишите собственный процесс, который работает как демон с NDK и порождает его один раз после загрузки как root. Теперь у вас есть 3 основные проблемы для решения:

как узнать, если что-то изменился?

Это легкая часть. Вам нужно будет использовать интерфейс linux inotify, который должен быть доступен на каждом телефоне android, поскольку SDK имеет FileObserver С API 1, Так вы не в безопасности здесь.

еще одна интересная вещь, может быть, чтобы поймать C2DM сообщения. Я нашел класс NDK, который называется BroadcastReceiver, так что NDK может быть в состоянии поймать их. Но я лично не стал бы этого делать, это чувствует неправильно красть намерения. Также вам придется перераспределить их или позволить им в режиме реального получателя, поэтому не буду описывать это подробно. Это может сработать, но это может быть сложнее и должно быть только резервным вариантом.

Итак, когда вы решили это, возникает следующая проблема:

как прочитать изменения в способе сохранения?

У вас есть проблема, большая, здесь. Файл не принадлежит вам, вы даже не имеете права знать, где он находится (обычно.) Таким образом, отслеживаемое приложение не знает о вас и будет действовать так, как файл принадлежит исключительно ему. Если они используют какой-то простой старый текстовый файл для написания сообщений, вы должны найти способ безопасно читать из него, поскольку он может быть перезаписан или расширен в любое время. Но вам может повезти, когда они используют sqlite, согласно этой совершенно справедливо иметь больше чем одного одновременного читателя, как раз только одного писателя. Мы в спецификации, все снова в порядке. Когда вы сейчас прочитаете новые данные, больше проблем для решения:

как получить новые данные обратно в основное приложение?

вы должны сделать только минимум в этой программе c / C++, потому что она работает как root. Вы также должны защитить пользователей приложения от нарушений безопасности, поэтому запрограммируйте демона с учетом этого. Я понятия не имею, что это может работать очень хорошо, но вот некоторые из них:

  • записать собранные данные в свою собственную базу данных SQLite (в c / C++ и java)
  • запишите собранные данные в простой файл (не рекомендуется вообще, боль в спине)
  • отправить намерение, которое содержит новые данные (возможно, не так просто в c/C++, но легко в java)
  • розетки/труб/..., просто каждый механизм rpc, который вы могли себе представить, который приходит к вам linux (так же, как файл, не делайте этого)

Как указано в тексте выше, пожалуйста, будьте осторожны при написании этого демона, поскольку это потенциальный угроза безопасности. Также это может быть трудно сделать, когда у вас нет знаний о c/C++ вообще, и даже когда вы написали простые программы, это должна быть нетривиальная задача.

в моем поиске через интернет я нашел эти классы NDK c++, о которых я упоминал выше. Его можно найти по адресу код google. У меня нет опыта работы с NDK или с оболочкой c++, но, возможно, стоит посмотреть, когда вы планируете это написать.


сила, я должен сказать вам, что сервис Android не требует корневого доступа вместо некоторых действий (например, доступ, чтение, запись системных ресурсов) требуются разрешения Root. Каждая служба Android, предоставляемая в Android SDK, может быть запущена без доступа ROOT.

вы можете выполнять действия с правами root с помощью команд оболочки.

Я создал абстрактный класс, чтобы помочь тебе с этим

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import android.util.Log;

public abstract class RootAccess {
    private static final String TAG = "RootAccess";
    protected abstract ArrayList<String> runCommandsWithRootAccess();

    //Check for Root Access
    public static boolean hasRootAccess() {
        boolean rootBoolean = false;
        Process suProcess;

        try {
            suProcess = Runtime.getRuntime().exec("su");

            DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
            DataInputStream is = new DataInputStream(suProcess.getInputStream());

            if (os != null && is != null) {
                // Getting current user's UID to check for Root Access
                os.writeBytes("id\n");
                os.flush();

                String outputSTR = is.readLine();
                boolean exitSu = false;
                if (outputSTR == null) {
                    rootBoolean = false;
                    exitSu = false;
                    Log.d(TAG, "Can't get Root Access or Root Access deneid by user");
                } else if (outputSTR.contains("uid=0")) {
                    //If is contains uid=0, It means Root Access is granted
                    rootBoolean = true;
                    exitSu = true;
                    Log.d(TAG, "Root Access Granted");
                } else {
                    rootBoolean = false;
                    exitSu = true;
                    Log.d(TAG, "Root Access Rejected: " + is.readLine());
                }

                if (exitSu) {
                    os.writeBytes("exit\n");
                    os.flush();
                }
            }
        } catch (Exception e) {
            rootBoolean = false;
            Log.d(TAG, "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
        }

        return rootBoolean;
    }

    //Execute commands with ROOT Permission
    public final boolean execute() {
        boolean rootBoolean = false;

        try {
            ArrayList<String> commands = runCommandsWithRootAccess();
            if ( commands != null && commands.size() > 0) {
                Process suProcess = Runtime.getRuntime().exec("su");

                DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());

                // Execute commands with ROOT Permission
                for (String currentCommand : commands) {
                    os.writeBytes(currentCommand + "\n");
                    os.flush();
                }

                os.writeBytes("exit\n");
                os.flush();

                try {
                    int suProcessRetval = suProcess.waitFor();
                    if ( suProcessRetval != 255) {
                        // Root Access granted
                        rootBoolean = true;
                    } else {
                        // Root Access denied
                        rootBoolean = false;
                    }
                } catch (Exception ex) {
                    Log.e(TAG, "Error executing Root Action", ex);

                }
            }
        } catch (IOException ex) {
            Log.w(TAG, "Can't get Root Access", ex);
        } catch (SecurityException ex) {
            Log.w(TAG, "Can't get Root Access", ex);
        } catch (Exception ex) {
            Log.w(TAG, "Error executing operation", ex);
        }

        return rootBoolean;
    }


}

расширить класс с помощью RootAccess или создайте экземпляр класса RootAccess и переопределите метод runCommandsWithRootAccess ().


запуск чего-то как root является не правильный способ решения этой проблемы.

вместо этого рассмотрим службу доступности, которая может следить за новыми уведомлениями:

AccessibilityEvent


невозможно запустить службу (или любой другой компонент приложения) в качестве root, если вы нацелены на неизмененные, некорневые устройства. Разрешение этого сделало бы все механизмы безопасности в Android бессмысленными.

также невозможно изменить разрешения APK во время выполнения. Разрешения всегда предоставляются или отклоняются во время установки APK. Пожалуйста, обратитесь кhttp://developer.android.com/guide/topics/security/security.html для некоторых больше информация по этому вопросу.


" Что мне нужно знать, так это как зарегистрировать Broadcastreceiver, который получает определенную трансляцию "нормальные" приемники не получают, так как сама трансляция требует разрешения на основе подписи, которого у меня нет."

ты не можешь. Точка. Конец истории. И спасибо ghod за это.

да, если вы используете страшные корневые устройства, чтобы иметь некоторый код, выполняемый как root, вы можете теоретически делать все, что хотите. На практике, это может быть довольно трудно обойти это ограничение, и платформа часто спроектирована таким образом. Вам, по крайней мере, нужно будет возиться с состоянием, поддерживаемым и/или сохраняемым менеджером пакетов, и, вероятно, потребуется заставить пользователя перезагрузить устройство, чтобы получить изменения, которые вы делаете как root, чтобы фактически повлиять. И, конечно же, вы тогда возитесь с глубоко внутренними деталями реализации Платформы, что означает разбиение повсюду в разных версиях платформы и разных сборках из разных мировые производители.


можно использовать

pm grant your.permission

как команда оболочки для предоставления дополнительных разрешений вашему приложению. Я думаю, что эта команда была добавлена совсем недавно, поэтому, если вы нацелены на более старые версии, вам может потребоваться непосредственно изменить пакеты.формате XML'.

можно выполнить файл app/dex как root с помощью команды app_process, но я еще не понял, как получить допустимый контекст (с этим вы можете использовать java.Ио.Файл api для доступа ко всем файлам, но не статические методы android, такие как bindService и т. д. не удастся, потому что вы работаете без контекста приложения).


конечно, вы можете изменить разрешения для приложений. Если разрешения будут изменены, пользователю просто нужно будет вручную обновить приложение, и новое разрешение будет отображаться пользователю. Но я точно не знаю, как изменение вашего разрешения приложения поможет вам в решении этой проблемы.

еще одна вещь, которую я могу вам сказать, это то, что вы не можете запустить Service или как root, только на корневых устройствах, и это не будет легкой задачей, чтобы искоренить устройства через ваше приложение, а также это не будет то, что многие пользователи захотят.

как вы в настоящее время доступ к SMS? Если у вас есть BroadcastReceiverвы можете установить MAX_PRIORITY для receiver и, возможно, он будет перехватывать сообщения перед другими приложениями. Это можно сделать следующим образом:

   <receiver android:name=".SmsReceiver" >
        <intent-filter android:priority="100" >
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>

вы также можете использовать SMS Provider, который сейчас не является общедоступным, но, возможно, если вы запросите с заданным интервалом это Provider вы можете проверить наличие новых сообщений. Ты мог бы ... также посмотрите на эту тему:поставщик SMS Android если вы еще не сделали этого все готово.