Как создать резервную копию Android-приложения
Любое приложение для Android можно скопировать себе на компьютер. Это удобно для создания резервных копий особо ценных приложений. А то вдруг разработчик по какой-то причине решит удалить свое творение из Play Store. Также это позволяет изучить внутреннее устройство закрытого приложения, или даже модифицировать его.
Поскольку на ноутбуке у меня Linux, то описанные шаги будут для этой системы. Вероятно, для Windows и MacOS шаги будут похожи. Но так ли это на самом деле, я не проверял.
Понадобятся следующие пакеты:
$ sudo apt install adb apksigner
Они тянут за собой довольно тяжелую JRE. Однако постоянно держать в системе названные пакеты не требуется. Можно установить, воспользоваться, и сразу удалить.
Утилита ADB, Android Debug Bridge, предназначена для управления Android-устройством с компьютера. Она позволяет устанавливать приложения, копировать файлы, отлаживать код и т.п. Чтобы это работало, устройство необходимо перевести в режим разработчика.
Для этого заходим в Settings → About phone. Проматываем в самый низ и 7 раз нажимаем на Build Number. Должно появиться сообщение об активации режима разработчика. Возвращаемся на предыдущий экран. Идем в System → Advanced → Developer options → Debugging. Ставим галочку напротив USB debugging.
Подключаем смартфон / планшет к компьютеру по USB. Определяем полное имя интересующего нас приложения. Для этого в консоли говорим:
$ adb shell pm list packages | grep -i superproga
package:me.eax.superproga
Определяем соответствующие ему apk-файлы:
$ adb shell pm path me.eax.superproga
package:/data/app/(...много букв...)/base.apk
package:/data/app/(...много букв...)/split_config.arm64_v8a.apk
package:/data/app/(...много букв...)/split_config.en.apk
package:/data/app/(...много букв...)/split_config.ru.apk
package:/data/app/(...много букв...)/split_config.xxhdpi.apk
В данном случае приложение разбито на несколько файлов. Копируем их на ноутбук:
$ adb pull /data/app/(...много букв...)/base.apk .
$ adb pull /data/app/(...много букв...)/split_config.arm64_v8a.apk .
$ adb pull /data/app/(...много букв...)/split_config.en.apk .
$ adb pull /data/app/(...много букв...)/split_config.ru.apk .
$ adb pull /data/app/(...много букв...)/split_config.xxhdpi.apk .
Удаляем приложение. Затем проверяем, что оно устанавливается из бэкапа:
$ adb install-multiple base.apk split_config.arm64_v8a.apk ⏎
split_config.en.apk split_config.ru.apk split_config.xxhdpi.apk
Для удобства склеим полученные файлы в один монолитный apk:
$ mkdir me.eax.superproga
$ mv *.apk me.eax.superproga
$ java -jar APKEditor.jar m -i ./me.eax.superproga -o superproga.apk
Здесь использована программа APKEditor. Помимо нее существует схожая по функционалу apktool. Однако apktool не работает со split-пакетами, а также имеет другие недостатки.
Склеенному пакету требуется новая цифровая подпись. Android не против самоподписанных сертификатов. Только при установке система предупредит, что перед вами приложение от неизвестного разработчика.
Создаем приватный ключ и самоподписанный сертификат со сроком годности 10 000 дней:
$ openssl genrsa -out eaxme_key.pem 2048
$ openssl req -new -key eaxme_key.pem -out eaxme_csr.csr
$ openssl x509 -req -days 10000 -in eaxme_csr.csr -signkey eaxme_key.pem ⏎
-out eaxme_cert.x509.pem
Конвертируем ключ в формат PKCS#8, который понятен Android'у:
$ openssl pkcs8 -topk8 -outform DER -in eaxme_key.pem -inform PEM ⏎
-out eaxme_key.pk8 -nocrypt
Подписываем пакет:
$ apksigner sign --key eaxme_key.pk8 --cert eaxme_cert.x509.pem superproga.apk
Удаляем приложение на смарфтоне и говорим:
$ adb install superproga.apk
Теперь у нас есть резервная копия приложения в виде монолитного apk. Кстати, для его установки не обязательно использовать ADB. Можно перекинуть apk при помощи условного Google Drive, и просто открыть файл на Android-устройстве.
Обратите внимание, что при установке приложения из Play Store устройство получает сплиты под конкретные модель процессора, DPI и язык системы. Чтобы собрать все сплиты и получить самый переносимый apk, необходимо больше одного устройства.
А что, если приложение еще доступно в Play Store, но мы не хотим обновляться? Ведь иногда после обновления софт начинает работать хуже. Пусть такое и случается не всегда, но бывает.
Модифицируем приложение соответствующим образом. Для этого его нужно распаковать:
java -jar APKEditor.jar d -i superproga.apk -o superproga
Помимо прочего, в каталоге superproga будет создано множество файлов с расширением .smali. Это текстовые файлы с ассемблерным листингом соответствующих классов. С ними можно работать в вашем любимом текстовом редакторе и при желании вносить изменения.
Однако сейчас нас интересует superproga/AndroidManifest.xml:
<?xml version='1.0' encoding='utf-8' ?>
<manifest android:versionCode="123"
android:versionName="1.2.3"
android:compileSdkVersion="36"
android:compileSdkVersionCodename="16"
package="me.eax.superproga"
platformBuildVersionCode="36"
(... пропущено ...)
Здесь versionName – это версия приложения, показываемая пользователю, а versionCode – внутренний номер версии для Play Store. Чтобы приложение перестало обновляться, нужно указать большое значение versionCode:
<?xml version='1.0' encoding='utf-8' ?>
<manifest android:versionCode="999999"
android:versionName="1.2.3-backup"
android:compileSdkVersion="36"
android:compileSdkVersionCodename="16"
package="me.eax.superproga"
platformBuildVersionCode="36"
(... пропущено ...)
Запаковываем и снова подписываем:
$ mv superproga.apk /tmp
$ java -jar APKEditor.jar b -i superproga -o superproga.apk
$ apksigner sign --key eaxme_key.pk8 --cert eaxme_cert.x509.pem superproga.apk
Еще раз переустанавливаем. Приложение должно работать как раньше, но теперь иметь версию 1.2.3-backup. Если что-нибудь сломалось (не должно, но мало ли), то смотрим логи:
$ adb logcat *:E | grep -i me.eax.superproga
Для более глубокого изучения JVM-кода существует декомпилятор JADX, а для файлов .so – уже знакомые нам Radare2 и Cutter.
Примечательно, что на самом деле apk-файлы представляют собой zip-архивы. Однако эти архивы имют ряд особенностей. Например, файлы .so хранятся несжатыми и выровненными по размеру страницы, а AndroidManifest.xml имеет бинарный формат. Поэтому для работы с .apk следует использовать специальные утилиты.