Запустите службу с правами root или добавьте права с правами root - PullRequest
13 голосов
/ 03 февраля 2012

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

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

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

  • Простота реализации.
  • Однако это неэффективно от батареи
  • Также сообщения не считываются сразу.

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

  • Сложнее реализовать
  • Улучшение взаимодействия с пользователем

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

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

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

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

Можете ли вы помочь мне с этим?Благодарю.

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

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

Ответы [ 7 ]

3 голосов
/ 11 февраля 2012

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

Вам действительно нужно иметь root-доступ кустройство, как это нарушает систему безопасности 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 code .У меня нет опыта работы ни с NDK, ни с оболочкой C ++, но, возможно, стоит посмотреть, когда вы планируете написать это.

2 голосов
/ 07 февраля 2012

Принудительно, я должен сказать вам, что для Службы Android не требуется root-доступ , вместо этого для некоторых действий (например, Доступ, Чтение, Запись системных ресурсов) требуются Root-разрешения.Все службы Android, предоставляемые в Android SDK, могут быть запущены без ROOT ACCESS.

Вы можете выполнить действия с правами 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 ().

2 голосов
/ 06 февраля 2012

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

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

AccessibilityEvent

1 голос
/ 10 февраля 2012

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

Ты не можешь. Период. Конец истории. И спасибо Господу за это.

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

1 голос
/ 06 февраля 2012

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

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

0 голосов
/ 08 марта 2013

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

pm grant your.permission

в качестве команды оболочки для предоставления дополнительных разрешений вашему приложению.Я думаю, что команда была добавлена ​​совсем недавно, поэтому, если вы нацелены на более старые версии, вам, возможно, придется напрямую изменить «packages.xml».

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

0 голосов
/ 10 февраля 2012

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

Еще одна вещь, которую я могу вам сказать, это то, что вы не можете запустить 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, вы можете проверить наличие новых сообщений.Вы также можете посмотреть эту тему: Android SMS Provider , если вы еще этого не сделали.

...