DexPatcher: Popravite APK-je za Android z uporabo Jave

DexPatcher razvijalcem omogoča popravljanje APK-jev z uporabo Jave. To ima več prednosti in uporaba DexPatcherja je veliko lažja od klasičnega pristopa Smali.

Verjetno ste že videli ali namestili spremenjene aplikacije, pa naj gre za popravljen klicalnik za vašo ločljivost ali različico WhatsApp po meri z dodanimi funkcijami. Kako razvijalci to počnejo? Veliko časa izvorna koda aplikacij sploh ni na voljo, kako torej vse skupaj deluje? Najprej bomo to videli, nato pa si bomo ogledali novo orodje, katerega namen je precej olajšati postopek, in ga na koncu primerjali s priljubljenim ogrodjem Xposed, da vidimo, v čem se razlikujejo.

Morda ste že slišali, kako se APK-ji običajno spreminjajo - razvijalci se vključijo v matrix, začnite videti vse v Smaliju in pridobite možnost spreminjanja stvari z uporabo moči Vir. Telefonski klic je dovolj, da jih spravi ven, ko je to opravljeno, in takrat so pripravljeni deliti bleščeče nove APK-je.

Bolj resno… Začnimo na začetku. Če niste seznanjeni s spreminjanjem aplikacij za Android, se morda sprašujete, kaj je smali. Razvijalci običajno uporabljajo programski jezik Java za kodiranje aplikacij za Android. Program (prevajalnik) nato "prevede" to kodo v drugo obliko, ki je primerna za vašo napravo, kar povzroči datoteke .dex, ki jih vsebuje paket aplikacije (ali APK).

Takrat ne morete več dostopati do izvirne izvorne kode (razen če ste razvijalec ali če je aplikacija odprtokodna). Vseeno pa imate APK, saj je to tisto, kar je nameščeno v vaši napravi. Iz njega lahko dobite datoteke dex (običajno classes.dex) in jih nato poskusite prevesti nazaj v obliko, ki jo razumete. Tu nastopi smali, kot bolj berljiv, a zvest prevod. Lahko greste še korak dlje in ga prevedete nazaj v Javo, čeprav ta postopek ni dovolj zvest -- dobili boste razumljiv rezultat, vendar je verjetno, da ga ne boste mogli prevesti v drugo smer, ker bodo nekatere podrobnosti izgubljene spotoma. Z drugimi besedami, vse spremembe, ki jih boste morda naredili, bodo zaman, saj ga ne boste mogli znova spremeniti nazaj v APK, da bi ga namestili v svojo napravo... vsaj ne brez veliko truda.

smali/baksmali je pravzaprav asembler/dissembler za format dex -- to dobesedno pomeni v islandščini. Vendar se običajno sklicujemo na obliko, ki jo smali razume, ko rečemo "Smali" (mislite na to kot na navodila definirati vse najmanjše podrobnosti, tudi če jih ljudje ne potrebujemo – zato je bolj besedno kot Java). Upoštevajte tudi, da je zgornja razlaga nekoliko poenostavljena, vendar bi morala biti podobna analogiji, hkrati pa jo je lahko razumeti.

Kaj bi potem moral razvijalec narediti, da spremeni aplikacijo (brez dostopa do vira)? Postopek je bolj ali manj tak:

  1. Pridobite APK (iz spleta ali iz naprave).
  2. Uporabite nekaj podobnega apktool da dekompilirate APK v Smali. (apktool uporablja smali/baksmali, vendar omogoča veliko lažje dekompiliranje in ponovno gradnjo APK-jev ter poskrbi tudi za dekodiranje virov, kot so datoteke XML.)
  3. Ekstrahirajte classes.dex iz APK-ja in nato uporabite dex2jar in končno dekompilator Java za pridobitev (nepopolne, pogosto pokvarjene, a večinoma razumljive) kode Java. (To ni obvezno, vendar je lahko koristno, saj je Smali veliko težje razumeti.)
  4. Ugotovite, kaj želite spremeniti.
  5. Pravzaprav ga spremenite tako, da neposredno uredite kodo Smali.
  6. Druga možnost je, da napišete spremembo v Javi, jo prevedete, znova dekompilirate v Smali, nato pa prekopirate dobljeno kodo Smali.
  7. Ko je vsega konec, uporabite apktool znova, da znova zgradite APK.
  8. Podpišite APK (za preverjanje identitete avtorja; vsi paketi morajo biti podpisani) in ga končno namestite.

Pisanje kode Smali je precej težko in nagnjeno k napakam. Manjše spremembe je mogoče narediti v Smaliju, vendar je dodajanje novih funkcij z njim zahtevnejše. Poleg tega ne boste imeli nobenih napak pri prevajanju, tako da bodo tudi tipkarske napake morda odkrite le med izvajanjem. Razširitev in deljenje popravkov Smali je lahko tudi težavno, saj so razlike ponavadi zelo specifične za določeno različico APK-ja. Čeprav obstajajo nekatera orodja, ki olajšajo dele zgoraj razloženega postopka (Studio Virtuous Ten pride na misel), lahko še vedno postane utrujajoče.

DexPatcher starejšega člana XDA Lanchon želi odpraviti te težave tako, da poenostavi postopek in omogoči razvijalcem, da se popolnoma izognejo ukvarjanju s Smalijem. Namesto tega lahko razvijalci pišejo popravke samo v Javi, DexPatcher pa poskrbi za vse ostalo.

To ima glavno prednost, saj ima preprosto berljive in obvladljive datoteke popravkov. Krpanje APK-jev postane na splošno bolj priročno. Čez nekaj časa si bomo ogledali celoten primer uporabe DexPatcherja, tukaj pa je najprej kratek pregled tega, kar ponuja:

  • Odprtokodno.
  • Večplatformsko: delovati bi moralo v sistemih Linux, Mac in Windows.
  • Datoteke popravkov: spremembe, ki jih naredite, so vsebovane v datotekah popravkov Java, ki jih lahko delite neodvisno.
  • Java: ni Smali.

Prav tako pridobite prednost preverjanja napak med gradnjo, tako da se hrošči pokažejo zgodaj v razvojnem ciklu. Prevedena Java zagotavlja običajno preverjanje časa prevajanja (z dostopom do izvirnih simbolov APK), DexPatcher pa uveljavi združljivost vira in popravka pri popravku, zagotavljanje koristnih informacij in dajanje opozoril, ko se zdi, da nekaj počnete legalen, a negotov.

Poleg tega ima DexPatcher nabor pomožne skripte (na voljo samo v Linuxu, čeprav jih je mogoče prenesti tudi na druge platforme). Ti poskrbijo za nastavitev delovnega prostora, ekstrahiranje razredov in virov ciljnega APK-ja, dekompilacijo razredov v Javo ( CFR Java decompiler se uporablja za slednje) in končno zgradite in podpišete popravljeni APK, ko končate.

Oglejmo si primer (v Linuxu):

Namestite skripte 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.

Konfigurirajte skripte DexPatcher

Odprto dxp.config v vašem najljubšem urejevalniku besedil in poskrbite, da boste spremenili potrebne spremenljivke, da bodo ustrezale vašemu sistemu. Spremeniti morate samo naslednjo vrstico, da namesto tega kaže na mesto namestitve vašega SDK-ja za Android:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher bo samodejno izbral najvišjo razpoložljivo različico platforme. Poleg tega lahko spremenite tudi druge možnosti konfiguracije, da namesto privzetih privzetih nastavitev uporabljajo vaše lastne različice nekaterih orodij.)

Za lažji dostop lahko dodamo dexpatcher imenik do našega POT, ali celo simbolno povezavo do drugega dxp-* skripte na lokacijo, ki je že v vašem POT, kot naprimer ~/bin:

export PATH=$PWD:$PATH

Spremenite aplikacijo

Za ta primer bomo uporabili preprosto in odprtokodno aplikacijo. Seveda bi bilo v tem posebnem primeru mogoče neposredno popraviti izvorno kodo, vendar to sploh ni zabavno!

Vzeli bomo aplikacijo "Get ID" podjetja basil2style, aplikacijo, ki vam prikaže nekaj podrobnosti o vaši napravi. Naš cilj je spremeniti gumb »Kopiraj« za »ID naprave« in omogočiti skupno rabo tega ID-ja:

  • Najprej prenesimo APK, ki ga bomo spremenili: Dobi osebni dokument.
  • Dekompilirajte aplikacijo.
  • Ustvarite podpisni ključ, ki ga bomo kasneje uporabili za podpis APK-ja.

Vse lahko naredimo tudi prek lupine z uporabo pomožnih skriptov:

$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".

Tam boste opazili nekaj različnih imenikov:

  • dekodirati: tukaj boste našli vire in Smali, kot jih dekodira apktool.
  • src: Prazen imenik. Tukaj bomo postavili naše datoteke popravkov.
  • src-cfr: tukaj je cfr dekompiliral aplikacijo (skupaj z napakami). Dobro mesto za ogled, da se odločite, kaj spremeniti (morda boste potrebovali tudi vire in njihove ID-je iz zgornjega imenika za dekodiranje, vendar ne za ta primer).
  • src-cfr-nodecode: enako kot zgoraj, vendar vsebuje samo prazne škrbine (brez kode, samo okostja). Te datoteke lahko uporabite kot osnovo za svoj popravek, kot bomo videli čez nekaj časa.

Kot smo že omenili, želimo spremeniti gumb »Kopiraj« ID-ja naprave, da namesto tega deli besedilo ID-ja. Če pogledamo izvorno kodo, bomo opazili, da je gumb Kopiraj ID naprave (device_copy) onClick dogodek obravnava anonimni razred v src-cfr/makeinfo/com/getid/MainActivity.java. Čeprav bi ga lahko tukaj spremenili, je običajno bolje najti alternativni način za to, saj imajo anonimni razredi številska imena (Ime glavnega razreda $ nekaj števila, npr. Glavna dejavnost $3), ki se lahko nepredvidljivo spremeni med različicami.

Namesto tega bomo za dogodek prijavili svoj razred tako, da bomo spremenili Glavna dejavnost razred. Najprej kopirajmo "skeleton" različico iz src-cfr-nocode/makeinfo/com/getid/MainActivity.java do src/makeinfo/com/getid/MainActivity.java (Zapomni si to src kjer bo naš obliž živel). (Če želite, lahko tudi kopirate različico s celotno kodo, to je zgolj stvar okusa.)

Zdaj ga lahko uredimo na naslednji način:

  • Dodajte potreben uvoz za opombo DexPatcher:
importlanchon.dexpatcher.annotation.*;
  • Dodajte oznako, ki označuje, da urejamo razred. Nastavili smo tudi privzeto dejanje za člane razreda popravkov na PREZRI, kar pomeni, da so člani tam, da se nanje sklicuje naša koda med prevajanjem Jave, vendar jih bo DexPatcher prezrl.
@DexEdit(defaultAction=DexAction.IGNORE)

publicclassMainActivity

// The reference to ActionBarActivity will be satisfied by symbols

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

extendsActionBarActivity{

  • Poleg tega v konstruktor dodajte prazna telesa in onCreate metodo, kot tudi vse druge metode, ki jih nameravamo uporabiti (ne pozabite, da bodo prezrte, ko bo naš popravek dejansko uporabljen - samo dodajamo jih, da se lahko po potrebi sklicujemo nanje tukaj). Lahko tudi samo dodate domačin namesto tega ključno besedo.
  • Na tej točki že lahko zgradimo popravek, če ste radovedni:
    $ dxp-make # Output: `patched.apk`.
    Precej preprosto, kajne? Vendar nadaljujmo – še vedno nismo končali.
  • Uredimo onCreate zdaj, da določi svoje OnClickListener tako da lahko delimo ID naprave, namesto da ga kopiramo v odložišče:
    // 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();}}}
  • Videti je, da smo zdaj končali! Celoten popravek bi moral izgledati takole to. Zdaj lahko sestavimo popravljeni APK in ga namestimo:
    $ dxp-make$ adb install patched.apk
  • Poglejmo si rezultat:

(Hvala Lanchonu za pomoč pri vzorčni kodi!)

Xposed je izjemno priljubljen in z dobrim razlogom - omogoča veliko preprostejšo gradnjo, skupno rabo in nameščanje modifikacij za razvijalce in uporabnike. Obstaja nekaj razlik med DexPatcherjem in Xposedom, zaradi katerih imajo nekateri raje enega pred drugim:

  1. Xposed naredi svojo čarovnijo tako, da prevzame metode med izvajanjem in omogoči razvijalcem, da naredijo nekaj pred, po ali namesto katere koli metode. DexPatcher pa po drugi strani spremeni vse pred časom izvajanja in izdela samostojen spremenjen APK -- izvajanje kode pred, za ali namesto metod je še vedno možno in dejansko imate nekaj dodatnega svoboda.
  2. Izdelava samostojnega APK-ja pomeni, da ni odvisen od nobenega zunanjega ogrodja. To tudi pomeni, da root ni potreben za spreminjanje uporabniških aplikacij.
  3. Ker ste ustvarili nov APK z DexPatcherjem, bo podpisan drugače. To pomeni, da uporabniki ne morejo prejemati uradnih posodobitev od prvotnega avtorja in lahko povzročijo težave z aplikacijami, kot je Google Apps, če so podpisi preverjeni.
  4. Izvorno kodo modulov in popravkov DexPatcher je mogoče enostavno distribuirati in spreminjati. Imajo tudi veliko podobnosti, če se nekoliko seznanite z vsakim.

Dovolj smo govorili o DexPatcherju. Zdaj ste na vrsti, da poskusite, zato pojdite na Tema foruma DexPatcher da začnete takoj!