DexPatcher: Patch Android APK-er ved hjelp av Java

DexPatcher lar utviklere lappe APK-er ved hjelp av Java. Dette har flere fordeler, og å bruke DexPatcher er mye enklere enn den klassiske Smali-tilnærmingen.

Du har sannsynligvis sett eller installert modifiserte applikasjoner, enten det er en lappet dialer for oppløsningen din eller en tilpasset WhatsApp-versjon med ekstra funksjoner. Men hvordan gjør utviklere det? Mye av tiden er ikke applikasjonens kildekode engang tilgjengelig, så hvordan fungerer det hele? Vi skal se det først, så ta en titt på et nytt verktøy som tar sikte på å gjøre prosessen mye enklere, og til slutt sammenligne det med det populære Xposed-rammeverket for å se hvordan de skiller seg.

Du har kanskje hørt om hvordan APK-er vanligvis modifiseres - utviklere kobler seg til matrise, begynn å se alt på smali, og få muligheten til å endre ting ved å bruke kraften til Kilde. En telefonsamtale er nok til å få dem ut når det er gjort, og da er de klare til å dele de skinnende nye APK-ene.

Mer seriøst... La oss starte med begynnelsen. Hvis du ikke er kjent med modding av Android-applikasjoner, lurer du kanskje på hva smali er. Utviklere bruker vanligvis programmeringsspråket Java til å kode Android-apper i. Et program (kompilatoren) "oversetter" deretter koden til et annet format som passer for enheten din, noe som resulterer i .dex-filer inne i applikasjonspakken (eller APK).

På det tidspunktet har du ikke lenger tilgang til den originale kildekoden (med mindre du er utvikleren eller applikasjonen er åpen kildekode). Det du imidlertid har er APK, siden det er det som er installert på enheten din. Fra den kan du hente dex-filene (vanligvis classes.dex) og deretter prøve å oversette den tilbake til et format du kan forstå. Det er her smali kommer inn, som en mer lesbar, men trofast oversettelse. Du kan gå ett skritt videre og oversette det tilbake til Java, selv om den prosessen ikke er trofast nok -- du vil få en forståelig resultat, men sjansene er store for at du ikke vil være i stand til å oversette det omvendt igjen da noen detaljer vil gå tapt langs veien. Med andre ord, eventuelle endringer du kan gjøre vil være for intet siden du ikke vil kunne gjøre den om til en APK igjen for å installere den på enheten din... i hvert fall ikke uten mye innsats.

smali/baksmali er faktisk en assembler/dissembler for dex-formatet -- det er det det bokstavelig talt betyr på islandsk. Imidlertid refererer vi vanligvis til formatet smali forstår når vi sier 'Smali' (tenk på det som instruksjoner definere hver minste detalj, selv om det ikke er alt som trengs av oss mennesker -- det er derfor mer detaljert enn Java). Vær også oppmerksom på at forklaringen ovenfor er litt forenklet, men bør være en nær analogi samtidig som den er lett å forstå.

Hva må en utvikler gjøre for å endre en app (uten tilgang til kilden), da? Prosessen er mer eller mindre som følger:

  1. Få APK-en (fra nettet eller fra enheten).
  2. Bruk noe sånt som apktool for å dekompilere APK-en til Smali. (apktool bruker smali/baksmali, men gjør det mye enklere å dekompilere og gjenoppbygge APK-er, og tar seg også av dekodingsressurser som XML-filer.)
  3. Trekk ut classes.dex fra APK-en, og bruk deretter dex2jar og til slutt en Java-dekompiler for å få (ufullstendig, ofte ødelagt, men stort sett forståelig) Java-kode. (Dette er valgfritt, men kan være nyttig siden Smali er mye vanskeligere å forstå.)
  4. Identifiser hva som skal endres.
  5. Endre den faktisk ved å redigere Smali-koden direkte.
  6. Alternativt kan du skrive modifikasjonen i Java, kompilere den, dekompilere den igjen til Smali, og deretter kopiere den resulterende Smali-koden over.
  7. Når alt er over, bruk apktool igjen for å gjenoppbygge APK.
  8. Signer APK-en (for å bekrefte identiteten til forfatteren; alle pakker må signeres) og til slutt installere den.

Å skrive Smali-kode er ganske vanskelig og utsatt for feil. Mindre endringer kan gjøres på Smali, men å legge til nye funksjoner med det er mer utfordrende. I tillegg vil du ikke ha noen kompileringstidsfeil, så selv skrivefeil kan bare oppdages under kjøring. Utvidelse og deling av Smali-patcher kan også være plagsomt, ettersom differ har en tendens til å være veldig spesifikke for en bestemt APK-versjon. Selv om det finnes noen verktøy for å gjøre deler av prosessen forklart ovenfor enklere (Virtuous Ten Studio kommer til tankene), kan det fortsatt bli slitsomt.

DexPatcher av XDA seniormedlem Lanchon tar sikte på å fikse disse problemene ved å gjøre prosessen enklere og la utviklere helt unngå å håndtere Smali. I stedet kan utviklere skrive patcher i Java alene og la DexPatcher håndtere alt annet.

Dette har den største fordelen av å ha lett lesbare og håndterbare oppdateringsfiler. Patching av APK-er blir også mer praktisk generelt. Vi vil se et fullstendig eksempel på hvordan du bruker DexPatcher om litt, men her er en rask oversikt over hva den tilbyr først:

  • Åpen kilde.
  • Cross-platform: den skal kjøre på Linux, Mac og Windows.
  • Patch-filer: endringer du gjør er inneholdt i Java-patch-filer du kan dele uavhengig.
  • Java: det er ikke Smali.

Du får også fordelen av feilkontroll under byggetid, så feil dukker opp tidlig i utviklingssyklusen. Java-kompileringen gir sin vanlige kompileringstidskontroll (med tilgang til de originale APK-symbolene), og DexPatcher håndhever kompatibilitet av kilde og oppdatering ved oppdatering, gir nyttig informasjon og advarsler når du ser ut til å gjøre noe lovlig men fishy.

I tillegg til det kommer DexPatcher med et sett med hjelpeskript (kun tilgjengelig på Linux, selv om de kan overføres til andre plattformer også). Disse tar seg av å sette opp arbeidsområdet, trekke ut mål-APKs klasser og ressurser, dekompilere klassene til Java (den CFR Java-dekompilator brukes til sistnevnte), og til slutt bygger og signerer den lappede APK-en når du er ferdig.

La oss ta en titt på et eksempel (på Linux):

Installer DexPatcher-skriptene

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

Konfigurer DexPatcher-skriptene

Åpen dxp.config i favoritttekstredigeringsprogrammet ditt, og sørg for å endre de nødvendige variablene for å passe til systemet ditt. Du trenger bare å endre følgende linje for å peke til Android SDK-ens installasjonssted i stedet:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher vil automatisk velge den høyeste tilgjengelige plattformversjonen. I tillegg kan du også endre andre konfigurasjonsalternativer for å få den til å bruke dine egne versjoner av noen verktøy i stedet for de medfølgende standardinnstillingene.)

For enkel tilgang kan vi legge til dexpatcher katalog til vår STI, eller til og med symlink de forskjellige dxp-* skript til en plassering som allerede er på din STI, som for eksempel ~/bin:

export PATH=$PWD:$PATH

Endre en applikasjon

For dette eksempelet bruker vi en enkel og åpen kildekode-applikasjon. Selvfølgelig ville det vært mulig å lappe kildekoden direkte i dette tilfellet, men det er ikke noe moro i det hele tatt!

Vi tar "Få ID"-applikasjonen fra basil2style, en applikasjon som viser deg noen detaljer om enheten din. Målet vårt er å endre "Kopier"-knappen for "Enhets-ID" og få den til å dele denne ID-en i stedet:

  • Først, la oss laste ned APK-en vi skal endre: Få ID.
  • Dekompiler applikasjonen.
  • Lag signeringsnøkkelen som vi senere skal bruke til å signere APK-en.

Vi kan også gjøre alt via skallet, ved å bruke hjelpeskriptene:

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

Du vil legge merke til noen forskjellige kataloger der inne:

  • dekode: du finner ressursene og Smali her, som dekodet av apktool.
  • src: Tøm katalog. Det er her vi plasserer patchfilene våre.
  • src-cfr: dette er hvor jfr dekompilerte appen (sammen med feil). Et godt sted å se for å bestemme hva som skal endres (du kan også trenge ressurser og deres IDer fra dekodekatalogen ovenfor, men ikke for dette spesielle eksemplet).
  • src-cfr-nodekode: samme som ovenfor, men inneholder bare tomme stubber (ingen kode, bare skjeletter). Du kan bruke disse filene som grunnlag for oppdateringen din, som vi vil se om litt.

Som vi har nevnt før, ønsker vi å endre enhets-ID "Kopier"-knappen for å dele ID-teksten i stedet. Hvis vi ser rundt i kildekoden, vil vi legge merke til at Device ID Copy-knappen (device_copy) ved trykk hendelsen håndteres av anonym klasse i src-cfr/makeinfo/com/getid/MainActivity.java. Selv om vi kunne endre det her, er det vanligvis bedre å finne en alternativ måte å gjøre det på, da anonyme klasser har numeriske navn (MainClassName$SomeNumber, f.eks. MainActivity$3) som kan endre seg uforutsigbart mellom versjoner.

I stedet vil vi registrere vår egen klasse for arrangementet ved å endre Hoved aktivitet klasse. Først, la oss kopiere "skjelett"-versjonen fra src-cfr-nocode/makeinfo/com/getid/MainActivity.java til src/makeinfo/com/getid/MainActivity.java (Husk at src er der lappen vår vil bo). (Du kan også kopiere versjonen med hele koden hvis du foretrekker det, dette er bare en smakssak.)

Vi kan nå redigere den som følger:

  • Legg til nødvendig import for DexPatcher-kommentaren:
importlanchon.dexpatcher.annotation.*;
  • Legg til en tag for å indikere at vi redigerer klassen. Vi setter også standardhandlingen for medlemmer av patchklassen til OVERSE, som betyr at medlemmene er der for å bli referert av koden vår under Java-kompilering, men vil bli ignorert av 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{

  • I tillegg legger du til tomme kropper til konstruktøren og påOpprett metode, så vel som alle andre metoder vi planlegger å bruke (husk at de vil bli ignorert når oppdateringen vår faktisk er brukt -- vi legger dem bare til slik at vi kan referere til dem her hvis vi trenger det). Du kan også bare legge til innfødt søkeord i stedet.
  • Vi kan allerede bygge oppdateringen på dette tidspunktet, hvis du er nysgjerrig:
    $ dxp-make # Output: `patched.apk`.
    Ganske enkelt, ikke sant? La oss imidlertid fortsette – vi er fortsatt ikke ferdige ennå.
  • La oss redigere påOpprett nå for å sette ut egen OnClickListener slik at vi kan dele enhets-ID-en i stedet for å kopiere den til utklippstavlen:
    // 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();}}}
  • Ser ut som vi er ferdige nå! Hele lappen skal se ut dette. Vi kan nå bygge den lappede APK-en og installere den:
    $ dxp-make$ adb install patched.apk
  • La oss ta en titt på resultatet:

(Takk til Lanchon for hjelpen med prøvekoden!)

Xposed er umåtelig populært, og av en god grunn - det gjør det mye enklere å bygge, dele og installere mods for utviklere og brukere. Det er noen få forskjeller mellom DexPatcher og Xposed som kan gjøre at noen foretrekker den ene fremfor den andre:

  1. Xposed gjør sin magi ved å koble metoder under kjøring og la utviklere gjøre noe før, etter eller i stedet for hvilken som helst metode. DexPatcher, derimot, modifiserer alt før kjøretid og produserer en frittstående, modifisert APK -- Å kjøre kode før, etter eller i stedet for metoder er fortsatt mulig, og du har faktisk litt ekstra frihet.
  2. Å produsere en frittstående APK betyr at den ikke er avhengig av noe eksternt rammeverk. Dette betyr også at root ikke er nødvendig for å endre brukerapper.
  3. Siden du har opprettet en ny APK med DexPatcher, blir den signert annerledes. Dette betyr at brukere ikke kan motta offisielle oppdateringer fra den opprinnelige forfatteren, og kan forårsake noen problemer med apper som Google Apps hvis signaturene er sjekket.
  4. Kildekoden til både moduler og DexPatcher-patcher kan enkelt distribueres og endres. De deler også mange likheter hvis du blir litt kjent med hver.

Vi har snakket nok om DexPatcher. Det er din tur til å prøve det nå, så gå over til DexPatcher-forumtråd for å komme i gang med en gang!