«Взлом» приложения Spotify для Android, чтобы получить премиум-функции

Около 7 месяцев назад я хотел посмотреть, насколько сложно будет перепроектировать хорошо известное приложение для Android и найти какой-нибудь «крутой» эксплойт. Я заядлый пользователь Spotify, поэтому сказал: «Почему бы и нет?»

Первым делом нужно было получить .apk, чтобы с ним «поиграться». Есть много сайтов, где вы можете искать и скачивать .apks. Мало того, вы даже можете выбрать, какую версию .apk вы хотите (даже архитектуру). Я выбрал x86, так как решил, что эмулятор будет лучшим вариантом, чем настоящее устройство. Кроме того, это дало мне некоторое душевное спокойствие. Если выйдет модифицированная версия .apk, ее можно будет использовать только в эмуляторах (в дикой природе не так много Android-устройств x86).

После покупки .apk пришло время настроить инструменты. Раньше я пользовался apkStudio, но только в Linux. У меня было все настроено при установке OS X, поэтому мне пришлось скомпилировать apkStudio из исходного кода; это было интересно.

После того, как я запустил apkStudio, пришло время предварительно взглянуть на код. Также помогло установить JD-GUI, чтобы увидеть часть рекомпилированного кода Java; мои навыки чтения смали не так уж и хороши.

Поигравшись с приложением, я смог сказать, что приложение использует Dagger 2 вместо DI. Моя первоначальная мысль заключалась в том, чтобы попытаться внедрить премиальные зависимости вместо не премиум-зависимостей. Эта идея вроде как сработала. Мне удалось ввести премиум-компонент (IIRC, я думаю, это был RecyclerView.ViewHolder), который воспроизводил одну песню из плейлиста (премиум-функция), но когда вы пытались воспроизвести другую, это не сработало; приложение было умнее этого. Кроме того, проверка правильности внедрения всего графа при чтении обфусцированного кода определенно не является тривиальной задачей и требует много времени. Пришлось найти другой способ.

Я продолжил, добавляя операторы журнала для классов, которые мне показались интересными; здесь мне немного повезло, так как ProGuard не смог скрыть два особо важных класса. Я добавил операторы журнала, которые распечатали toString() метод этих классов (toString() распечатал состояние класса, мне снова повезло). Это выявило некоторые интересные вещи:

  1. Приложение обращается к файлу .so, который действует так, как если бы он был RESTful-сервером.
  2. Когда пользователь входит в систему, приложение обращается к библиотеке .so (точнее, sp: // product-state / v1 / values). Это возвращает тело в форме byte[]. В конце концов, этот byte[] представляет собой набор пар ключ / значение, в котором содержится информация об аккаунте.

Это был долгий путь, но попробовать стоило. Я решил изменить эти пары «ключ-значение», чтобы они соответствовали паре премиум-аккаунта (я знал, каковы были премиальные значения, так как у меня есть премиум-аккаунт). Здесь действительно пригодились Android Studio и плагин Smali Support. Это позволило мне написать код Kotlin, скомпилировать его в smali, скопировать этот код и внедрить его в код smali в приложении Spotify вместо написания чистого smali; Вначале я писал смали от руки. Здесь все стало немного сложнее, мне нужно было убедиться, что счетчик и выделение регистров хорошо сочетаются с существующим кодом; к счастью, это было не так уж сложно. Окончательный код smali выглядит примерно так: (Фактические пары имя и ключ / значение не являются настоящими значениями)

.method public final synthetic method(Ljava/lang/Object;)Ljava/lang/Object;
.locals 3

.line 23
check-cast p1, Lcom/spotify/magic/package/MagicClass;

invoke-direct {p0, p1}, Lict;->a(Lcom/spotify/magic/package/MagicClass;)Lcom/google/common/base/Optional;

move-result-object p1

invoke-direct {p1}, Lcom/google/common/base/Optional;->c()Ljava/lang/Object;

move-result-object v1

check-cast v1, Ljava/util/Map;

.line 23
new-instance v0, Ljava/util/HashMap;

invoke-direct {v0, v1}, Ljava/util/HashMap;-><init>(Ljava/util/Map;)V

.line 27
.local v0, "map":Ljava/util/HashMap;, "Ljava/util/HashMap<Ljava/lang/String;Ljava/lang/String;>;"
const-string v2, "magic-constant-one"

const-string p0, ""

invoke-virtual {v0, v2, p0}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

.line 28
const-string v2, "magic-constant-two"

const-string p0, ""

invoke-virtual {v0, v2, p0}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

.line 29
const-string v2, "magic-constant-three"

const-string p0, ""

invoke-virtual {v0, v2, p0}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

.line 30
const-string v2, "magic-constant-four"

const-string p0, ""

invoke-virtual {v0, v2, p0}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

return-object v0
.end method

Я перекомпилировал, установил, создал новую учетную запись и вуаля, ЭТО РАБОТАЛО!. Я смог выбрать, какие песни слушать из списка воспроизведения (т.е. я не получил макет режима случайного воспроизведения, который получают пользователи без премиум-класса). Я внес несколько других изменений в .apk, которые показали больше премиального интерфейса, но это было больше для эстетики, чем для чего-либо еще. Я не разблокировал все премиум-функции, но мне этого хватило.



Я пошел дальше и поискал программу вознаграждений Spotify; у них есть один через HackerOne. Я заполнил подробный отчет и… это был их ответ.

Похоже, у них есть программное обеспечение для мониторинга, которое определяет, используете ли вы модифицированную версию их приложения. Если они обнаружат вас, они могут отключить эту версию приложения и / или отключить учетную запись, которую вы используете, я бы не стал рисковать.

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

P.S. Мне сообщили, что есть способ получить премиум-функции для приложения Spotify с использованием модифицированного .apk. Цель этой статьи больше связана с техническим аспектом того, как это можно сделать, а не с предоставлением .apk для бесплатного использования премиум-функций.

[1] smali / baksmali - это ассемблер / дизассемблер для формата dex, используемого dalvik, реализацией виртуальной машины Java для Android.