DexPatcher: Corectează APK-urile Android folosind Java

DexPatcher permite dezvoltatorilor să corecteze APK-uri folosind Java. Acest lucru are mai multe avantaje, iar utilizarea DexPatcher este mult mai ușoară decât abordarea clasică Smali.

Probabil ați văzut sau ați instalat aplicații modificate, fie că este vorba de un dialer corelat pentru rezoluția dvs. sau de o versiune WhatsApp personalizată cu funcții adăugate. Cum fac dezvoltatorii asta, totuși? De multe ori, codul sursă al aplicațiilor nici măcar nu este disponibil, așa că cum funcționează totul? Vom vedea asta mai întâi, apoi vom arunca o privire asupra unui nou instrument care își propune să ușureze mult procesul și, în cele din urmă, îl vom compara cu cadrul popular Xposed pentru a vedea cum diferă.

S-ar putea să fi auzit despre modul în care APK-urile sunt de obicei modificate -- dezvoltatorii se conectează la matrice, începeți să vedeți totul în Smali și obțineți capacitatea de a modifica lucrurile folosind puterea Sursă. Un apel telefonic este suficient pentru a le scoate odată ce s-a terminat, moment în care sunt gata să partajeze noile APK-uri strălucitoare.

Mai serios... Să începem cu începutul. Dacă nu sunteți familiarizat cu modificarea aplicațiilor Android, s-ar putea să vă întrebați ce este smali. Dezvoltatorii folosesc de obicei limbajul de programare Java pentru a codifica aplicațiile Android. Un program (compilatorul) apoi „traduce” acel cod într-un alt format potrivit pentru dispozitivul dvs., rezultând fișiere .dex conținute în pachetul aplicației (sau APK).

În acel moment, nu mai puteți accesa codul sursă original (cu excepția cazului în care sunteți dezvoltatorul sau aplicația este open source). Cu toate acestea, ceea ce aveți este APK-ul, deoarece este ceea ce este instalat pe dispozitivul dvs. Din acesta, puteți obține fișierele dex (de obicei classes.dex) și apoi încercați să le traduceți înapoi într-un format pe care îl puteți înțelege. Acolo intervine smali, ca o traducere mai lizibilă, dar mai fidelă. Puteți face un pas mai departe și îl traduceți înapoi în Java, deși acest proces nu este suficient de fidel -- veți obține un rezultat de înțeles, dar sunt șanse să nu îl puteți traduce din nou invers, deoarece unele detalii se vor pierde pe parcurs. Cu alte cuvinte, orice modificare pe care le-ați putea face va fi în zadar, deoarece nu îl veți putea transforma din nou într-un APK pentru a-l instala pe dispozitivul dvs... cel puțin nu fără mult efort.

smali/baksmali este de fapt un asamblator/dezasamblator pentru formatul dex -- asta înseamnă literalmente în islandeză. Cu toate acestea, de obicei ne referim la formatul pe care smali îl înțelege atunci când spunem „Smali” (gândiți-vă la el ca instrucțiuni definirea fiecărui mic detaliu, chiar dacă nu este necesar pentru noi, oamenii -- este, prin urmare, mai verbos decât Java). De asemenea, rețineți că explicația de mai sus este puțin simplificată, dar ar trebui să fie o analogie apropiată, în același timp fiind ușor de înțeles.

Ce ar trebui să facă un dezvoltator pentru a modifica o aplicație (fără acces la sursă), atunci? Procesul este mai mult sau mai puțin după cum urmează:

  1. Obțineți APK-ul (de pe web sau de pe dispozitiv).
  2. Folosește ceva de genul apktool pentru a decompila APK-ul în Smali. (apktool folosește smali/baksmali, dar face mult mai ușor decompilarea și reconstruirea APK-urilor și, de asemenea, se ocupă de decodarea resurselor, cum ar fi fișierele XML.)
  3. Extrageți classes.dex din APK, apoi utilizați dex2jar și, în sfârșit, un decompilator Java pentru a obține cod Java (incomplet, adesea rupt, dar în mare parte ușor de înțeles). (Acest lucru este opțional, dar poate fi util, deoarece Smali este mult mai greu de înțeles.)
  4. Identificați ce să modificați.
  5. De fapt, modificați-l prin editarea directă a codului Smali.
  6. Alternativ, scrieți modificarea în Java, compilați-o, decompilați-o din nou în Smali, apoi copiați codul Smali rezultat.
  7. Odată ce totul s-a terminat, folosește apktool din nou pentru a reconstrui APK-ul.
  8. Semnează APK-ul (pentru a verifica identificarea autorului; toate pachetele trebuie să fie semnate) și, în final, instalați-l.

Scrierea codului Smali este destul de dificilă și predispusă la erori. Modificări mai mici pot fi făcute în Smali, dar adăugarea de noi funcții cu acesta este mai dificilă. În plus, nu veți avea erori de compilare, așa că chiar și greșelile de scriere pot fi detectate doar în timpul execuției. Extinderea și partajarea patch-urilor Smali poate fi, de asemenea, supărătoare, deoarece diferențele tind să fie foarte specifice unei anumite versiuni APK. Deși există unele instrumente pentru a ușura părți ale procesului explicat mai sus (Studioul Virtuous Ten îmi vine în minte), încă poate deveni obositor.

DexPatcher de la XDA Senior Member Lanchon își propune să rezolve aceste probleme, simplificând procesul și permițând dezvoltatorilor să evite complet de-a face cu Smali. În schimb, dezvoltatorii pot scrie patch-uri numai în Java și pot lăsa DexPatcher să se ocupe de orice altceva.

Acest lucru are principalul avantaj de a avea fișiere de corecție ușor de citit și de gestionat. Corectarea APK-urilor devine, de asemenea, mai convenabilă în general. Vom vedea un exemplu complet despre cum să utilizați DexPatcher într-un pic, dar iată o scurtă prezentare generală a ceea ce oferă mai întâi:

  • Sursa deschisa.
  • Multiplatformă: ar trebui să ruleze pe Linux, Mac și Windows.
  • Fișiere de corecție: modificările pe care le faceți sunt conținute în fișierele de corecție Java pe care le puteți partaja independent.
  • Java: nu este Smali.

De asemenea, obțineți avantajul verificării erorilor în timpul construirii, astfel încât erorile apar la începutul ciclului de dezvoltare. Java compilat oferă verificarea obișnuită a timpului de compilare (cu acces la simbolurile APK originale), iar DexPatcher impune compatibilitatea sursei și a patch-ului la corecție, oferind informații utile și oferind avertismente atunci când se pare că faci ceva legal, dar de pește.

În plus, DexPatcher vine cu un set de scripturi de ajutor (disponibil doar pe Linux, deși ar putea fi portate și pe alte platforme). Acestea se ocupă de configurarea spațiului de lucru, extragerea claselor și resurselor APK-ului țintă, decompilarea claselor în Java ( Decompilator CFR Java este folosit pentru acesta din urmă) și, în cele din urmă, construiți și semnați APK-ul corectat odată ce ați terminat.

Să aruncăm o privire la un exemplu (pe Linux):

Instalați scripturile 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.

Configurați scripturile DexPatcher

Deschis dxp.config în editorul de text preferat și asigurați-vă că modificați variabilele necesare pentru a se potrivi cu sistemul dvs. Trebuie doar să modificați următoarea linie pentru a indica locația de instalare a SDK-ului dvs. Android:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher va alege automat cea mai înaltă versiune de platformă disponibilă. În plus, puteți modifica și alte opțiuni de configurare pentru ca acesta să utilizeze propriile versiuni ale unor instrumente în loc de setările implicite incluse.)

Pentru a facilita accesul, putem adăuga dexpatcher directorul nostru CALE, sau chiar simbolizează diferit dxp-* scripturi într-o locație care este deja în dvs CALE, ca ~/bin:

export PATH=$PWD:$PATH

Modificați o aplicație

Pentru acest exemplu, vom folosi o aplicație simplă și open source. Desigur, corectarea directă a codului sursă ar fi posibilă în acest caz particular, dar nu este deloc distractiv!

Vom lua aplicația „Get ID” de la basil2style, o aplicație care îți arată câteva detalii despre dispozitivul tău. Scopul nostru este să modificăm butonul „Copiere” pentru „ID-ul dispozitivului” și să-i oferim în schimb acest ID:

  • Mai întâi, să descarcăm APK-ul pe care îl vom modifica: Obțineți ID.
  • Decompilați aplicația.
  • Creați cheia de semnare pe care o vom folosi ulterior pentru a semna APK-ul.

De asemenea, putem face totul prin intermediul shell-ului, folosind scripturile de ajutor:

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

Veți observa câteva directoare diferite acolo:

  • decodifica: veți găsi resursele și Smali aici, așa cum a fost decodat de apktool.
  • src: Director gol. Aici vom plasa fișierele de corecție.
  • src-cfr: aici e locul cfr a decompilat aplicația (împreună cu erori). Un loc bun de căutat pentru a decide ce să schimbați (s-ar putea să aveți nevoie și de resurse și ID-urile acestora din directorul de decodare de mai sus, dar nu pentru acest exemplu special).
  • src-cfr-nodecode: la fel ca mai sus, dar conținând doar stub-uri goale (fără cod, doar schelete). Puteți folosi aceste fișiere ca bază pentru patch-ul dvs., așa cum vom vedea în curând.

După cum am menționat anterior, dorim să schimbăm butonul „Copiere” ID dispozitiv pentru a partaja textul ID-ului. Dacă ne uităm în jurul codului sursă, vom observa că butonul Copiere ID dispozitiv (device_copy) onClick evenimentul este gestionat de o clasă anonimă în src-cfr/makeinfo/com/getid/MainActivity.java. Deși l-am putea modifica aici, de obicei este mai bine să găsim o modalitate alternativă de a face acest lucru, deoarece clasele anonime au nume numerice (MainClassName$ SomeNumber, de exemplu. Activitate principală $3) care s-ar putea schimba în mod imprevizibil între versiuni.

În schimb, vom înregistra propria noastră clasă pentru eveniment prin modificarea Activitate principala clasă. Mai întâi, să copiem versiunea „schelet” din src-cfr-nocode/makeinfo/com/getid/MainActivity.java la src/makeinfo/com/getid/MainActivity.java (sa nu uiti asta src este locul unde va locui patch-ul nostru). (De asemenea, puteți copia versiunea cu codul complet, dacă preferați, aceasta este doar o chestiune de gust.)

Acum îl putem edita după cum urmează:

  • Adăugați importul necesar pentru adnotarea DexPatcher:
importlanchon.dexpatcher.annotation.*;
  • Adăugați o etichetă pentru a indica că edităm clasa. Am setat, de asemenea, acțiunea implicită pentru membrii clasei de corecție IGNORA, ceea ce înseamnă că membrii sunt acolo pentru a fi referiți de codul nostru în timpul compilării Java, dar vor fi ignorați de 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{

  • În plus, adăugați corpuri goale la constructor și onCreate metoda, precum și toate celelalte metode pe care intenționăm să le folosim (rețineți că acestea vor fi ignorate atunci când patch-ul nostru este aplicat efectiv -- le adăugăm doar ca să ne putem referi la ele aici dacă este nevoie). De asemenea, puteți adăuga pur și simplu nativ cuvânt cheie în schimb.
  • Putem construi deja patch-ul în acest moment, dacă sunteți curios:
    $ dxp-make # Output: `patched.apk`.
    Destul de simplu, nu? Să continuăm, totuși -- încă nu am terminat.
  • Hai să edităm onCreate acum să pornesc singur OnClickListener astfel încât să putem partaja ID-ul dispozitivului în loc să-l copiem în clipboard:
    // 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();}}}
  • Se pare că am terminat acum! Plasturele complet ar trebui să arate ca acest. Acum putem construi APK-ul corectat și îl putem instala:
    $ dxp-make$ adb install patched.apk
  • Să ne uităm la rezultat:

(Mulțumim lui Lanchon pentru ajutor cu exemplul de cod!)

Xposed este extrem de popular și dintr-un motiv întemeiat - face construirea, partajarea și instalarea modurilor mult mai simplă pentru dezvoltatori și utilizatori deopotrivă. Există câteva diferențe între DexPatcher și Xposed care îi pot face pe unii să prefere unul față de celălalt:

  1. Xposed își face magia prin conectarea metodelor în timpul execuției și permițând dezvoltatorilor să facă ceva înainte, după sau în loc de orice metodă. DexPatcher, pe de altă parte, modifică totul înainte de rulare și produce un APK autonom, modificat -- rularea codului înainte, după sau în loc de metode este încă posibilă și, de fapt, aveți ceva în plus libertate.
  2. Producerea unui APK independent înseamnă că nu depinde de niciun cadru extern. Aceasta înseamnă, de asemenea, că root nu este necesar pentru modificarea aplicațiilor utilizatorului.
  3. Deoarece ați creat un nou APK cu DexPatcher, acesta va fi semnat diferit. Aceasta înseamnă că utilizatorii nu pot primi actualizări oficiale de la autorul original și pot cauza unele probleme cu aplicații precum Google Apps dacă semnăturile sunt verificate.
  4. Codul sursă atât al modulelor, cât și al patch-urilor DexPatcher poate fi ușor distribuit și modificat. De asemenea, au multe asemănări dacă vă familiarizați puțin cu fiecare.

Am vorbit destul despre DexPatcher. E rândul tău să încerci acum, așa că mergi la Subiect de forum DexPatcher pentru a începe imediat!