Реверс-инжиниринг android приложений
В этой статье я постараюсь рассказать про реверс-инжиниринг приложений для android. Этот процесс несколько отличается от оного для win-приложений: здесь нет отладчика и нет ассемблера, вместо них выступают LogCat и байт-код. Как вы уже догадались, мы будем исследовать приложение с целью его взлома, или, проще говоря, «крякать».
БРИФИНГ
В качестве подопытного кролика я выбрал программу «Multi Mount SD-Card». Ее суть заключается в монтировании flash-накопителя девайса с одновременным доступом к нему системы и пользователя. Дело в том, что по умолчанию android не имеет доступа к смонтированному в данный момент накопителю. Для пользователей Eclair это не так критично, но вот пользователи Froyo+ писают кипятком не радуются, когда установленные на карту программы вылетают при ее монтировании. Собственно для решения этой проблемы была и написана эта программа. Ах да, программе нужны root права.
Для начала нам нужен дистрибутив программы, чтобы было что ломать. Но где же его взять? Ведь для этого надо ее купить. Ну, или выпросить у уже купившего человека. Таким человеком стал creage с форума 4pda, который любезно расшарил купленный apk.
Итак, у нас есть дистрибутив, мы уже установили программу, запускаем… И тут бац! Видим окошко с предложением купить лицензию. Отсюда вытекает, что проверка идет через интернет, пробуем отключить — не помогает. Покупателю приложения не дают никаких ключей и логинов, что говорит нам о привязке к чему-то вроде hardware_id или google-аккаунта. Следовательно у нас есть несколько вариантов взлома: либо захардкодить в программу заведомо правильную проверяемую информацию, либо вырезать из кода все участки, проверяющие валидность лицензии. Я выбрал второй вариант, ибо он мне больше нравится.
Инструментарий
Введение
Прежде чем приступать, я немного объясню структуру android приложений. Каждое приложение есть файл с расширением apk, упакованный zip’ом. В нем содержатся ресурсы приложения, AndroidManifest.xml и classes.dex. Что же из себя представляет последний? Это байт-код программы, скомпилированный специально для виртуальной машины dalvik. Получить из него чистый исходный код на java нельзя, но можно получить dalvik opcodes — набор команд для виртуально машины, грубо говоря, это местный ассемблер. А еще можно превратить dex файл в jar, после чего декомпилировать его и получить более-менее читаемый код на java. Чем мы и будем сейчас заниматься.
Декомпиляция
Начало анализа
Что же это? Как подсказывает гугл, эта строчка намекает на то, что в приложении используется LVL, то есть менеджер лицензий android. Ну что ж, это даже хорошо, ведь у нас есть документация. Почитав которую, пожно понять, что этот LVL не только управляет лицензиями, но и подвергает код обфускации, что существенно усложнит нам работу.
Ну да ладно, приступим непосредственно к анализу кода. Переключаемся на jd-gui, разворачиваем дерево, и видим три пространства имен: первое — что-то связано с рекламой, второе — набор классов LVL, третье — то, что нам надо.
Заходим в него и видим последствия обфускации. Открываем MultiMountSDCardConfigure, бегло просматриваем код. В глаза сразу бросается длинная строчка с каким-то хэшем. Это base64 public key. А вокруг него находятся и остальные строчки, проверяющие лицензию. Их нам необходимо выпилить.
Открываем apk_manager\projects\multimount.apk\smali\com\rafoid\multimountsdcard\widget\MultiMountSDCardConfigure.smali и видим байт-код. Прежде чем читать дальше, советую сначала просмотреть список команд. Нам необходимо найти те самые строчки и закоментить их. Вот они:
Закоменчиваем, сохраняем. Вроде как, все, можно пользоваться. Осталось только скомпилить и установить.
Компиляция и установка
Опять анализ
Запускаем и радуемся, что сэкономили целых 30 рублей на покупке этой полезнейшей программы.
Примечания
Процесс описан целиком для Windows, но легко может быть повторен и на Linux, так как все необходимые библиотеки кроссплатформенны.
Уже после написания статьи я наткнулся на на вот этот способ взлома, но, насколько я понимаю, он актуален для ранних версий LVL.
Вся информация представлена исключительно в ознакомительных целях. А так же для разработчиков, с целью улучшения программной защиты.
Формат файла DEX

JAMIE LYNCH
January 4, 2018
Оригинал:
https://www.bugsnag.com/blog/dex-and-d8
Задумывались ли вы, что происходит с кодом приложения Android, когда тот компилируется и упаковывается в APK? В этой статье подробно рассматривается формат исполняемого файла Dalvik с практическим примером структуры простейшего файла Dex.
Что такое файл DEX?
Файл Dex содержит код для исполнения в виртуальной машине Android Runtime. Каждый APK имеет отдельный файл classes.dex, который ссылается на все классы или методы, используемые в приложении. По сути, любая активность, объект или фрагмент, используемые в вашем коде, будут преобразованы в байты, в файл Dex, который можно запустить как приложение Android.
Будет очень полезно понять структуру Dex файла. Например, ссылки могут занимать слишком много места. Использование многих сторонних библиотек может увеличить размер APK на мегабайты или, что еще хуже, привести к печально известному ограничению размера метода в 64 КБ. И, конечно, может наступить день, когда знание стуктуры Dex поможет отследить неожиданное поведение в вашем приложении.
Поскольку большинство мобильных устройств имеют жёсткие ограничения по объему памяти, вычислительной мощности и времени автономной работы, ART предлагает производительность превосходящую JVM. Одна из ключевых особенностей, которая помогает достичь этого, заключается в том, что ART выполняет компиляцию как до исполнения, так и во время исполнения. Это позволяет избежать среде исполнения некоторых накладных расходов JIT, но при этом с течением времени позволяет повысить производительность при профилировании приложения.
Как создать файл Dex
Практика на примере файла Dex делает понимание намного проще. Давайте создадим минимальный APK, который содержит только один класс Application, поскольку это позволит нам понять формат файла, не перегруженный тысячами методов, присутствующих в типичном приложении.
Мы будем использовать Hexfiend для просмотра файла Dex в шестнадцатеричном формате, поскольку Dex использует некоторые необычные типы данных для экономии места. Мы скрыли все нулевые байты, поэтому пустые места на приведенном выше снимке экрана фактически представляют 00.
Структура файла Dex
Полная структура нашего 480-байтового файла Dex показана в шестнадцатеричном и UTF-8 ниже. Некоторые секции мгновенно распознаются при интерпретации как UTF-8, например, один класс BugsnagApp, который мы определили в исходном коде, а других секций не так много:
Исследование андроид-вируса
Всем привет. Недавно мне valdikss рассказал об андроид-вирусе, который может немало навредить пользователю, если он недостаточно внимателен. Мне захотелось узнать его внутренности, т.к. более или менее в последнее время занимаюсь ресерчем андроид приложений, но вирусы никогда еще не исследовал. До его рассмотрения, мне сразу бросилось в глаза название файла — android_update-1.apk. Первым делом делаю то, что делает каждый андроид ресерчер — распаковывает его dex2jar-ом (ну и параллельно можно посмотреть WinRAR-ом список файлов).
dex2jar
Когда я распаковал файл dex2jar-ом у меня получился красивый jar. Я обрадовался и кинулся смотреть его в JD-GUI.
Но, к сожалению, JD-GUI не смог полностью декомпильнуть получившийся файл, зато в самом конце файла были интересные строки.
Тут 2 варианта: либо вирус «китайского происхождения», либо ошибка кодировки. Думаю, пока рано делать выводы.
WinRAR
Как известно, APK — формат архивных исполняемых файлов-приложений для Android. Список файлов, которые входят в APK-архив, можно с легкостью просмотреть WinRAR-ом, что я и сделал.
На первый взгляд ничего особенного, но я знаю, что в папке assets разработчики хранят локальные файлы — html страницы, картинки, ну, в общем, локальные ресурсы, которые можно дергать из приложения.
Там я нашел файл classes.dex. Classes.dex — контейнер который, если мы распакуем, получим (если повезет) исходный код приложения под Android. По стандарту, файл classes.dex должен начинаться следующими байтами:
Что в ASCII — dex.035.
Но файл assets\classes.dex начинался так:
Явно зашифровано. Уже начинает проявляться логика работы зловреда. Когда мы скачиваем на смартфон и запускаем apk, он устанавливается, дергает из своих ресурсов файл classes.dex, расшифровывает, (по логике) получает какой то новый аpk, который и выполняет свою основную функцию.
Чтобы полностью понять как все работает, надо посмотреть действие зловреда в динамике. На реальном устройстве запускать — самоубийство. В качестве эмулятора я взял Genymotion, его преимущества как эмулятора описывать не буду, все здесь написано. Также, вместе с Genymotion, я использую Android Studio (в дальнейшем AS) 1.2 (нет слов, чтобы описать его слаженную работу). Когда мы запускаем Android Studio и Genymotion, они связываются с помощью adb. В Android Studio удобно смотреть лог работы приложения, в данном случае зловреда.
Установка apk привела к странной ошибке:
Если мы попытаемся удалить его из администраторов (нажав на checkbox, он отмечен красным), то вылезет окно:
После нажатия на кнопку деактивации нас ждет сюрприз — приложение невозможно удалить.
Окейййй. Посмотрим сетевой трафик, вдруг он что-то куда-то шлет. В эмуляторе, на WiFi соединение, поставим прокси и перезагрузим эмулятор. Так я и думал — есть и сетевая активность
тело в POST-запросе пустое.
Откроем logcat в AS и посмотрим, вдруг это приложение что-то записывает в логах. Нам везет:
Вот что получается — зловред берет из ресурсов файл assets/classes.dex, расшифровывает, записывает в /data/data/com.adobe.jaguar/app_dex/new.apk.
Так. Чтобы теперь узнать, каков его основной фунционал, нам надо поймать файл new.apk. Устанавливаем total commander на андроид и переходим в /data/data/com.adobe.jaguar/app_dex/. Папка оказалось пустой, после запуска new.apk файл удаляется. Возник вопрос: как получить его? Сначала подумывал, не написать ли мне приложение под андроид, которое в цикле следит за папкой /data/data/com.adobe.jaguar/app_dex/ и когда зловред снова создаст этот файл, мое приложение скопирует его, и я наконец узнаю что, оно делает на самом деле. Хорошо, что я в некоторых вопросах ленивый. Немного подумав, решил поэкспериментировать над правами папки /data/data/com.adobe.jaguar/app_dex/, и тут тоже повезло — он создал файл new.apk и упал.
Копируем new.apk из андроид, распаковываем dex2jar-ом и декомпилируем с помощью JD-GUI.
Опять иероглифы… Я решил открыть получившийся файл luyten-ом, мало ли, вдруг JD-GUI не может что-то правильно декомпильнуть.
.
Да, я был прав, это не иероглифы, а зашифрованный текст, нашел функцию которая занимается расшифровкой, но из всего apk только этот класс был обфусцирован, luyten тоже упал на нем. Есть еще один декомпилер — DJ Java Decompiler, у него туго с графикой, поэтому я его использую только для просмотра отдельных классов, а не всего проекта. Он, как бы, смог декомпильнуть, но, к сожалению, я не смог понять, как именно идет расшифровка.
Класс который отвечает за расшифровку (буду рад если взгляните на код, с первого взгляда AES, но не факт):
Нам уже из сетевой активности известно, что по сети передаются POST-запросы, так что этот код отправит POST-запрос:
В некоторых участках кода я увидел функции, в именах которых есть слово из 4-х букв — «bank».
Теперь у нас есть полная картина, этот зловред — банковский троян, который маскируется под андроид апдейт для Adobe Flash Player. После установки создает сервисы com.adobe.jaguar:jaguar_bf и com.adobe.jaguar:jaguar_obs. Сканируют файловую систему (в теле new.apk нашел код) на предмет установленных программ банк-клиентов, если находит их, то читает файлы из папки shared_prefs и отправляет злоумышленнику.
Мораль:
1. Не устанавливайте root и банк-клиент на одном устройстве
2. Не доверяйте приложениям, скачанными из сторонних магазинов
Как устроен билд APK файла внутри
Процесс создания APK и компиляции кода
Рассматриваемые темы
Архитектура процессоров и зачем нужна виртуальная машина
Андроид после того как вышел в 2007 году претерпел множество изменений связанный с билд процессом, средой исполнения и улучшениями производительности.
У андроида много удивительных характеристик и одна из них разные архитектуры процессоров такие как ARM64 и x86
Невозможно скомпилировать код, который поддерживает каждую архитектуру. Вот именно поэтому используется Java виртуальная машина.
Понимание Java виртуальной машины
JVM это виртуальная машина, позволяющая устройству запускать код, который скомпилирован в Java байткод
Используя JVM, вы избавляетесь от проблемы с разной архитектурой процессоров.
JVM предоставляет переносимость и она позволяет запускать Java код в виртуальной среде, вместо того, чтобы запускать его сразу «на железе»
Но JVM была создана для систем с большими мощностями по ресурсам, а наш андроид имеет сравнительно мало памяти и заряда батареи.
По этой причине Google создал адаптированную под андроид виртуальную машину, которая называется Dalvik.
Компилируем исходный код
Для котлина есть kotlinc компилятор, который делает совместимый с Java байткод.
Байткод — это набор инструкций, который выполняется на целевом устройстве.
Java байткод — это набор инструкций для Java виртуальной машины.
Андроид виртуальная машина
Каждое андроид приложение работает на своей виртуальной машине. С версий 1.0 до 4.4, это был Dalvik. В андроид 4.4, вместе с Dalvik, Google представил в качестве эксперимента новый андроид runtime, который назывался ART
Но у андроида есть свой собственный оптимизированный формат байткода, который называется Dalvik bytecode — это просто инструкции машинного кода для процессора также как и JVM байткод.
Dex — это аббревиатура с английского — Dalvik Executable.
ART против Dalvik
Преимущество ART над Dalvik проявляется в том, что приложения запускаются быстрее, потому что весь DEX байткод транслируется в машинный код во время установки, не нужно дополнительного времени на компиляцию в рантайме.
ART и Dalvik совместимы, так что приложения разработанные для Dalvik должны работать и на ART.
Компиляция Dalvik (JIT- just in time) имела такие минусы как — быстрая трата батареи, лаги в приложениях и плохой перформанс. В Dalvik трансляция происходит только когда это нужно. Мы открываем новый экран и только в этот момент происходит трансляция, за счет этого установка происходит быстрее, но при этом проседает перформанс.
Это причина по которой Google сделал Android Runtime (ART).
ART — основан на AOT (ahead of time) компиляции, она происходит до того как приложение запустится.
В ART компиляция происходит во время установки приложения. Это ведет к более долгому времени установки, но уменьшает трату батареи и избавляет от лагов, которые были на Dalvik.
В андроид 7.0 JIT вернулся. Гибридная среда сочетает фичи как от JIT компиляции так и
от ART
Среда запуска байткода это очень важная часть андроида и она вовлечена в процесс запуска и установки приложения
Каждый этап описанного процесса
Source Code (Исходный код)
Это Java и Kotlin файлы в src пакете.
Resource Files
Файлы находящиеся в директории с ресурсами
AIDL Files
AIDL — аббревиатура Android Interface Definition Language, позволяет вам описать интерфейс межпроцессорного взаимодействия.
AIDL — может использоваться между любыми процессами в андроиде.
Library Modules
Модули библиотек содержат Java или Kotlin классы, компоненты андроида и ресурсы.
Код и ресурсы бибилотеки компилируются и пакуются вместе с приложением.
Поэтому модуль библиотеки может считаться компайл тайм артефактом.
AAR Libraries
Андроид библиотеки компилируются в AAR — android archive файл, который вы можете использовать как зависимость для вашего android app модуля.
AAR файлы могут содержать андроид ресурсы и файл манифеста, что позволяет вам упаковать туда общие ресурсы такие как layouts и drawables в дополнение к Java или Kotlin классам и методам.
JAR Libraries
JAR это Java библиотека и в отличие от AAR она не может содержать андроид ресурсы и манифесты.
Android Asset Packaging Tool
AAPT2 — аббревиатура (Android Asset Packaging Tool) — компилирует манифест и файлы ресурсов в один APK.
Этот процесс разделен на два шага компиляцию и линковку Это улучшает производительность так как если вы поменяете один файл, вам нужно компилировать только его и прилинковать к остальным файлам командой ‘link’
AAPT2 может компилировать все типы андроид ресурсов, таких как drawables и XML файлы.
При вызове AAPT2 для компиляции, туда передается по одному ресурсному файлу на каждый вызов
resources.arsc
APK содержит AndroidManifest, бинарные XML файлы и resources.arsc
resource.arsc содержит всю мета информацию о ресурсах, такую как индексы всех ресурсов в пакете
Это бинарный файл и APK который может быть запущен. APK который вы обычно создаете и запускаете не сжат и может быть использован просто посредством размещения в памяти.
R.java файл это выходной файл вместе с APK ему назначен уникальный id, который позволяет Java коду использовать ресурсы во время компиляции.
arsc это индекс ресурса который используется во время запуска приложения
D8 и R8
Начиная с андроид студии 3.1 и далее, D8 был сделан дефолтным компилятором.
D8 производит более маленькие dex файлы с лучшей производительностью, если сравнивать со старым dx.
R8 используется для компиляции кода. R8 это оптимизированная версия D8
D8 играет роль конвертера класс файлов в Dex файлы, а также производит дешугаринг функций из Java 8 в байткод, который может быть запущен на андроиде
R8 оптимизирует dex байткод. Он предоставляет такие фичи как оптимизация, обфускация, удаление ненужных классов.
Обфускация уменьшает размер вашего приложения укорачивая названия классов, методов и полей.
Обфускация имеет и другие преимущества для предотвращения реверс инжиниринга, но основная цель уменьшить размер.
Оптимизация уменьшает размер Dex файла путем переписывания ненужных частей кода и инлайнинга.
С помощью дешугаринга мы можем использовать удобные фичи языка Java 8 на андроиде.
Dex and Multidex
R8 дает на выходе один DEX файл, который называется classes.dex
Если количество методов приложения переваливает за 65,536, включая подключенные библиотеки, то произойдет ошибка при билде
Компиляция и сборка Android приложения (как это работает)
Дисклеймер: Я не 23 летний сеньор (мне 19 и до сеньора мне еще ой как далеко, года 4, поэтому супер статьи от меня не ждите.
Основа пути моего, разработчика как — обучение/изучение нового постоянное. Надеюсь, у вас тоже.
В общих чертах процесс сборки приложения выглядит так:
Нас особенно интересует второй этап (компиляция и сборка ресурсов), так что, рассмотрим его более подробно (21 этап как никак):
Пожалуйста, не прокручивайте диаграмму из-за того, что вам лень вникать, она не сложная, к тому же переведенная. Это основа статьи.
(Оригинал здесь: developer.android.com/tools/building/index.html)
Что есть что на диаграмме:
1. Ресурсы приложения — это все xml ресурсы из папки res вашего проекта + некомпилируемые бинарные ресурсы, например, картинки из res/drawable или файлы из /res/raw, а так же файлы из /assets/
2. aapt — утилита, которая ищет в вашем проекте компилируемые ресурсы, такие как AndroidManifest.xml и xml файлы из res/ и компилирует их в бинарное представление, а изначально бинарные ресурсы, такие как картинки, и файлы из /res/raw и /assets не компилируются. Далее, эта утилита генерирует важнейший класс R.java для вашего приложения, благодаря которому вы можете обращаться к ресурсам из вашего кода без всяких заморочек с чтением файлов, как скажем с /assets.
Кстати, кроме компиляции xml ресурсов, aapt создает файл resources.arsc, который представляет собой таблицу для маппинга ресурсов во время выполнения приложение, туда входят все ресурсы из /res/, в том числе и /res/raw/, содержимое /assets не включается в таблицу.
Полезно знать: Утилита aapt находится в папке platform-tools вашего Android SDK. Если вам захотелось сделать реверс-инжиниринг скомпилированных ресурсов приложения, вы можете воспользоваться apk-tool (https://code.google.com/p/android-apktool/)
3. R.java — класс, генерируемый утилитой aapt для того, чтобы вы могли обращаться к ресурсам из папки res без явной работы с файловой системой через библиотеки ввода/вывода.
Если кто-то еще не знал — всякие R.string, R.menu и прочее — это статические вложенные классы, а в R.string.app_name, app_name — public static final int поле класса. Получается, что правило-принцип CamelCase, применяемый в Java, для них нарушен, должно то быть: R.String, R.Menu, а с константами — R.String.APP_NAME, айайай Google.
5. Java интерфейсы — это не те, обычные интерфейсы (обычные входят в состав исходного кода приложения, предыдущий пункт), которые вы используете в вашем коде, это интерфейсы, сгенерированные утилитой aidl (следующий пункт содержит пояснение).
8. Java компилятор — (наконец-то мы до него добрались!) это обычный javac из вашего JDK, которому дают на обработку исходный код приложения (4), R.java (3) и интерфейсы aidl, которые переведены в java код с помощью утилиты aidl
Разработчики Android выбрали регистровую архитектуру Dalvik VM, вместо привычной для JVM — стековой архитектуры из двух ключевых соображений:
1. Производительность регистровой ВМ выше (инфа 100%), особенно на процессорах с RISC-архитектурой, а это все ARM процессоры. Первые версии Dalviik VM даже не включали JIT (до Android 2.2), но давали терпимую производительность приложений, скажем я не испытывал особых проблем с HTC Desire на 2.1.
2. java bytecode транслируется в меньший по объему dex bytecode, что уменьшает размер скомпилированного приложения.
Сам компилятор находится в папке platform-tools вашего Android SDK, запускать его можно через dx.bat (для Windows), при этом будет задействован dx.jar из папки platform-tools/lib
12. classes.dex — в данный файл dex компилятор записывает весь исполняемый код вашего проекта.
13. Скомпилированные ресурсы — xml ресурсы приложения, скомпилированные в бинарное представление.
Пример содержания CERT.SF:
Signature-Version: 1.0
SHA1-Digest-Manifest-Main-Attributes: O1qITQssq6nv0FUt+eR1aLnqk5w=
Created-By: 1.6.0_43 (Apple Inc.)
SHA1-Digest-Manifest: OwzyFA/Qjd+5X1ZwaJQSxFgdciU=
Name: res/drawable-mdpi-v4/ic_premium_pin.png
SHA1-Digest: 8ksQB8osCHTnMlpL6Ho/GDc719Q=
Name: res/drawable/round_bottom_white.xml
SHA1-Digest: rQelve4dQmwCfkVlYZ2+9j5aW5w=
Кроме того, если у вас есть выложенное приложение в Google Play, вы не сможете обновить его, если новая версия подписана другим сертификатом! Так что советую забекапить сертификат, а так же не забыть пароль к нему. Иначе вы не сможете обновлять свои приложения.
Важное замечание: приложение надо сначала подписать, а затем применить zipalign, т.к. подпись — это добавление папки META-INF в архив, а это изменение архива, следовательно нарушение его оптимизации. То есть, если вы сначала примените zipalign, а потом измените архив — смысла в zipalign не будет. Насчет нарушения контрольных сумм, которые рассчитала утилита jarsign, бояться не стоит, т.к. zipalign делает оптимизации по выравниванию данных в архиве, все это происходит на уровне zip, сами данные не изменяются.
Хозяйке на заметку: во время сборки debug версии проекта zipalign не вызывается, скорее всего, чтобы вы не ждали выполнения еще и этой операции (спасибо и на этом).
Я думаю, что теперь понятно, почему сборка и запуск Android приложения происходит так долго 🙂 Так что, советую поставить SSD, ну и процессор побыстрее и сэкономить себе нервы и время.
Немного полезного оффтопа:
2. Вы знали, что Android инстанциирует для каждого запущенного приложения отдельный экземпляр Dalvik VM? Это сделано для того, чтобы исключить ситуации, когда одно приложение валит Dalvik VM, а за ним тянет все другие запущенные приложения. Яркий пример подобного вмешательства — Facebook, они через reflection изменяют параметры Dalvik VM (не стоит так делать). Если бы Android использовал один инстанс Dalvik — это изменение затронуло бы все запущенные приложения.
3. Dalvik VM не является JVM, т.к. во-первых он не понимает java bytecode, а во-вторых не реализует спецификации для JVM, т.к. использует свой байт код. Так что, советую называть Dalvik VM именно Dalvik VM.
Надеюсь, вы не зря потратили свое время и узнали что-то новое.





