Expertus metuit
Ломаем APK-пакеты
2012-02-26 21:32
Теги: android, linux

Обновлено 2015-09-17: исправлены ссылки на программы

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

Вот этим мы и займёмся. Традиционно здесь всё рассказывается в контексте линукса, с остальными операционками разбирайтесь сами, хотя принцип ровно такой же.

Предварительная подготовка

Нам понадобится телефон с андроидом, дата-кабель к нему, настроенный для работы с ADB компьютер1, установленный Android SDK (каталоги tools и platform-tools должны быть вынесены в переменную окружения PATH).

Также на телефоне необходимо разрешить отладку через USB.

Ещё необходимо добавить какой-нибудь каталог, в который вы можете писать, в переменную окружения $PATH, у меня туда добавлен каталог ~/bin.

Получение apk-файла приложения

Есть несколько способов добыть файл с пакетом приложения:

  • скачать с интернета, на всяких форумах часто выкладывают пакеты;
  • скачать с официально сайта приложения, такое тоже бывает, да;
  • вытащить из собственного телефона, куда приложение было установлено с маркета.

Первые два способа тривиальны, о них не будем рассказывать, а вот третий достоин внимания. Подключаем телефон кабелем к компьютеру, проверяем, что девайс видится командой adb:

% adb devices
List of devices attached 
3731276A498700EC        device

Допустим, нас интересует приложение Google+, очевидно, что где-то в названии приложения должно быть слово plus, ищем:

% adb shell pm list packages -f plus
package:/data/app/com.google.android.apps.plus-1.apk=com.google.android.apps.plus
package:/data/app/org.geometerplus.zlibrary.ui.android-1.apk=org.geometerplus.zlibrary.ui.android

Что мы только что сделали? Мы выполнили команду на стороне девайса (adb shell), команда называется pm (т.е. package manager), опция команды list packages говорит сама за себя, опция -f включает отображение связанных с пакетом файлов; а plus — это фильтр.

Видим, что интересующее нас приложение лежит в файле /data/app/com.google.android.apps.plus-1.apk, вытаскиваем его на компьютер:

% adb pull /data/app/com.google.android.apps.plus-1.apk .
3132 KB/s (8913253 bytes in 2.778s)

Разбор apk-файла на части

APK-файл фактически является обычным ZIP-архивом, внутри которого лежат скомпилированные исходники приложения, ресурсы и манифест. Вы можете в этом сами убедиться:

% unzip -l com.google.android.apps.plus-1.apk
Archive:  com.google.android.apps.plus-1.apk
  Length      Date    Time    Name
---------  ---------- -----   ----
    97360  2008-08-21 17:13   META-INF/MANIFEST.MF
    97402  2008-08-21 17:13   META-INF/CERT.SF
     1580  2008-08-21 17:13   META-INF/CERT.RSA
    39212  2008-08-21 17:13   AndroidManifest.xml
     3162  2008-08-21 17:13   assets/licenses.html
  5293140  2008-08-21 17:13   classes.dex
  7608988  2008-08-21 17:13   lib/armeabi/libgcomm_jni.so
... тут пропущено много строчек
  2493944  2008-08-21 17:13   resources.arsc
---------                     -------
 16786021                     1042 files

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

Для этого есть замечательный инструмент android-apktool, полная инструкция по установке описана на официальном сайте. Нас интересует версия 2.X, скачиваем jar-файл в каталог ~/bin, туда же скачиваем скрипт-обёртку, примерно так:

cd ~/bin/
wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.0.1.jar
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool
chmod +x apktool

Проверяем в терминале, что команда apktool работает, просто набираем и смотрим. Если выдаётся ошибка, фиксим, например, пермиссии на файл. Когда всё заработает, можно приступать к декодированию, всё просто:

% apktool d com.google.android.apps.plus-1.apk gplus
I: Baksmaling...
I: Loading resource table...
I: Loaded.
I: Loading resource table from file: /home/USER/apktool/framework/1.apk
I: Loaded.
I: Decoding file-resources...
I: Decoding values*/* XMLs...
I: Done.
I: Copying assets and libs...

После завершения процесса внутри каталога gplus будут лежать декодированные (в некоторой степени) внутренности пакета. К примеру, там уже можно смотреть в нормальном виде xml-файлы (макеты интерфейса или манифест). Там даже можно увидеть слегка декодированные исходники приложения, но не в виде java-кода, а в виде smali-файлов, об этом формате подробнее можно тут прочитать, при желании их можно даже редактировать и затем собрать назад в apk-пакет (это также можно сделать при помощи apktool).

Дизассемблирование до java-кода

Следующий шаг — попытаться добраться до близкого к оригинальному java-кода приложения. В этом нам поможет программа dex2jar, качаем с сайта проекта архив с программой (файл вида dex2jar-0.0.9.8.tar.gz), она тоже написана на java, внутри каталог с кучей файлов, из которых нам понадобится каталог lib (скопируем его целиком в ~/bin):

$ cp -r ./lib ~/bin/

и dex2jar.sh, скопируем его туда же в ~/bin. Запускаем на примере нашего пакета (на большом пакете программа может долго работать):

% dex2jar.sh com.google.android.apps.plus-1.apk
dex2jar version: translator-0.0.9.8
dex2jar com.google.android.apps.plus-1.apk -> com.google.android.apps.plus-1_dex2jar.jar
Done.

После выполнения получим в этом же каталоге jar-файл (в нашем случае — com.google.android.apps.plus-1_dex2jar.jar).

Это самый обычный java jar archive, содержащий обычные class-файлы со скомпилированным java-кодом.

Декомпиляция class-файлов в java-файлы

Финальный этап — это получение более-менее читабельного java-кода из class-файлов с байткодом. Эта задача частично решается программой из предыдущего раздела: скопируем в каталог ~/bin скрипт d2j-jar2jasmin.sh. Результатом работы скрипта является каталог с файлами в формате jasmin, что, однако, вовсе не java-код, но тоже может оказаться полезным для анализа:

% d2j-jar2jasmin.sh -o res com.google.android.apps.plus-1_dex2jar.jar
disassemble com.google.android.apps.plus-1_dex2jar.jar -> res 

Но можно получить и java-код! Для этого можно попробовать воспользоваться вот этим дизассемблером. Не факт, что сработает на вашем пакете, плюс не гарантируется извлечение компилируемого кода, но какие-то данные вы всё же получите.

Что осталось за кадром

Я не рассматриваю вопрос преобразования odex-файлов в dex-файлы. Об этом можно самому прочитать вот тут, например.

Аналогично вопрос обратной сборки файлов в apk-пакет тоже не рассматривается. Так же как и подписывание/выравнивание apk-пакета.

Ссылки


  1. особенности настройки линукс-машины для работы с телефоном по дата-кабелю раскрываются в соответствующей статье на сайте developer.android.com 

Комментарии

Алексей | 2012-04-14 в 01:37

Тут со своим кодом разобраться бы, а потом только за чужие файлы браться. Я что в ЯВЕ написал более двух месяцев назад, если код более 1000 строк уже с переводчиком должен смотреть.

Сергей | 2012-07-09 в 23:31

Да чё вы так всё усложнили?! Тут проще чем написать слово "молоко"! Просто поменяйте расширение "apk" в "rar". И всё!

P.S. Написано на Си.)

dafeuot | 2012-07-23 в 21:15

Читай статью повнимательней:

APK-файл фактически является обычным ZIP-архивом, внутри которого лежат скомпилированные исходники приложения, ресурсы и манифест.Однако просто распаковать и дальше ковыряться в этом всём, к сожалению, не получится: эти файлы там лежат в бинарном оптимизированном для использования на девайсе формате, их нужно сначала декодировать в пристойный вид.

Текст комментария (разметка: *курсив*, **полужирная**, [ссылка](http://example.com) или <http://example.com> ещё)
Имя (обязательно, 50 символов или меньше)
Email, на который получать ответы (не будет опубликован)
Веб-сайт
© 2006—2016 Sergey Stolyarov | Работает на Pyrone