Пишем троян под Андроид

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

В классической Java есть класс под названием java.lang.ClassLoader. Его задача — загружать байт-код указанного класса (файл с расширением .class) в виртуальную машину во время исполнения приложения. Затем можно создать объект этого класса и вызывать его методы с помощью рефлексии. Такой вот способ динамической загрузки кода, который можно использовать для написания приложений с расширяемой функциональностью, или, попросту говоря, поддержкой плагинов.

В Android нет виртуальной машины Java и нет класса ClassLoader, но есть его аналог DexClassLoader, выполняющий ровно ту же функцию, но в отношении байт-кода Dalvik (и файлов .dex вместо .class соответственно). И, в отличие от настольной Java, где проще положить нужный jar-файл в CLASSPATH и не возиться с динамической загрузкой, в Android такой подход дает действительно много преимуществ, главное из которых в том, что функциональность приложения можно расширять и обновлять незаметно для пользователя и ни о чем его не спрашивая. В любой момент твое приложение может скачать файл с классом с сервера, загрузить, а затем удалить файл.

[ad name=»Responbl»]

Кроме этого, классы можно хранить прямо в пакете APK и загружать во время старта приложения. Профит здесь в том, что код загружаемых классов будет отделен от кода самого приложения и находиться в APK «не по адресу»; инструменты типа apktool, которыми так любят пользоваться реверсеры, их просто не увидят. С другой стороны, это скорее защита от дурака, так как нормальный реверсер быстро смекнет, что к чему.

Как бы там ни было, динамическая загрузка классов — очень полезная штука при написании не совсем «белых» приложений, поэтому любой security-специалист должен знать, как этот механизм работает и как он используется в троянах.

ПРОСТЕЙШИЙ ПРИМЕР

Чтобы все написанное далее было проще понять, сразу приведу пример рабочего загрузчика классов: Screen Shot 2016-07-12 at 15.13.10

В целом здесь все просто: код загружает jar-архив /sdcard/myapp/module. jar с нашим классом, загружает из него класс com.example.modules.simple. Module, создает объект и вызывает метод run(). Обрати внимание на три момента:

  • DexClassLoader умеет загружать как «просто» файлы .dex, так и jar-архивы, последние предпочтительнее из-за сжатия и возможности использовать цифровую подпись;
  • второй аргумент конструктора DexClassLoader — это каталог, который он использует для сохранения оптимизированного байт-кода (odex), для простоты мы указываем приватный каталог самого приложения;
  • в качестве аргумента метода loadClass всегда необходимо указывать адрес класса вместе с именем пакета.

Чтобы проверить данный код на работоспособность, создадим простейший модуль:
Не торопись создавать новый проект в Android Studio, можешь накидать этот код в блокноте и собрать его в jar-архив прямо из командной строки:

javac -classpath /путь/до/SDK/platforms/android-23/android.jar
    Module.java
/путь/до/SDK/build-tools/23.0.3/dx --dex --output=module.jar
    Module.class

Удостоверься, что каталоги platforms/android-23 и build-tools/23.0.3 существуют, в твоем случае их имена могут отличаться.

[ad name=»Responbl»]

Если все пройдет гладко, на выходе ты получишь файл module.jar. Останется только добавить код загрузчика в приложение, положить module.jar на карту памяти, собрать и запустить приложение.

ДОЛОЙ РЕФЛЕКСИЮ

Рефлексия — хорошая штука, но в данном случае она только мешает. Один метод без аргументов с ее помощью вызвать нетрудно, однако, если мы хотим, чтобы наше приложение имело развитый API модулей с множеством методов, принимающих несколько параметров, нужно придумать что-то более удобное. Например, использовать заранее определенный интерфейс, который будет реализовывать каждый модуль.

Применив такой подход к приведенному выше примеру, мы получим следующие три файла:

Файл ModuleInterface.java с описанием API:

2. Файл Module.java с реализацией нашего модуля:

3.Новый загрузчик модуля (помести в свое приложение):

Это все. Теперь мы можем работать с модулем, как с обычным объектом. Более того, система сама отбракует модули (классы), несовместимые с интерфейсом, еще на этапе загрузки, поэтому нам не придется задаваться вопросами, а есть ли в модуле нужный нам метод.

КОГДА МОДУЛЕЙ МНОГО

С одним модулем разобрались, но что, если их будет много? Как вести учет этих модулей и не потеряться среди них? На самом деле все просто — для этого можно использовать hashmap. Еще раз изменим загрузчик: Данный код загружает все jar-файлы из указанного каталога, загружает их классы Module, создает на их основе объекты и помещает их в хешмап modules. Обрати внимание на трюк, использованный при загрузке класса и размещении объекта в хешмапе. Он нужен для простоты: вместо того чтобы выяснять принадлежность каждого модуля/класса к пакету, мы просто условились, что имя jar-файла модуля будет соотноситься с именем пакета по схеме com.example.modules.ИМЯ_JAR_ФАЙЛА, так что мы сразу знаем полный адрес класса каждого модуля.

[ad name=»Responbl»]

Например, приведенный ранее модуль принадлежит пакету com.example. modules.simple (см. директиву package), поэтому его необходимо включить в jar-архив simple.jar (меняем —output=module.jar на —output=simple. jar в команде сборки). Когда придет время создать новый модуль (к примеру, remote_shell), первой строчкой в его исходниках ты укажешь package com. example.modules.remote_shell.Module; и запакуешь скомпилированный байт-код в jar-архив remote_shell.jar.

Имя jar-файла (без расширения) используется также в качестве ключа в хешмапе, поэтому, зная имя модуля, всегда можно запустить его методы:

БЕРЕМ МОДУЛИ С СОБОЙ

На данном этапе у нас уже есть приложение, способное загружать неограниченное количество модулей из указанного каталога и с удобством работать с ними. Осталось разобраться с тем, как распространять эти модули. Самый очевидный вариант — загружать их с сервера, пусть наш «троян» делает это раз в день, а после скачивания модулей запускает загрузчик модулей, чтобы подгрузить их в приложение. Рассказывать, как сделать это, я не буду, здесь все элементарно, и решение этой задачи ты найдешь в любой вводной статье или книге про разработку для Android.

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

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


Все очень просто. Код находит модули внутри пакета и поочередно копирует их в каталог /sdcard/myapp, из которого затем их можно будет подгрузить с помощью загрузчика.

ВЫВОДЫ

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

Click to rate this post!
[Total: 26 Average: 3.3]

Специалист в области кибер-безопасности. Работал в ведущих компаниях занимающихся защитой и аналитикой компьютерных угроз. Цель данного блога - простым языком рассказать о сложных моментах защиты IT инфраструктур и сетей.

1 comments On Пишем троян под Андроид

Leave a reply:

Your email address will not be published.