2024-11-25
Table of Contents
Einführung
Android Apps können in Kotlin, Java oder C++ geschrieben und in einem Android Package (APK) oder Android App Bundle kompiliert werden (Google, 2023). Eine APK ist eine Archivdatei, die alle Inhalte beinhaltet, die von einer Android App während der Laufzeit benötigt werden. Ähnlich wie bei ZIP- und RAR-Archivdateien kann auch eine APK ohne großen Aufwand entpackt werden. Der Java Decompiler JD-GUI kann verwendet werden, um den Java Byte Code einer App zu analysieren und anzuzeigen (Dupuy, 2019). Das Problem dabei ist, dass die Android-Entwicklung sich immer mehr von Java wegbewegt und auch die APK-Inhalte immer weniger Java Code beinhalten (Menge-Sonnentag, 2022). An dieser Stelle kommen spezifisch für APK entwickelte Decompiler wie JADX und ApkTool ins Spiel, welche die in den APK enthaltenen Dalvik Executables (DEX)-Dateien zu lesbarem Programmcode dekompilieren können. Diese DEX-Dateien werden aus dem kompilierten Java-Bytecode konvertiert und können dann von der Android Runtime ausgeführt werden (Google, 2024). Sowohl JADX als auch ApkTool werden Stand Juli 2024 aktiv weiterentwickelt und funktionieren damit bei den meisten Apps ohne Komplikationen. Durch verschiedene Verschleierungstechniken können Klassen, Variablen und Funktionsnamen von denen im originalen Quellcode abweichen. Sie können sich ebenfalls zwischen den verschiedenen Appversionen unterscheinen.
Dex zu Java decompiling mit JADX
JADX ist ein Dex zu Java decompiler, der aus den Android Dex-Dateien in der APK lesbaren Java Programmcode produziert (skylot, Dex to Java decompiler, 2024).
Die aktuelle Version kann einfach von GitHub unter https://github.com/skylot/jadx/releases/latest heruntergeladen werden und beinhaltet die CLI- und GUI-Version von JADX (skylot, Releases, 2024). Die GUI kann mit dem Öffnen der JAR gestartet werden. Wer jedoch eine andere Java IDE wie IntelliJ verwenden will oder lediglich den Java-Programmcode zur weiteren Verarbeitung benötigt, kann das CLI-Tool mit dem Befehl jadx -d app app.apk
verwenden, bei dem das Argument -d
den Ausgabeordner definiert.
Android Apps liegen im APK-Format vor und können neben dem Google Play Store auch von anderen Plattformen heruntergeladen werden.
Ein Beispiel ist die Plattform APKMirror.
Anschließend kann die APK mit JADX mit jadx -d app com.app.apk
in lesbaren Java Code übersetzt und das Projekt in einer IDE wie Android Studio zum Analysieren geöffnet werden.
Java Code ist hingegen der Smali repräsentation des Programmcodes einfacher lesbar.
Dex zu Smali decompiling mit ApkTool
Das ApkTool dekompiliert APK-Dateien in die Intermediate Sprache Smali (Tumbleson, iBotPeaches/Apktool, 2024). Dadurch wird es möglich, Änderungen im Programmcode vorzunehmen und diese dann wieder zu einer APK zu kompilieren. Die Installation des ApkTools wird im Installationsguide unter https://apktool.org/docs/install erklärt (Tumbleson, Install Guide, 2024). Um das Werkzeug auf Linux zu installieren, muss ein Wrapperscript und die aktuelle ApkTool-Version heruntergeladen werden.
~ mkdir /opt/apktool
~ wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool -P /opt/apktool
~ wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.9.3.jar -O /opt/apktool/apktool.jar
~ chmod +x /opt/apktool/apktool
Im nächsten Schritt kann die APK-Datei mit dem Befehl apktool d app.apk
dekompiliert werden. Wenn Komplikationen beim Kompilieren der APK-Datei auftreten, kann es helfen, das Argument -r
anzuhängen, wodurch die Ressourcen nicht mit dekompiliert werden. Auch helfen kann es, den Dekompilierungsmodus „fallback“ mit dem Argument -m fallback
zu verwenden, damit der Programmcode und die Instruktionen so wenig wie möglich verändert werden.
Nachdem die Veränderungen am Programmcode vorgenommen wurden, muss der Programmcode mit apktool b -o repackaged.apk app
im Ordner app kompiliert werden, sodass die APK als repackaged.apk
in den aktuellen Ordner geschrieben wird.
Anschließend muss die APK neu signiert werden, bevor sie auf einem Gerät installiert werden kann. Dafür kann das Tool uber-apk-signer verwendet werden, welches dabei hilft, APK-Dateien mit Debug oder mit zur Verfügung gestellten Release Zertifikaten zu signieren, zu ZIP alignen und zu verifizieren (Favre, patrickfav/uber-apk-signer, 2023). Dafür muss die entsprechende JAR-Datei von GitHub unter https://github.com/patrickfav/uber-apk-signer/releases/latest heruntergeladen und mit java -jar uber-apk-signer-1.3.0.jar –apks repackaged.apk
ausgeführt werden (Favre, patrickfav/uber-apk-signer: Releases, 2023). Das Tool erzeugt nach dem ausführen des Befehls die Dateien repackaged-aligned-debugSigned.apk
und repackaged10-aligned-debugSigned.apk.idsig
. Mit adb install repackaged-aligned-debugSigned.apk
kann dann die APK auf dem Smartphone installiert werden kann.
Function hooking mit Frida
Frida ist ein dynamisches Instrumentierungs-Toolkit für Entwickler, Reverse-Engineers und Sicherheitsforscher.
Es ermöglicht JavaScript Snippets in native Windows, macOS, GNU/Linux, iOS, watchOS, tvOS, Android, FreeBSD und QNX-Anwendungen zu injizieren, um Anwendungslogiken besser nachvollziehen
zu können (Ravnås, 2024).
Die CLI-Tools von Frida können mit PyPI über pip3 install frida-tools
installiert werden.
Mit administrativen Berechtigungen auf einem Android Smartphone ist es mit Frida möglich, über USB in eine laufende App Code zu injizieren.
Die Berechtigungen können dann z. B. durch das Rooten des Geräts erlangt werden.
Da für diese Arbeit kein Gerät mit solchen Berechtigungen vorliegt, kann alternativ ein sogenanntes frida-gadget in die App eingebunden werden.
Dieses ermöglicht es, remote mit der App zu kommunizieren, wofür es wiederum folgende zwei Optionen gibt:
Die erste Option ist, zuerst die APK mit Hilfe des ApkTools zu dekompilieren.
Anschließend kann die Frida Gadget Binary von GitHub heruntergeladen und in dem Verzeichnis lib/arm64-v8a
als libfrida-gadget-16.4.7-android-arm64.so
abgelegt werden.
Den Dateipfad der MainActivity, die beim Starten der App als erstes geladen wird, kann mithilfe der AndroidManifest.xml
Datei ermittelt werden.
In der AndroidManifest.xml
Datei, die im Hauptverzeichnis der App liegt, ist die MainActivity unter application->activity
in der Regel als erstes Element registriert.
Nachdem der Dateipfad ermittelt wurde, kann in der MainActivity-Datei nach der onCreate
oder als Alternative nach der <init>
Methode gesucht werden.
In einer der beiden Methoden ist anschließend nach der Zeile .locals X
der folgende Code einzufügen, der das Frida Gadget lädt, sobald die App gestartet wird:
const-string v0, " libfrida-gadget-16.4.7-android-arm64.so"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
Anschließend muss sichergestellt werden, dass die App über die notwendigen Berechtigungen für eine Internetverbindung verfügt. Sobald das sichergestellt ist, kann der Programmcode der App zu einer APK kompiliert und diese signiert werden.
Die zweite Option besteht darin, das Gadget automatisch mit einem Tool wie ksg97031/frida-gadget (KSG, 2024) in die App zu injizieren.
Diese Methode ist zwar simpler, aber auch fehleranfälliger, falls die App über irgendwelche Besonderheiten verfügt.
Das Programm frida-gadget kann mit pip3 install frida-gadget
installiert werden.
Mit dem Befehl frida-gadget app.apk –arch arm64 --sign
führt das Skript die in der ersten Option beschriebenen Schritte eigenständig aus, kompiliert eine neue APK und signiert sie.
Die generierte APK befindet sich danach im Ordner app/dist/app-aligned-debugSigned.apk
.
Anschließend kann die App regulär mit ADB installiert und nach dem Starten die Verbindung zum Gadget mit dem Befehl frida-trace -U App
aufgebaut werden.
Die Option -U
beschreibt, dass es sich um eine USB-Verbindung handelt und „App“ ist der Name der App.
Frida kann nun verwendet werden, um einzelne Funktionen in der Android App zu überschreiben oder Informationen wie Secrets oder Strack Traces auszugeben.
Auslesen von Android Application Data
Android Apps können ihre Daten, wie beispielsweise Konfigurationsdateien, Logs, Datenbanken oder sonstige Ressourcen, entweder in einem welt-lesbar („world-readable“) Format ablegen oder
standardmäßig als nicht welt-lesbar („not world-readable“) ablegen (Google LLC, 2024).
Nur das welt-lesbar Format ermöglicht es die Daten mit einem USB-Kabel auszulesen. Wenn die Daten nicht welt-lesbar sind, können sie nicht ohne vorherige Schritte ausgelesen
werden (Google LLC, 2024). Dementsprechend kann beispielsweise der Befehl adb pull /data/data/com.app/data.txt
nicht verwendet werden.
Der Befehl adb shell "run-as com.app cat /data/data/com.app/data.txt > /sdcard/Downloads/data.txt"
ermöglicht es jedoch, auf die Dateien im Namen der App zuzugreifen und diese auf ein anderes Speichermedium zu schreiben.
Von dort aus können die Dateien dann mit adb pull /sdcard/Downloads/data.txt
heruntergeladen werden.
Wenn keine SD-Karte im Smartphone vorhanden ist, kann der Befehl adb exec-out "run-as com.app cat /data/data/com.app/data.txt" > data.txt
verwendet werden, um die Daten aus der Datei in das aktuelle Verzeichnis auf
dem Computer in die Datei data.txt
zu schreiben.
Java Native Interface in Android Apps
In Java-Umgebungen muss nicht nur Java-Programmcode geschrieben werden.
Die Technologie Java Native Interface (JNI) ermöglicht es C oder C++ Code in die Anwendung zu laden.
Das kann beispielsweise hilfreich sein, wenn Java ein spezifisches Feature oder eine Bibliothek nicht unterstützt.
Nachdem eine Funktion im Java Code ohne Funktionskörper definiert wurde, kann in C++ eine Funktion mit dem in Java verwendeten Paket, Klassen und Funktionsnamen definiert werden (Saraf, 2022):
Java_com_package_name_MainClass_printFunction(JNIEnv *, jobject thisObject);
Sobald Parameter an die Funktion übergeben werden, werden sie einfach an die von JNI geforderten Parameter angehängt:
Java_com_package_name_MainClass_printFunction(JNIEnv *, jobject thisObject, jstring message);
Quellen
- Google - Application fundamentals | Android Developers - 10.10.2023 - https://developer.android.com/guide/components/fundamentals
- Dupuy, Emmanuel - Java Decompiler - 2019 - https://java-decompiler.github.io/
- Menge-Sonnentag, Rainald - Heise: Von Java nach Kotlin: Meta berichtet von zehn Millionen Codezeilen - 28.10.2022 - https://www.heise.de/news/Von-Java-nach-Kotlin-Meta-berichtet-von-zehn-Millionen-Codezeilen-7323083.html
- Google - Android runtime and Dalvik - 29.04.2024 - https://source.android.com/docs/core/runtime
- skylot - skylot/jadx: Dex to Java decompiler - 2024 - https://github.com/skylot/jadx
- skylot - skylot/jadx: Releases - 2024 - https://github.com/skylot/jadx/releases/latest
- Tumbleson, Connor - iBotPeaches/Apktool: A tool for reverse engineering Android apk files - 2024 - https://github.com/iBotPeaches/Apktool
- Tumbleson, Connor - Install Guide - 2024 - https://apktool.org/docs/install
- Favre, Patrick - patrickfav/uber-apk-signer - 2023 - https://github.com/patrickfav/uber-apk-signer
- Favre, Patrick - patrickfav/uber-apk-signer: Releases - 2023 - https://github.com/patrickfav/uber-apk-signer/releases/latest
- Ravnås, Ole André Vadla - Frida - A world-class dynamic instrumentation toolkit - 2024 - https://frida.re/
- KSG - ksg97031/frida-gadget: Automated tool for patching APKs to enable the use of Frida gadget - 2024 - https://github.com/ksg97031/frida-gadget
- Google LLC - Data and file storage overview - 2024 - https://developer.android.com/training/data-storage
- Google LLC - Android Debug Bridge (adb) - 2024 - https://developer.android.com/tools/adb
- Saraf, Anshul - JNI-101 — Introduction to Java Native Interface - 2022 - https://medium.com/@sarafanshul/jni-101-introduction-to-java-native-interface-8a1256ca4d8e