Реверс-инжиниринг позволяет не только разобраться в существующих приложениях, но и модифицировать их. В этом смысле приложения на Андроид — клад для начинающего реверсера. Сегодня мы разберем несколько приложений, чтобы потренироваться в реверс-инжиниринге и узнать о подлинных возможностях вашего смартфона.
Какое приложение мы будем реверсить? Я выбрал для этой статьи VK Admin — приложение для управления сообществами «ВКонтакте» со смартфона. В нем к сожалению не предусмотрен ночной режим, поэтому мы с вами путем реверса попробуем это дело исправить.
Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция сайта tech-geek.ru, ни автор не несут ответственности за любой возможный вред, причиненный изложенным материалом.
Собираем и разбираем
Сначала извлечем все ресурсы приложения, используя утилиту apktool — она распаковывает и запаковывает файлы пакетов APK, которые хранятся в сжатом, бинарном виде, и дизассемблирует программный код, заключенный в них.
Чтобы получить установочный пакет, можно воспользоваться Android Debugging Bridge — системой для отладки программ на устройстве. В *nix-подобных системах ADB ставится стандартно, с помощью пакетного менеджера, а в Windows — идет в составе Android Studio или Android SDK Platform Tools.
В первую очередь установим приложение из Google Play Store на смартфон, подключим его к компьютеру с помощью USB, затем воспользуемся ADB для переноса пакета приложения на компьютер и извлечем его содержимое.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ adb shell pm path com.vk.admin package:/data/app/com.vk.admin-Ka5KVtTbnGgxoRqnObb-pQ==/base.apk $ adb pull /data/app/com.vk.admin-Ka5KVtTbnGgxoRqnObb-pQ==/base.apk com.vk.admin.apk 3881 KB/s (13414132 bytes in 3.374s) $ apktool d com.vk.admin.apk I: Using Apktool 2.4.0 on base.apk I: Loading resource table… I: Decoding AndroidManifest.xml with resources… I: Regular manifest package… I: Decoding file-resources… I: Decoding values / XMLs… I: Baksmaling classes.dex… I: Copying assets and libs… I: Copying unknown files… I: Copying original files… |
После этого мы получим папку com.vk.admin/, внутри которой хранится все содержимое исходного .apk, только в декодированном виде. Чтобы применить изменения, необходимо будет снова воспользоваться рядом утилит.
- Сначала соберите приложение обратно в пакет .apk.
1 2 3 4 5 6 7 8 |
$ apktool b com.vk.admin/ I: Using Apktool 2.4.0 I: Checking whether resources has changed… I: Checking whether sources has changed… I: Smaling classes folder into classes.dex… I: Building apk file… I: Copying unknown files/dir… I: Built apk… |
- Затем необходимо подписать приложение. Это нужно, чтобы и Google Play Store, и устройство не обновляли приложение, если подписи не совпадают. Поэтому не забудьте удалить приложение с телефона, прежде чем установить свое, подписанное своим ключом.
Для создания подписи в первый раз нужно воспользоваться утилитой keytool (входит в Java Development Kit):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ keytool -genkey -keyalg RSA -alias xakep -keystore ks.keystore -validity 10000 -keysize 2048 Enter keystore password: Re-enter new password: What is your first and last name? [Unknown]: Xakep User What is the two-letter country code for this unit? [Unknown]: RU Is CN=Xakep User, C=RU correct? [no]: yes Enter key password for (RETURN if same as keystore password): Re-enter new password: |
- Когда вы уже создали ключ, подпишите приложение.
1 2 3 |
$ jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore ks.keystore com.vk.admin.apk xakep Enter Passphrase for keystore: jar signed. |
- После этого установите приложение на смартфон.
1 2 3 |
$ adb install com.vk.admin.apk 3881 KB/s (13414132 bytes in 3.374s) Success |
РЕКОМЕНДУЕМ:
Взлом приложений для Андроид с помощью отладчика
Меняем цветовые схемы
Цвета в приложении можно настроить несколькими способами:
- использовать встроенные цвета, к примеру @android:color/white;
- создать палитру собственных цветов в файле colors.xml, которые затем используются в виде @color/text_primary;
- задать цвет шестнадцатеричным кодом, главное — не забудьте, что цвета в приложении записаны в формате #AARRGGBB — прозрачность на первом месте;
- воспользоваться параметрами setTextColor, setBackgroundColor внутри кода Java или Kotlin.
Все эти способы жизнеспособны и постоянно используются.
colors.xml
Цветовая палитра приложения содержится в файле com.vk.admin/res/values/colors.xml. Структура файла выглядит так:
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="abc_input_method_navigation_guard">@android:color/black</color> <color name="background_chat">#ffebf0f4</color> <color name="background_material_light">@android:color/white</color> ... <color name="material_grey_100">#fff5f5f5</color> <color name="white">#ffffffff</color> </resources> |
Каждый цвет, который в дальнейшем используется в статичных экранах приложения, записан здесь. Наша цель — изменить цвета, самый простой способ это сделать — инвертировать. Для записи цвета в формате hex можно отнять из 255 каждый компонент: R, Gи B, то есть 255 - R, 255 - G, 255 - B. Параметры @android:color/white и @android:color/black можно изменить вручную.
styles.xml
В файле com.vk.admin/res/values/styles.xml заданы цвета, но только некоторые. Этот файл используется самими разработчиками, когда они хотят сделать несколько цветовых схем приложения. Если же этих схем нет, работать приходится нам с вами.
Некоторые цвета текста и фона заданы именно здесь, поэтому их нужно изменить аналогично с colors.xml.
Layout
В папке com.vk.admin/res/ находятся описания экранов приложения.
- com.vk.admin/res/layout/ — универсальное хранилище экранов для всех смартфонов. Если нет каких-то специальных указаний, то будут использованы эти ресурсы;
- com.vk.admin/res/layout-v``XX (где XX — версия SDK смартфона, зависит от версии Android на устройстве) используются для работы с самыми передовыми элементами UI;
- остальные com.vk.admin/res/layout-... задают специфичные экраны приложения для ориентации устройства, разрешения и так далее.
Некоторые цвета приложения, чаще всего задний фон, можно найти здесь и изменить.
Но закончить мы пока не можем — есть некоторые экраны, цвет фона и текста которых задан не в файлах .xml, а прямо в исполняемом коде приложения. Туда нам и дорога.
Smali
Внутри приложений на Android используется собственный формат файлов — .dex, или Dalvik EXecutable, и собственная виртуальная машина, чтобы эти файлы исполнять, — Dalvik.
Как и с любым компилируемым языком, для .dex есть байт-код — smali — человекочитаемый и понятный с первого взгляда.
Машина Dalvik, в отличие от JVM, — регистровая, а не стековая. Регистры не имеют типов и могут хранить всё: числа, строки, экземпляры классов. При этом язык smali строго типизирован.
Вот небольшая последовательность инструкций, чтобы вывести содержимое регистра v0 в лог.
- const-string v1, "MyTag" — записать в регистр v1 строку "MyTag".
- invoke-static {v0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String; — вызвать функцию String.valueOf(v0). Здесь static означает, что функция встроена в виртуальную машину; {v0} — список аргументов; L показывает, что сразу за ним идет название объекта, класса и так далее; java, lang, String; — тип строки; I — тип числа, Integer; а все вместе ( ->valueOf(I)Ljava/lang/String;) говорит нам о том, что вызывается функция valueOf от одного аргумента и возвращает она строку.
- move-result-object v2 — записать результат предыдущей операции в v2.
- invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I — залогировать содержимое v2 под тегом из v1.
Если не удается понять, что значит тот или иной регистр или что делает та или иная функция, используйте декомпилятор smali в Java — Jadx.
Использовать Jadx просто — нужно лишь выбрать файл и открыть его, код будет автоматически декомпилирован и показан.
Рекомендую ознакомиться с документацией по байт-коду Dalvik VM.
setBackgroundColor
Для некоторых экранов приложения используется параметр setBackgroundColor(I)V, который устанавливает цвет фона. Часто это не статичные экраны, а динамические: с поддержкой скролла, различные списки и карточки.
1 |
invoke-virtual {v1, v0}, Landroid/webkit/WebView;->setBackgroundColor(I)V |
Эта строка занимается изменением. Чтобы изменить цвет, нужно его записать в регистр, а затем передать в функцию вместо настоящего.
1 2 3 4 |
const v12, -0x1000000 #### Эквивалент 0xFF000000 — черного invoke-virtual {v1, v12}, Landroid/webkit/WebView;->setBackgroundColor(I)V |
Теперь пройдитесь по всем файлам и замените цвет.
Бывают случаи на порядок проще.
1 2 3 4 |
const v2, -0x1 #### Здесь -0x1 == 0xFFFFFFFF — белый цвет invoke-virtual {v1, v2}, Landroid/support/v7/widget/CardView;->setBackgroundColor(I)V |
Нужно просто изменить -0x1 на -0x1000000, и приложение погрузится во тьму.
Стоит быть внимательным и пытаться разобраться в коде: иногда оптимизатор кода будет перемещать инструкции const вверх, и вы можете их не заметить.
setTextColor
Иногда текст, который меняется в ходе работы с приложением, может менять свой цвет. За это отвечает параметр setTextColor(I)V, второй аргумент которого можно подменить на нужный, в нашем случае — белый.
1 2 3 4 5 |
#### Меняем цвет const p1, -0x1 #### на белый invoke-virtual {v0, p1}, Landroid/widget/TextView;->setTextColor(I)V |
На этом борьбу со светлым фоном и ярким экраном можно закончить. Большинство элементов экрана поменяли свой цвет на противоположный. Так вы можете изменить любое приложение, особенно если вы любите использовать телефон поздно ночью.
Меняем функциональность приложения
Чтобы ощутить всю мощь smali, давайте попробуем изменить какую-то часть приложения. Например, обойдем проверку на внутренние покупки.
Возьмем другое приложение — ISS Detector. Оно показывает положение МКС над Землей. В нем можно купить расширения: показ комет, планет, Луны, телескопа «Хаббл».
При копировании приложения на компьютер может возникнуть проблема: в составе приложения не один и не два, а целых три файла apk!
1 2 3 4 |
$ adb shell pm path com.runar.issdetector package:/data/app/com.runar.issdetector-dtgy8_hlf1y-cekrg1_W-A==/base.apk package:/data/app/com.runar.issdetector-dtgy8_hlf1y-cekrg1_W-A==/split_config.en.apk package:/data/app/com.runar.issdetector-dtgy8_hlf1y-cekrg1_W-A==/split_config.xxhdpi.apk |
Копируем все. При переустановке приложения файлы split_config.en.apk и split_config.xxhdpi.apk потеряются, а без них приложение будет вылетать. Поэтому их нужно будет переподписать: зайти в них как в архивы ZIP, удалить папку META_INF и прогнать через стандартную процедуру утилиты jarsigner. Основной же файл мы будем препарировать с помощью apktool.
РЕКОМНДУЕМ:
Инструменты Android-разработчика
Покупками в приложении занимается интерфейс IInAppBillingService. Для него прописана обертка com.runar.issdetector.util: IabHelper, IabResult, Purchase, Security, Inventory.
В этом приложении можно не идти напролом, обманывая сервис покупок. Проще заставить приложение думать, что все уже куплено. В этом нам поможет Inventory.smali.
В особо сложных случаях такой трюк провернуть не удается, и тогда приходится подменять данные, заставляя сервис ложно сообщать о совершенных покупках. Подробнее об этом можно почитать в материале компании Securing Apps (PDF).
Открыв файл, вы увидите поле mPurchaseMap<String; Purchase>, которое содержит в себе все покупки: номер товара, сопоставленный с покупкой, которую совершил пользователь.
1 2 3 4 5 6 7 8 9 10 |
.field mPurchaseMap:Ljava/util/Map; .annotation system Ldalvik/annotation/Signature; value = { "Ljava/util/Map<", "Ljava/lang/String;", "Lcom/runar/issdetector/util/Purchase;", ">;" } .end annotation .end field |
Далее в коде мы видим строку hasPurchase(String sku) -> boolean, которая проверяет, совершал ли пользователь покупку. Для этого делается проверка на существование ключа sku в mPurchaseMap.
1 2 3 4 5 6 7 8 9 10 11 12 |
.method public hasPurchase(Ljava/lang/String;)Z .locals 1 .line 45 iget-object v0, p0, Lcom/runar/issdetector/util/Inventory;->mPurchaseMap:Ljava/util/Map; invoke-interface {v0, p1}, Ljava/util/Map;->containsKey(Ljava/lang/Object;)Z move-result p1 return p1 .end method |
А что будет, если в любом случае отдавать true?
1 2 3 4 5 6 7 |
.method public hasPurchase(Ljava/lang/String;)Z .locals 1 const p1, 0x1 return p1 .end method |
Собираем приложение и устанавливаем его.
1 2 |
$ adb install-multiplie com.runar.issdetector.apk split_config.xxhdpi.apk split_config.en.apk Success |
С этого можно начать свой путь в реверс-инжиниринг. Я рассказал вам основы реверса Андроид приложений, с которых начинал сам. Небольшие изменения могут улучшить вашу жизнь — надеюсь, я смог вам это показать.