Эта статья — оригинальная, а не копипаст и не машинный перевод. При копировании прошу ссылаться…
В этой статье я позволю себе немного отклониться от темы, непосредственно касающейся Smali. Сегодня немного о том, откуда приходит Smali и куда возвращается. Поговорим о разборке и сборке файлов APK.
Статья предназначена для людей, которые знают основы разработки приложений под OS Android. Кто считает себя "речным котиком" и "морским мурзиком" в вопросе разборки-сборки APK, может спокойно пропустить эту статью мимо глаз.
1. Декомпиляция APK
На сегодняшний день лично я знаю только один заслуживающий внимания инструмент для декомпиляции файлов APK – утилита apktool (https://apktool.org/). Установка для различных ОС достаточно полно описана здесь: https://apktool.org/docs/install.
Два основных сценария декомпиляции:
полная: apktool d base.apk декомпилирует и код и ресурсы
без ресурсов: apktool d -r base.apk декомпилирует только код. Применяется когда нет необходимости внесения изменений в ресурсы. Это немного экономит время на сборке и иногда избавляет от ошибок, связанных с ресурсами.
Однако, следует помнить, что если вы хотите вносить изменения в файл AndroidManifest.xml, то нужна полная декомпиляция.
В результате декомпиляции вы получаете рабочую папку примерно с такой внутренней структурой:
Не буду подробно описывать структуру папок, эта тема достаточно полно освещена в сети Internet. Нас же, как людей занимающихся анализом поведения приложений Android больше других интересуют следующие папки и файлы:
-
папки smali,smali_classesX – здесь лежит собственно сам код приложения и библиотек, которые были собраны вместе с приложением в нашем любимом формате – Smali. Да-да, мы можем изменять код не только непосредственно исследуемого приложения, но и код сторонних библиотек, скомпилированных вместе с ним.
Ориентироваться в этих папках не так уж легко. Например, наше приложение имеет следующуий Application ID (или package name): com.example.myapp. Файлы MainActivity и App лежат в корне, то есть путь до этих файлов такой: com/example/myapp/MainActivity и com/example/myapp/App. Тогда, по логике вещей, они должны бы оказаться в одной папке smali. Однако, в реальности эти файлы могут быть разнесены по разным папкам, и иметь разные пути, например:
smali/com/example/myapp/MainActivity и smali_classes2/com/example/myapp/App. файл AndroidManifest.xml – тут все понятно. Это основы Android.
файл apktool.yml – описывает правила сборки для apktool. Вернемся к нему чуть позже.
папка res – здесь лежат собственно ресурсы приложения. Если нужно поменять картинку, строки – это сюда.
папка lib – здесь лежат native libraries для различных архитектур процессоров (arm и x86). По содержимому этой папки можно сразу сказать на какой архитектуре будет работать это приложение, а на какой – нет.
Это может быть важно для вас, если вы работаете с файлами на эмуляторе. Знаю только один эмулятор, который умеет эмулировать архитектуру ARM из коробки, без танцев с бубном - Bluestacks для OS Windows. Поскольку я работаю в основном с OS Linux, то предпочитаю Genymotion.
Хочу так же отметить, что в сети Internet существует несколько крупных ресурсов, где можно скачать уже готовый файл APK под необходимую архитектуру (если такой существует). Пример такого ресурса: https://www.apkmirror.com/. Однако, лично я предпочитаю в первую очередь брать оригинальные файлы непосредственно с устройства. Иногда приходится поднимать старые версии приложения, тогда без таких ресурсов как APKMirror, конечно не обойтись.
1.2. Разделенные (Splitted) APK
Очень мешающая жить исследователям APK тема. Для пользователей удобно, когда на телефон загружаются не все языки мира и native libraries для всех архитектур, а только те, которые необходимы для работы приложения на данном устройстве. Просто меньше места занимается.
Если мы подключимся к устройству с помощью утилиты adb(https://developer.android.com/tools/adb) и посмотрим какие же APK установлены для определенного app ID, то можем увидеть следующую картину:
$ adb shell pm path com.av.android
package:/data/app/~~_iQAN8GT6jLoegcIOOACvA==/com.av.android-cUt8845xwv6Bf9mRQKj5qg==/base.apk
package:/data/app/~~_iQAN8GT6jLoegcIOOACvA==/com.av.android-cUt8845xwv6Bf9mRQKj5qg==/split_config.x86_64.apk
package:/data/app/~~_iQAN8GT6jLoegcIOOACvA==/com.av.android-cUt8845xwv6Bf9mRQKj5qg==/split_config.xxhdpi.apk
Здесь мы видим, что на девайс загружено три файла APK:
основной base.apk – в нем все, что не зависит от локали и архитектуры – по сути вся математика.
файл split_config.x86.apk хоть и называется APK, но по сути содержит на борту лишь native libraries (папку /lib) для архитектуры x86_64.
файл split_config.xxhdpi.apk содержит ресурсы для соответствующего разрешения экрана.
Нужно вытянуть с устройства все эти три файла следующим образом:
$ sudo adb pull /data/app/~~_iQAN8GT6jLoegcIOOACvA==/com.av.android-cUt8845xwv6Bf9mRQKj5qg==/base.apk
/data/app/~~_iQAN8GT6jLoegcIOOACvA==/com.av.android-cUt8...e.apk: 1 file pulled. 156.5 MB/s (65727493 bytes in 0.400s)
Повторить для каждого файла APK.
В результате в вашей текущей папке появятся три выше упомянутых APK файла.
Ну и что же с этим делать? Нам то нужен один APK.
Для начала, попробуйте установить и запустить base.apk на вашем эмуляторе или устройстве. В некоторых случаях вас ждет успех. Это значит, что конфигурации, содержащейся в base.apk достаточно для работы на вашем устройстве. Но, более вероятно то, что APK не установится, выдав ошибку, что не хватает дополнительных файлов.
Ну что же. Давайте дадим вашему устройству то, чего оно хочет.
1.3 Инструкция по объединению Splitted APK в один файл APK
декомпилируйте каждый из файлов APK командой apktool d xx.apk В результате этого у вас должны появиться три (для нашего случая) папки с развернутыми в них файлами APK.
скопируйте содержимое папок (у вас могут быть другие) \split_config.x86 и \split_config.xxhdpi в папку \base БЕЗ ЗАМЕНЫ. То есть вы дополните папку \base отсутствующими в ней файлами из остальных двух папок.
Откройте в папке \base файл AndroidManifest.xml и удалите все, что касается split. Прямо ищите поиском по файлу.
откройте в папке \base файл apktool.yml. Далее открывая такие же файлы (apktool.yml) в других папках, копируйте из них содержимое раздела "doNotCompress:" в такой же раздел файла из папки \base если этого содержимого там еще нет. Как бы и все).
Теперь нас интересует только папка \base. Все остальное можно перенести в папку backup чтобы не мешалось, но пока не удаляйте – успеете еще удалить.
Пробуем собрать файл APK из папки \base:
apktool b base
В 90% случаев все проходит удачно. Бывают накладки с ресурсами.
Тогда попробуйте для начала сделать так:
apktool b –use-aapt2 base
Иногда помогает. Хотите подробностей – ищите в Internet.
Часто бывает, что сыпятся сообщения об ошибках в ресурсах файлов plurals.xml. В этом случае, просто удалите такие файлы из всех папок \values, а также ссылки на plurals из файла \values\public.xml.
В результате всех этих действий вы должны получить из исходников в папке \base файл base.apk, который заработает на вашем устройстве.
Все! Теперь сделайте backup папки \base с оригинальным кодом, и можете приступать к исследованиям).
2. Сборка APK
Наверное вы уже проверили на собственном опыте и знаете, что недостаточно просто собрать файл APK утилитой apktool. Для того, чтобы файл установился и успешно запустился нужно выполнить еще две процедуры:
выравнивание содержимого файла (aligning)
подпись файла (sign).
Зачем это нужно – читайте в Internet из первоисточников. Скажу лишь, что для этих целей прекрасно подходят утилиты zipalign и apksign. Для подписания файла необходимо будет так же создать ключ подписи. Прцесс создания Keystore и Key подробно описан в Internet.
Почему я не даю конкретные ссылки, на материал – потому что не хочу вам указывать. Кто захочет – тот разберется, кто не захочет – ну и ладно.
3. Немного полезные ссылки
Здесь и в следующих статьях, при необходимости буду ссылаться на свои репозитории в GitHub.
Сегодня дам две ссылки:
По использованию – читайте здесь.
4. Заключение
На сегодня – все. Нет ничего лучше практики. Просто установите несколько приложений, вытяните их из гаджета, разберите и соберите. Да так, чтобы они снова запустились.
Не легкий это путь. Только спокойный и упрямый человек может его пройти. И тогда - Veni, Vidi, Vici. Именно так).
P.S.
Я за чистоту Русского Языка, и терпеть не могу, когда иностранные слова используют в кириллице, типа «кейс» или «сниппет» и вставляют их в устную речь, даже когда общаются с широкой и разнородной аудиторией, искажая Великий и Могучий. Считаю это признаком недалекости ума (Личное мнение автора статьи).