DexPatcher: Patchen Sie Android-APKs mit Java

Mit DexPatcher können Entwickler APKs mit Java patchen. Dies hat mehrere Vorteile und die Verwendung von DexPatcher ist viel einfacher als der klassische Smali-Ansatz.

Sie haben wahrscheinlich modifizierte Anwendungen gesehen oder installiert, sei es ein gepatchter Dialer für Ihre Auflösung oder eine benutzerdefinierte WhatsApp-Version mit zusätzlichen Funktionen. Aber wie machen Entwickler das? Oft ist der Quellcode der Anwendungen nicht einmal verfügbar. Wie funktioniert das Ganze? Wir werden uns das zuerst ansehen, dann einen Blick auf ein neues Tool werfen, das den Prozess viel einfacher machen soll, und es schließlich mit dem beliebten Xposed-Framework vergleichen, um zu sehen, wie sie sich unterscheiden.

Sie haben vielleicht schon davon gehört, wie APKs normalerweise modifiziert werden – Entwickler schließen sich an Matrix, beginnen Sie, alles auf Smali zu sehen, und erlangen Sie die Fähigkeit, Dinge mithilfe der Kraft der zu ändern Quelle. Sobald dies erledigt ist, genügt ein Anruf, um sie herauszuholen, und dann sind sie bereit, die glänzenden neuen APKs zu teilen.

Im Ernst: Fangen wir am Anfang an. Wenn Sie mit dem Modifizieren von Android-Anwendungen nicht vertraut sind, fragen Sie sich vielleicht, was Smali ist. Entwickler verwenden normalerweise die Programmiersprache Java, um Android-Apps zu programmieren. Ein Programm (der Compiler) „übersetzt“ diesen Code dann in ein anderes, für Ihr Gerät geeignetes Format, was zu .dex-Dateien führt, die im Anwendungspaket (oder APK) enthalten sind.

Ab diesem Zeitpunkt können Sie nicht mehr auf den ursprünglichen Quellcode zugreifen (es sei denn, Sie sind der Entwickler oder die Anwendung ist Open Source). Was Sie jedoch haben, ist das APK, da es auf Ihrem Gerät installiert ist. Von dort können Sie die Dex-Dateien (normalerweise „classes.dex“) abrufen und dann versuchen, sie wieder in ein für Sie verständliches Format zu übersetzen. Hier kommt Smali ins Spiel, als eine besser lesbare, aber getreue Übersetzung. Sie können noch einen Schritt weiter gehen und es zurück in Java übersetzen, obwohl dieser Prozess nicht zuverlässig genug ist – Sie erhalten eine Das Ergebnis ist verständlich, aber es besteht die Möglichkeit, dass Sie es nicht noch einmal andersherum übersetzen können, da einige Details verloren gehen nach dem Weg. Mit anderen Worten: Alle Änderungen, die Sie möglicherweise vornehmen, sind umsonst, da Sie es nicht wieder in ein APK umwandeln können, um es auf Ihrem Gerät zu installieren … zumindest nicht ohne großen Aufwand.

smali/baksmali ist eigentlich ein Assembler/Dissembler für das Dex-Format – das ist es, was es wörtlich auf Isländisch bedeutet. Normalerweise beziehen wir uns jedoch auf das Format, das smali versteht, wenn wir „Smali“ sagen (betrachten Sie es als Anweisungen). jedes noch so kleine Detail zu definieren, auch wenn es für uns Menschen nicht alles notwendig ist – es ist daher ausführlicher als Java). Beachten Sie auch, dass die obige Erklärung etwas vereinfacht ist, aber eine enge Analogie darstellen und dennoch leicht verständlich sein sollte.

Was müsste ein Entwickler dann tun, um eine App zu ändern (ohne Zugriff auf die Quelle)? Der Ablauf läuft mehr oder weniger wie folgt ab:

  1. Holen Sie sich die APK (aus dem Internet oder vom Gerät).
  2. Verwenden Sie so etwas wie apktool um die APK nach Smali zu dekompilieren. (apktool nutzt smali/baksmali, macht es aber viel einfacher, APKs zu dekompilieren und neu zu erstellen und kümmert sich auch um die Dekodierung von Ressourcen wie XML-Dateien.)
  3. Extrahieren Sie „classes.dex“ aus der APK und verwenden Sie es dann dex2jar und schließlich ein Java-Decompiler, um (unvollständigen, oft fehlerhaften, aber größtenteils verständlichen) Java-Code zu erhalten. (Dies ist optional, kann aber hilfreich sein, da Smali viel schwieriger zu verstehen ist.)
  4. Identifizieren Sie, was geändert werden soll.
  5. Ändern Sie es tatsächlich, indem Sie den Smali-Code direkt bearbeiten.
  6. Alternativ schreiben Sie die Änderung in Java, kompilieren sie, dekompilieren sie erneut nach Smali und kopieren dann den resultierenden Smali-Code.
  7. Sobald alles vorbei ist, verwenden Sie es apktool erneut, um die APK neu zu erstellen.
  8. Signieren Sie das APK (um die Identität des Autors zu überprüfen; Alle Pakete müssen signiert sein) und schließlich installieren.

Das Schreiben von Smali-Code ist ziemlich schwierig und fehleranfällig. In Smali können kleinere Änderungen vorgenommen werden, das Hinzufügen neuer Funktionen ist jedoch schwieriger. Darüber hinaus treten bei der Kompilierung keine Fehler auf, sodass selbst Tippfehler möglicherweise erst zur Laufzeit erkannt werden. Das Erweitern und Teilen von Smali-Patches kann ebenfalls problematisch sein, da Unterschiede in der Regel sehr spezifisch für eine bestimmte APK-Version sind. Obwohl es einige Tools gibt, die Teile des oben erläuterten Prozesses vereinfachen (Virtuous Ten Studio fällt mir ein), es kann immer noch ermüdend werden.

DexPatcher von XDA Senior Member Lanchon zielt darauf ab, diese Probleme zu beheben, indem der Prozess vereinfacht wird und es Entwicklern ermöglicht wird, den Umgang mit Smali vollständig zu vermeiden. Stattdessen können Entwickler Patches allein in Java schreiben und alles andere von DexPatcher erledigen lassen.

Dies hat den Hauptvorteil, dass die Patchdateien leicht lesbar und verwaltbar sind. Auch das Patchen von APKs wird im Allgemeinen komfortabler. Wir werden gleich ein vollständiges Beispiel für die Verwendung von DexPatcher sehen, aber hier ist zunächst ein kurzer Überblick darüber, was es bietet:

  • Open Source.
  • Plattformübergreifend: Es sollte auf Linux, Mac und Windows laufen.
  • Patchdateien: Von Ihnen vorgenommene Änderungen sind in Java-Patchdateien enthalten, die Sie unabhängig weitergeben können.
  • Java: Es ist nicht Smali.

Sie profitieren außerdem von der Fehlerprüfung während der Erstellung, sodass Fehler schon früh im Entwicklungszyklus auftauchen. Das kompilierte Java bietet die übliche Überprüfung der Kompilierungszeit (mit Zugriff auf die ursprünglichen APK-Symbole) und DexPatcher erzwingt dies Kompatibilität von Quelle und Patch beim Patchen, Bereitstellung hilfreicher Informationen und Warnungen, wenn Sie scheinbar etwas tun legal, aber faul.

Darüber hinaus wird DexPatcher mit einem Satz geliefert Hilfsskripte (nur unter Linux verfügbar, könnten jedoch auch auf andere Plattformen portiert werden). Diese kümmern sich um die Einrichtung des Arbeitsbereichs, das Extrahieren der Klassen und Ressourcen der Ziel-APK und die Dekompilierung der Klassen nach Java (die CFR Java-Decompiler wird für Letzteres verwendet) und schließlich das Erstellen und Signieren der gepatchten APK, sobald Sie fertig sind.

Schauen wir uns ein Beispiel an (unter Linux):

Installieren Sie die DexPatcher-Skripte

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

Konfigurieren Sie die DexPatcher-Skripte

Offen dxp.config in Ihrem bevorzugten Texteditor und stellen Sie sicher, dass Sie die erforderlichen Variablen an Ihr System anpassen. Sie müssen lediglich die folgende Zeile ändern, um stattdessen auf den Installationsort Ihres Android SDK zu verweisen:

dxp_android_sdk_dir=(~/android/sdk)

(DexPatcher wählt automatisch die höchste verfügbare Plattformversion aus. Darüber hinaus können Sie auch andere Konfigurationsoptionen ändern, damit Ihre eigenen Versionen einiger Tools anstelle der mitgelieferten Standardeinstellungen verwendet werden.)

Um den Zugriff zu erleichtern, können wir Folgendes hinzufügen Depatcher Verzeichnis zu unserem WEG, oder sogar die anderen verknüpfen dxp-* Skripte an einen Speicherort, der sich bereits in Ihrem befindet WEG, wie zum Beispiel ~/bin:

export PATH=$PWD:$PATH

Ändern Sie eine Anwendung

Für dieses Beispiel verwenden wir eine einfache Open-Source-Anwendung. Natürlich wäre in diesem speziellen Fall ein direktes Patchen des Quellcodes möglich, aber das macht überhaupt keinen Spaß!

Wir nehmen die Anwendung „Get ID“ von basil2style, eine Anwendung, die Ihnen einige Details zu Ihrem Gerät anzeigt. Unser Ziel ist es, die Schaltfläche „Kopieren“ für die „Geräte-ID“ zu ändern und stattdessen diese ID gemeinsam zu nutzen:

  • Laden wir zunächst die APK herunter, die wir ändern möchten: Holen Sie sich einen Ausweis.
  • Dekompilieren Sie die Anwendung.
  • Erstellen Sie den Signaturschlüssel, den wir später zum Signieren des APK verwenden.

Wir können das alles auch über die Shell erledigen, indem wir die Hilfsskripte verwenden:

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

Sie werden dort einige verschiedene Verzeichnisse bemerken:

  • dekodieren: Hier finden Sie die Ressourcen und Smali, wie von dekodiert apktool.
  • src: Leeres Verzeichnis. Hier werden wir unsere Patchdateien ablegen.
  • src-cfr: das ist wo cfr dekompilierte die App (zusammen mit Fehlern). Ein guter Ort, um zu entscheiden, was geändert werden soll (möglicherweise benötigen Sie auch Ressourcen und ihre IDs aus dem Decodierungsverzeichnis oben, aber nicht für dieses spezielle Beispiel).
  • src-cfr-nodecode: wie oben, enthält aber nur leere Stubs (kein Code, nur Skelette). Sie können diese Dateien als Grundlage für Ihren Patch verwenden, wie wir gleich sehen werden.

Wie bereits erwähnt, möchten wir die Schaltfläche „Kopieren“ der Geräte-ID ändern, um stattdessen den ID-Text freizugeben. Wenn wir uns den Quellcode ansehen, werden wir feststellen, dass die Schaltfläche „Geräte-ID kopieren“ (Gerätekopie) onClick Das Ereignis wird von der anonymen Klasse in verarbeitet src-cfr/makeinfo/com/getid/MainActivity.java. Obwohl wir es hier modifizieren könnten, ist es normalerweise besser, einen alternativen Weg zu finden, da anonyme Klassen numerische Namen haben (MainClassName$SomeNumber, z.B. Hauptaktivität$3), die sich zwischen den Versionen unvorhersehbar ändern kann.

Stattdessen registrieren wir unsere eigene Klasse für das Ereignis, indem wir die ändern Hauptaktivität Klasse. Kopieren wir zunächst die „Skelett“-Version von src-cfr-nocode/makeinfo/com/getid/MainActivity.java Zu src/makeinfo/com/getid/MainActivity.java (erinnere dich daran src dort wird unser Patch leben). (Sie können auch die Version mit dem vollständigen Code kopieren, wenn Sie möchten, das ist reine Geschmackssache.)

Wir können es nun wie folgt bearbeiten:

  • Fügen Sie den erforderlichen Import für die DexPatcher-Annotation hinzu:
importlanchon.dexpatcher.annotation.*;
  • Fügen Sie ein Tag hinzu, um anzugeben, dass wir die Klasse bearbeiten. Wir legen außerdem die Standardaktion für Mitglieder der Patch-Klasse auf fest IGNORIEREN, was bedeutet, dass die Member dazu da sind, von unserem Code während der Java-Kompilierung referenziert zu werden, aber von DexPatcher ignoriert werden.
@DexEdit(defaultAction=DexAction.IGNORE)

publicclassMainActivity

// The reference to ActionBarActivity will be satisfied by symbols

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

extendsActionBarActivity{

  • Fügen Sie dem Konstruktor außerdem leere Körper hinzu und onCreate -Methode sowie alle anderen Methoden, die wir verwenden möchten (denken Sie daran, dass sie ignoriert werden, wenn unser Patch tatsächlich angewendet wird – wir fügen sie nur hinzu, damit wir hier bei Bedarf darauf verweisen können). Sie können das auch einfach hinzufügen einheimisch Schlüsselwort stattdessen.
  • Wir können den Patch zu diesem Zeitpunkt bereits erstellen, falls Sie neugierig sind:
    $ dxp-make # Output: `patched.apk`.
    Ziemlich einfach, oder? Aber machen wir weiter – wir sind noch nicht fertig.
  • Lassen Sie uns bearbeiten onCreate Jetzt machen wir uns auf den Weg OnClickListener damit wir die Geräte-ID teilen können, anstatt sie in die Zwischenablage zu kopieren:
    // 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();}}}
  • Sieht so aus, als wären wir jetzt fertig! Der vollständige Patch sollte so aussehen Das. Wir können jetzt das gepatchte APK erstellen und installieren:
    $ dxp-make$ adb install patched.apk
  • Werfen wir einen Blick auf das Ergebnis:

(Danke an Lanchon für die Hilfe beim Beispielcode!)

Xposed erfreut sich großer Beliebtheit, und das aus gutem Grund: Es macht das Erstellen, Teilen und Installieren von Mods für Entwickler und Benutzer gleichermaßen viel einfacher. Es gibt einige Unterschiede zwischen DexPatcher und Xposed, die einige dazu veranlassen könnten, das eine dem anderen vorzuziehen:

  1. Xposed entfaltet seinen Zauber, indem es Methoden zur Laufzeit einbindet und es Entwicklern ermöglicht, vor, nach oder anstelle einer Methode etwas zu tun. DexPatcher hingegen ändert alles vor der Laufzeit und erstellt ein eigenständiges, modifiziertes APK – Das Ausführen von Code vor, nach oder anstelle von Methoden ist weiterhin möglich, und Sie haben tatsächlich einige Extras Freiheit.
  2. Durch die Erstellung einer eigenständigen APK ist diese nicht von einem externen Framework abhängig. Dies bedeutet auch, dass zum Ändern von Benutzer-Apps kein Root erforderlich ist.
  3. Da Sie mit DexPatcher ein neues APK erstellt haben, wird es anders signiert. Dies bedeutet, dass Benutzer keine offiziellen Updates vom ursprünglichen Autor erhalten können und es bei der Überprüfung der Signaturen zu Problemen mit Apps wie Google Apps kommen kann.
  4. Der Quellcode sowohl der Module als auch der DexPatcher-Patches kann einfach verteilt und geändert werden. Sie haben auch viele Gemeinsamkeiten, wenn Sie sich ein wenig mit ihnen vertraut machen.

Wir haben genug über DexPatcher gesprochen. Jetzt sind Sie an der Reihe, es auszuprobieren, also gehen Sie rüber zum DexPatcher-Forum-Thread um sofort loszulegen!