• XSS.stack #1 – первый литературный журнал от юзеров форума

Внедрение кода в Android приложения от Amazon. Отвязываем приложения от Amazon App Store

tabac

CPU register
Пользователь
Регистрация
30.09.2018
Сообщения
1 610
Решения
1
Реакции
3 332
Читая stackoverflow, узнал о существовании Amazon Appstore App for Android и о том, что Amazon инжектит в каждое приложение свой код. Мне стало интересно, зашел на сайт

appstore_main_page.png


Просят зайти с девайса по ссылке

store_main_page.png


Amazon Appstore требует авторизации, приложения скачанные с одного аккаунта, не будут работать на другом. Это и есть DRM защита, которую можно и не использовать, убрав галочку при публикации. Еще мы видим, что амазон переподписывает все апк своим ключом, так как инжектится дополнительный код.

drm.png


Интересно, что именно и как инжектит код амазон. О том, как именно он это делает, можно понять из документации к публикации приложений. Здесь говориться, что если у вас в приложении почти 65К методов, то засабмитить неполучится. Это говорит о том, что амазон инжектит код в ваши классы и добавляет свои, а не использует метод с добавление своего dex файла.

64K_methods.png


Главное окно приложения

appstore_look.png


Appstore содержит довольно много платных приложений. Вместе с DRM'ом, все приложения скачанные через этот appstore не работают без него. Давайте проверим это, скачаем рандомное приложение

es_explorer.png


Откроем стартовый Activity приложения ES Explorer под названием com.estrongs.android.pop.app.openscreenad.NewSplashActivity. Имя берем из манифеста. В методе OnCreate():
Код:
/* access modifiers changed from: protected */
    public void onCreate(Bundle bundle) {
        Kiwi.onCreate((Activity) this, true);
        boolean z = false;
        this.f8682k = false;
        setContentView((int) R.layout.activity_splash_view);
        super.onCreate(bundle);
        this.f8681j = getIntent().getStringExtra("key_from");
        if (!C3729h.m15797c(this)) {
            z = true;
        }
        this.f8683l = z;
    }
Самая первая строка была добавлена амазоном, вызывается onCreate() у какого-то Kiwi и передается вторым параметром true. Открываем Kiwi
Код:
public static void onCreate(Activity activity, boolean z) {
        long currentTimeMillis = System.currentTimeMillis();
        if (!isInitialized()) {
            INSTANCE = new Kiwi(activity.getApplication(), z);
        }
        if (preProcess("onCreate", activity)) {
            INSTANCE.contextManager.onCreate(activity);
        }
        if (KiwiLogger.TRACE_ON) {
            LOGGER.trace("Kiwi.ActivityOnCreate Time: " + (System.currentTimeMillis() - currentTimeMillis));
        }
    }
Вызов конструктора, который принимает Application
Код:
INSTANCE = new Kiwi(activity.getApplication(), z);
Здесь видно, что второй параметр отвечает за DRM, в предыдущем коде мы видели, что передавалось true, значит это приложение поддерживает DRM. Далее выводится информация в лог.
Код:
private Kiwi(Application application2, boolean z) {
        long currentTimeMillis = System.currentTimeMillis();
        this.drmEnabled = z;
        if (KiwiLogger.TRACE_ON) {
            LOGGER.trace("Starting initialization process for application: " + application2.getPackageName());
            LOGGER.trace("DRM enabled: " + z);
        }
        instantiateTheWorld(application2);
        if (KiwiLogger.TRACE_ON) {
            LOGGER.trace("Kiwi.Constructor Time: " + (System.currentTimeMillis() - currentTimeMillis));
        }
    }
Мы видим это в logcat, после запуска приложения

logcat_start_drm.png


Далее вызывается метод
Код:
private void instantiateTheWorld(Application application2) {
        C4882c cVar = new C4882c();
        cVar.mo27440a(application2);
        cVar.mo27440a(new C4883a());
        cVar.mo27440a(new C4957a());
        cVar.mo27440a(new C4854c());
        cVar.mo27440a(new C4863d());
        cVar.mo27440a(new PromptManagerImpl());
        cVar.mo27440a(new C4951b());
        cVar.mo27440a(new C4844a());
        cVar.mo27440a(new C4964c());
        cVar.mo27440a(new C4888c());
        cVar.mo27440a(new C4934c());
        cVar.mo27440a(new C4891f());
        cVar.mo27439a();
        cVar.mo27441b(this);
    }
Откроем метод C4882c.mo27440a()
Код:
    public final void mo27440a(Object obj) {
        if (KiwiLogger.TRACE_ON) {
            f15117a.trace("Registering resource: " + obj);
        }
        C4849a.m19515a();
        if (this.f15119c) {
            throw new IllegalStateException("Attempt made to register resource after population has begun!");
        }
        C4849a.m19516a(obj, "resource");
        C4849a.m19519b(m19561a(obj.getClass()) != null, "Resource already registered: " + obj);
        this.f15118b.add(obj);
    }
Здесь происходит "регистрация" своих амазоновских классов. Все классы находятся в com.amazon.*. По названию можно понять, что эти классы являются не родными для нашего приложения и были добавлены Амазоном.

logcat_load_resources_2.png


Чтобы понять, что такое регистрация классов, надо заметить, в ней участвует класс C4849a. Откроем его
Код:
ublic final class C4849a {
    /* renamed from: a */
    public static void m19515a() {
        long id = Looper.getMainLooper().getThread().getId();
        if (Thread.currentThread().getId() != id) {
            m19517a("Executing thread must be thread: " + id + ", was: " + Thread.currentThread().getId());
        }
    }

    /* renamed from: a */
    public static void m19516a(Object obj, String str) {
        if (obj == null) {
            m19517a("Argument: " + str + " cannot be null");
        }
    }

    /* renamed from: a */
    private static void m19517a(String str) {
        throw new C4850b(str);
    }

    /* renamed from: a */
    public static void m19518a(boolean z, String str) {
        if (!z) {
            m19517a(str);
        }
    }

    /* renamed from: b */
    public static void m19519b(boolean z, String str) {
        if (z) {
            m19517a(str);
        }
    }
}
Видим, что под регистрацией подразумевается проверка на null, то есть амазон проверяет целостность и наличие своих классов. Далее приложение ES Explorer биндится к сервису, который запускается приложением Amazon App Store, что еще раз явно указывает на то, что без него приложения не работают. Изначально, когда я это увидел, была мысль просто имитировать этот сервис самописным приложениям, но оказалось все проще.

1_service.png


  1. Проверяется наличие com.amazon.venezia, этот package относится к приложению Amazon App Store
2,3. Проверяется его сигнатура

  1. После этих процедур, запускается родной активити приложения
На самом деле, происходит намного больше всяких вещей, но они не так интересны.

Отвязка приложения

Как вы уже догадались, все очень просто и элементарно - все эти проверки начинаются с активити Kiwi, и мы видели в начале, что вызов этого активити внедряется в каждый активити приложения. Напомню ,выглядит примерно вот так
Код:
    public void onCreate(Bundle bundle) {
        Kiwi.onCreate((Activity) this, true);
        ...
        super.onCreate(bundle);
        ...
    }
Мы просто берем и выпиливываем это из каждого активити и наше приложение больше не привязан к Amazon App Store.


Автор @Thatskriptkid
источник https://github.com/thatskriptkid
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх