DexPatcher позволява на разработчиците да коригират APK файлове с помощта на Java. Това има няколко предимства и използването на DexPatcher е много по-лесно от класическия подход на Smali.
Вероятно сте виждали или инсталирали модифицирани приложения, независимо дали става дума за кръпка за набиране за вашата резолюция или персонализирана версия на WhatsApp с добавени функции. Как обаче разработчиците правят това? През много време изходният код на приложенията дори не е наличен, така че как работи всичко това? Първо ще видим това, след това ще разгледаме нов инструмент, който има за цел да направи процеса много по-лесен, и накрая ще го сравним с популярната рамка Xposed, за да видим как се различават.
Може би сте чували за това как APK обикновено се модифицират - разработчиците се включват в матрица, започнете да виждате всичко в Smali и придобийте способността да променяте нещата, използвайки силата на Източник. Едно телефонно обаждане е достатъчно, за да ги измъкне, след като това стане, след което те са готови да споделят лъскавите нови APK файлове.
По-сериозно… Да започнем отначало. Ако не сте запознати с модифицирането на Android приложения, може би се чудите какво е smali. Разработчиците обикновено използват езика за програмиране Java за кодиране на приложения за Android. След това програма (компилаторът) „превежда“ този код в друг формат, подходящ за вашето устройство, което води до .dex файлове, съдържащи се в пакета на приложението (или APK).
В този момент вече нямате достъп до оригиналния изходен код (освен ако не сте разработчикът или приложението е с отворен код). Но това, което имате, е APK, тъй като той е инсталиран на вашето устройство. От него можете да получите dex файловете (обикновено classes.dex) и след това да опитате да ги преведете обратно във формат, който разбирате. Точно там идва smali, като по-четлив, но верен превод. Можете да отидете още една крачка напред и да го преведете обратно на Java, въпреки че този процес не е достатъчно точен -- ще получите разбираем резултат, но има вероятност да не можете да го преведете обратно, тъй като някои подробности ще бъдат загубени по пътя. С други думи, всички модификации, които можете да направите, ще бъдат напразни, тъй като няма да можете да го превърнете отново в APK, за да го инсталирате на вашето устройство… поне не без много усилия.
smali/baksmali всъщност е асемблер/дисемблер за dex формата -- това буквално означава на исландски. Въпреки това, обикновено се позоваваме на формата, който smali разбира, когато казваме „Smali“ (мислете за това като инструкции дефиниране на всеки малък детайл, дори и да не е необходимо на нас хората - следователно е по-подробно от Java). Също така имайте предвид, че горното обяснение е малко опростено, но трябва да бъде близка аналогия, като същевременно е лесно за разбиране.
Тогава какво трябва да направи разработчикът, за да модифицира приложение (без достъп до източника)? Процесът е горе-долу както следва:
- Вземете APK (от мрежата или от устройството).
- Използвайте нещо подобно apktool за декомпилиране на APK до Smali. (apktool използва smali/baksmali, но прави много по-лесно декомпилирането и повторното изграждане на APK файлове и също така се грижи за декодирането на ресурси като XML файлове.)
- Извлечете classes.dex от APK, след което използвайте dex2jar и накрая декомпилатор на Java, за да получите (непълен, често повреден, но най-вече разбираем) код на Java. (Това не е задължително, но може да бъде полезно, тъй като Smali е много по-труден за разбиране.)
- Определете какво да промените.
- Всъщност го променете, като редактирате директно кода на Smali.
- Алтернативно, напишете модификацията на Java, компилирайте я, декомпилирайте я отново в Smali, след което копирайте получения код на Smali.
- След като всичко свърши, използвайте apktool отново, за да възстановите APK.
- Подпишете APK (за да потвърдите самоличността на автора; всички пакети трябва да бъдат подписани) и накрая го инсталирайте.
Писането на Smali код е доста трудно и податливо на грешки. По-малки промени могат да бъдат направени в Smali, но добавянето на нови функции с него е по-предизвикателно. Освен това, няма да имате никакви грешки по време на компилиране, така че дори правописни грешки могат да бъдат открити само по време на изпълнение. Разширяването и споделянето на пачове на Smali също може да бъде обезпокоително, тъй като разликите обикновено са много специфични за конкретна версия на APK. Въпреки че съществуват някои инструменти за улесняване на части от процеса, обяснен по-горе (Студио Virtuous Ten идва на ум), все още може да стане уморително.
DexPatcher от старши член на XDA Ланшон има за цел да коригира тези проблеми, като направи процеса по-прост и позволи на разработчиците напълно да избегнат работа със Smali. Вместо това разработчиците могат да пишат пачове само в Java и да накарат DexPatcher да се справи с всичко останало.
Това има основното предимство да имате лесно четими и управляеми пач файлове. Поправянето на APK също става по-удобно като цяло. След малко ще видим пълен пример за това как да използвате DexPatcher, но ето първо бърз преглед на това, което предлага:
- Отворен код.
- Междуплатформен: трябва да работи на Linux, Mac и Windows.
- Пач файлове: промените, които правите, се съдържат в Java пач файлове, които можете да споделяте независимо.
- Java: не е Smali.
Вие също така печелите предимството на проверката за грешки по време на изграждане, така че грешките се появяват рано в цикъла на разработка. Компилираната 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-* скриптове към място, което вече е във вашето ПЪТЕКА, като ~/bin:
export PATH=$PWD:$PATH
Промяна на приложение
За този пример ще използваме просто приложение с отворен код. Разбира се, директното коригиране на изходния код би било възможно в този конкретен случай, но това изобщо не е забавно!
Ще вземем приложението „Get ID“ от 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: Празна директория. Това е мястото, където ще поставим нашите пач файлове.
- src-cfr: това е където cfr декомпилира приложението (заедно с грешки). Добре е да разгледате, за да решите какво да промените (може също така да ви трябват ресурси и техните идентификатори от директорията за декодиране по-горе, но не и за този конкретен пример).
- src-cfr-нодекод: същото като по-горе, но съдържащо само празни мъничета (без код, само скелети). Можете да използвате тези файлове като основа за вашата корекция, както ще видим след малко.
Както споменахме преди, искаме да променим бутона „Копиране“ на идентификатора на устройството, за да споделим вместо това текста на идентификатора. Ако разгледаме изходния код, ще забележим, че бутонът Device ID Copy (устройство_копие) onClick събитието се обработва от анонимен клас в src-cfr/makeinfo/com/getid/MainActivity.java. Въпреки че можем да го модифицираме тук, обикновено е по-добре да намерим алтернативен начин да го направим, тъй като анонимните класове имат цифрови имена (MainClassName$SomeNumber, напр. Основна дейност $3), които могат да се променят непредсказуемо между версиите.
Вместо това ще регистрираме нашия собствен клас за събитието, като променим Основна дейност клас. Първо, нека копираме "скелетната" версия от src-cfr-nocode/makeinfo/com/getid/MainActivity.java да се src/makeinfo/com/getid/MainActivity.java (не забравяйте, че src е мястото, където нашата кръпка ще живее). (Можете също да копирате версията с пълния код, ако предпочитате, това е чисто въпрос на вкус.)
Сега можем да го редактираме, както следва:
- Добавете необходимото импортиране за анотацията на 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 и Xposed, които може да накарат някои да предпочетат едното пред другото:
- Xposed прави своята магия, като закача методи по време на изпълнение и позволява на разработчиците да направят нещо преди, след или вместо всеки метод. DexPatcher, от друга страна, променя всичко преди изпълнението и създава самостоятелен, модифициран APK -- изпълняването на код преди, след или вместо методи все още е възможно и всъщност имате някои допълнителни свобода.
- Създаването на самостоятелен APK означава, че той не зависи от външна рамка. Това също означава, че root не е необходим за модифициране на потребителски приложения.
- Тъй като сте създали нов APK с DexPatcher, той ще бъде подписан по различен начин. Това означава, че потребителите не могат да получават официални актуализации от оригиналния автор и може да причини някои проблеми с приложения като Google Apps, ако подписите са проверени.
- Изходният код както на модулите, така и на пачовете на DexPatcher може лесно да се разпространява и модифицира. Те също споделят много прилики, ако се запознаете малко с всеки.
Говорихме достатъчно за DexPatcher. Сега е ваш ред да опитате, така че преминете към Тема във форума на DexPatcher за да започнете веднага!