DexPatcher: исправление APK-файлов Android с помощью Java

DexPatcher позволяет разработчикам исправлять APK-файлы с помощью Java. Это имеет ряд преимуществ, и использовать DexPatcher намного проще, чем классический подход Smali.

Вы наверняка видели или устанавливали модифицированные приложения, будь то исправленная звонилка под ваше разрешение или пользовательская версия WhatsApp с дополнительными функциями. Но как разработчики это делают? В большинстве случаев исходный код приложений даже недоступен, так как же все это работает? Сначала мы это увидим, затем рассмотрим новый инструмент, призванный значительно упростить процесс, и, наконец, сравним его с популярной платформой Xposed, чтобы увидеть, чем они отличаются.

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

А если серьезно… Начнем с самого начала. Если вы не знакомы с моддингом приложений Android, вам может быть интересно, что такое smali. Разработчики обычно используют язык программирования Java для написания приложений Android. Затем программа (компилятор) «транслирует» этот код в другой формат, подходящий для вашего устройства, в результате чего внутри пакета приложения (или APK) появляются файлы .dex.

В этот момент вы больше не сможете получить доступ к исходному исходному коду (если только вы не являетесь разработчиком или приложение не имеет открытый исходный код). Однако у вас есть APK, поскольку именно он установлен на вашем устройстве. Из него вы можете получить файлы dex (обычно classs.dex), а затем попытаться перевести их обратно в понятный вам формат. Вот тут-то и появляется smali, более читабельный, но точный перевод. Вы можете пойти еще дальше и перевести его обратно на Java, хотя этот процесс недостаточно точен — вы получите результат понятен, но, скорее всего, вы не сможете еще раз перевести его наоборот, так как некоторые детали будут потеряны по пути. Другими словами, любые изменения, которые вы можете внести, будут напрасны, поскольку вы не сможете снова превратить его в APK, чтобы установить на свое устройство… по крайней мере, не без больших усилий.

smali/baksmali на самом деле является ассемблером/диссемблером формата dex — вот что это буквально означает на исландском языке. Однако, когда мы говорим «Smali», мы обычно ссылаемся на формат, который понимает smali (думайте об этом как об инструкции определяя каждую мелочь, даже если нам, людям, не все это нужно - поэтому это более многословно, чем Джава). Также обратите внимание, что приведенное выше объяснение немного упрощено, но должно представлять собой близкую аналогию, но при этом быть простым для понимания.

Что тогда нужно сделать разработчику, чтобы изменить приложение (без доступа к исходному коду)? Процесс примерно следующий:

  1. Получите APK (из Интернета или с устройства).
  2. Используйте что-то вроде apktool декомпилировать APK в Smali. (apktool использует smali/baksmali, но значительно упрощает декомпиляцию и пересборку APK, а также заботится о декодировании ресурсов, таких как файлы XML.)
  3. Извлеките Classes.dex из APK, затем используйте dex2jar и, наконец, декомпилятор Java для получения (неполного, часто сломанного, но в основном понятного) кода Java. (Это необязательно, но может быть полезно, поскольку Smali гораздо сложнее понять.)
  4. Определите, что изменить.
  5. На самом деле измените его, отредактировав код Smali напрямую.
  6. Альтернативно, напишите модификацию на Java, скомпилируйте ее, снова декомпилируйте в Smali, а затем скопируйте полученный код Smali.
  7. Как только все закончится, используйте apktool еще раз, чтобы пересобрать APK.
  8. Подпишите APK (чтобы проверить личность автора; все пакеты должны быть подписаны) и, наконец, установите его.

Написание кода Smali довольно сложно и подвержено ошибкам. В Smali можно внести меньшие изменения, но добавить с его помощью новые функции сложнее. Кроме того, у вас не возникнет ошибок во время компиляции, поэтому даже опечатки могут быть обнаружены только во время выполнения. Распространение и распространение патчей Smali также может быть проблематичным, поскольку различия, как правило, очень специфичны для конкретной версии APK. Хотя существуют некоторые инструменты, упрощающие части процесса, описанного выше (Студия «Виртуоз Тен» приходит на ум), это все равно может утомить.

DexPatcher от старшего участника XDA Ланшон призван исправить эти проблемы, упростив процесс и позволив разработчикам полностью избежать работы со Smali. Вместо этого разработчики могут писать патчи только на Java, а DexPatcher обрабатывает все остальное.

Главным преимуществом этого является наличие легко читаемых и управляемых файлов исправлений. Исправление APK также становится более удобным в целом. Чуть позже мы увидим полный пример использования DexPatcher, но вот краткий обзор того, что он предлагает в первую очередь:

  • Открытый источник.
  • Кроссплатформенность: он должен работать на Linux, Mac и Windows.
  • Файлы исправлений: внесенные вами изменения содержатся в файлах исправлений Java, которыми вы можете поделиться независимо друг от друга.
  • Ява: это не Смали.

Вы также получаете преимущество проверки ошибок во время сборки, поэтому ошибки обнаруживаются на ранних этапах цикла разработки. Скомпилированный Java обеспечивает обычную проверку времени компиляции (с доступом к исходным символам APK), а DexPatcher обеспечивает совместимость исходного кода и патча при исправлении, предоставление полезной информации и предупреждение, когда вы что-то делаете законно, но подозрительно.

В дополнение к этому, DexPatcher поставляется с набором вспомогательные сценарии (доступны только в Linux, хотя их можно переносить и на другие платформы). Они заботятся о настройке рабочей области, извлечении классов и ресурсов целевого APK, декомпиляции классов в Java ( CFR Java-декомпилятор используется для последнего), и, наконец, по завершении сборки и подписания исправленного APK.

Давайте посмотрим на пример (в Linux):

Установите скрипты DexPatcher

$# Make a directory where we can test stuff out and enter it. 

$ mkdir xda-test

$cd xda-test

$ git clone https://github.com/Lanchon/DexPatcher-scripts.git dexpatcher # Clone the DexPatcher helper scripts repo.

$cd dexpatcher

$ chmod +x dxp-* # Not necessary, but for clarity: we need to make sure the files we'll call later are executable.

Настройте сценарии DexPatcher

Открыть dxp.config в вашем любимом текстовом редакторе и обязательно измените необходимые переменные в соответствии с вашей системой. Вам нужно всего лишь изменить следующую строку, чтобы она указывала на место установки вашего Android SDK:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher автоматически выберет самую последнюю доступную версию платформы. Кроме того, вы также можете изменить другие параметры конфигурации, чтобы использовать ваши собственные версии некоторых инструментов вместо встроенных значений по умолчанию.)

Для удобства доступа добавим декспатчер каталог к ​​нашему ПУТЬили даже символическую ссылку на разные dxp-* скрипты в папку, которая уже находится в вашем ПУТЬ, такой как ~/бин:

export PATH=$PWD:$PATH

Изменить приложение

В этом примере мы будем использовать простое приложение с открытым исходным кодом. Конечно, в данном конкретном случае можно было бы напрямую исправить исходный код, но это совсем не весело!

Мы возьмем приложение «Получить идентификатор» от basil2style, приложение, которое показывает вам некоторые подробности о вашем устройстве. Наша цель — изменить кнопку «Копировать» для «Идентификатора устройства» и вместо этого использовать этот идентификатор:

  • Сначала давайте загрузим APK, который мы собираемся изменить: Получить идентификатор.
  • Декомпилируем приложение.
  • Создайте ключ подписи, который мы позже будем использовать для подписи APK.

Мы также можем сделать все это через оболочку, используя вспомогательные скрипты:

$cd dexpatcher # Go to our working directory. 

$ curl -O https://f-droid.org/repo/makeinfo.com.getid_1.apk # Download the APK.

$ dxp-setup-for-apk makeinfo.com.getid_1.apk # Unpack and decompile the APK.

$cd makeinfo.com.getid_1 # Go to the newly created directory where everything is unpacked/decompiled to.

$ dxp-create-keystore # Create the APK signing key. Press 6 times (or fill out the info), then "yes".

Там вы заметите несколько разных каталогов:

  • декодировать: здесь вы найдете ресурсы и Smali в расшифровке apktool.
  • источник: Пустой каталог. Здесь мы будем размещать наши файлы патчей.
  • src-cfr: это где CFR декомпилировал приложение (вместе с ошибками). Удобное место для поиска и принятия решения о том, что изменить (вам также могут понадобиться ресурсы и их идентификаторы из каталога декодирования выше, но не для этого конкретного примера).
  • src-cfr-nodecode: то же, что и выше, но содержит только пустые заглушки (без кода, только скелеты). Вы можете использовать эти файлы в качестве основы для вашего патча, как мы увидим позже.

Как мы уже упоминали ранее, мы хотим изменить кнопку «Копировать» идентификатора устройства, чтобы вместо этого поделиться текстом идентификатора. Если мы посмотрим исходный код, то заметим, что кнопка «Копировать идентификатор устройства» (устройство_копия) по щелчку событие обрабатывается анонимным классом в src-cfr/makeinfo/com/getid/MainActivity.java. Хотя мы могли бы изменить это здесь, обычно лучше найти альтернативный способ сделать это, поскольку анонимные классы имеют числовые имена (MainClassName$SomeNumber, например Основная деятельность$3), который может непредсказуемо меняться в зависимости от версии.

Вместо этого мы зарегистрируем наш собственный класс для события, изменив Основная деятельность сорт. Для начала скопируем «скелетную» версию из src-cfr-nocode/makeinfo/com/getid/MainActivity.java к src/makeinfo/com/getid/MainActivity.java (помните, что источник здесь будет жить наш патч). (При желании вы также можете скопировать версию с полным кодом, это чисто дело вкуса.)

Теперь мы можем редактировать его следующим образом:

  • Добавьте необходимый импорт для аннотации DexPatcher:
importlanchon.dexpatcher.annotation.*;
  • Добавьте тег, указывающий, что мы редактируем класс. Мы также установили действие по умолчанию для членов класса patch: ИГНОРИРОВАТЬ, что означает, что на эти члены будет ссылаться наш код во время компиляции Java, но они будут игнорироваться DexPatcher.
@DexEdit(defaultAction=DexAction.IGNORE)

publicclassMainActivity

// The reference to ActionBarActivity will be satisfied by symbols

// extracted from the app when we build the patch.

extendsActionBarActivity{

  • Кроме того, добавьте в конструктор пустые тела и onCreate метод, а также все другие методы, которые мы планируем использовать (помните, что они будут игнорироваться при фактическом применении нашего патча — мы просто добавляем их, чтобы при необходимости можно было обратиться к ним здесь). Вы также можете просто добавить родной вместо этого ключевое слово.
  • Если вам интересно, мы уже можем создать патч на этом этапе:
    $ dxp-make # Output: `patched.apk`.
    Довольно просто, правда? Однако давайте продолжим — мы еще не закончили.
  • Давайте редактировать onCreate теперь изложу свой OnClickListener чтобы мы могли поделиться идентификатором устройства, а не копировать его в буфер обмена:
    // Rename the target method so that we can still call it (the original)// if needed.@DexEdit(target="onCreate")protectedvoidsource_onCreate(Bundlevar1){}// Add our new custom method.@Override@DexAddprotectedvoidonCreate(Bundlevar1){// Call the original method:source_onCreate(var1);// Replace the text and handler:device_copy.setText("Share");device_copy.setOnClickListener(newDeviceCopyOnClick());}// Note that we don't use an anonymous class to avoid nameclashing with// MainActivity$1, which already exists.// We also could've defined a nested MainActivity.Patch class and used// an anonymous class in MainActivity.Patch.onCreate(), and then called// MainActivity.Patch.onCreate() from MainActivity.onCreate().@DexAddclassDeviceCopyOnClickimplementsView.OnClickListener{@OverridepublicvoidonClick(Viewobject){if(MainActivity.this.val){Intentintent=newIntent(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra(Intent.EXTRA_SUBJECT,"Device ID");intent.putExtra(Intent.EXTRA_TEXT,device.getText().toString());startActivity(Intent.createChooser(intent,"Share Device ID"));}else{Toast.makeText(MainActivity.this.getApplicationContext(),"Nothing to Share",0).show();}}}
  • Похоже, мы закончили! Полный патч должен выглядеть так этот. Теперь мы можем собрать исправленный APK и установить его:
    $ dxp-make$ adb install patched.apk
  • Давайте посмотрим на результат:

(Спасибо Lanchon за помощь с примером кода!)

Xposed чрезвычайно популярен, и на это есть веская причина: он значительно упрощает создание, обмен и установку модов как для разработчиков, так и для пользователей. Есть несколько различий между DexPatcher и Xpose, из-за которых некоторые могут предпочесть один другому:

  1. Xpose творит чудеса, подключая методы во время выполнения и позволяя разработчикам делать что-то до, после или вместо любого метода. DexPatcher, с другой стороны, изменяет все перед выполнением и создает отдельный модифицированный APK. -- запуск кода до, после или вместо методов все еще возможен, и у вас действительно есть некоторые дополнительные свобода.
  2. Создание автономного APK означает, что он не зависит от какой-либо внешней платформы. Это также означает, что для изменения пользовательских приложений не требуется root.
  3. Поскольку вы создали новый APK с помощью DexPatcher, он будет подписан по-другому. Это означает, что пользователи не могут получать официальные обновления от первоначального автора и могут вызвать некоторые проблемы с такими приложениями, как Google Apps, если подписи проверены.
  4. Исходный код как модулей, так и патчей DexPatcher можно легко распространять и модифицировать. У них также много общего, если вы немного знакомы с каждым.

Мы достаточно говорили о DexPatcher. Теперь ваша очередь попробовать, так что отправляйтесь в Тема на форуме DexPatcher чтобы начать прямо сейчас!