JADX-GUI
Android-APKs dekompilieren und BLE-Logik aufdecken
Was ist JADX-GUI und wofür brauchst du es?
JADX-GUI wandelt kompilierten Android-Bytecode (.dex-Dateien aus einer APK) zurück in lesbares Java. Das Ergebnis ist kein perfekter Quellcode — Variablennamen gehen verloren, manche Konstrukte werden anders dargestellt — aber es reicht vollständig aus, um die Programmlogik zu verstehen. Für BLE-Sicherheitsanalysen ist JADX-GUI das erste Werkzeug, das du anfasst: Es deckt auf, welche UUIDs eine App verwendet, ob und wie sie verschlüsselt, wo sie writeCharacteristic() aufruft, und ob kryptografische Schlüssel direkt im Java-Code stehen oder in eine native Bibliothek ausgelagert wurden. Oft lässt sich in JADX innerhalb von Minuten feststellen, ob ein Gerät hardcodierte Schlüssel hat oder ob sich die Analyse in Richtung Ghidra bewegen muss.
Installation
Linux
Die meisten Distributionen haben JADX nicht in ihren offiziellen Paketquellen, oder die Version ist veraltet. Empfohlen: direkt von GitHub herunterladen.
# Direkter Download (Version 1.5.3)
wget https://github.com/skylot/jadx/releases/download/v1.5.3/jadx-1.5.3.zip
unzip jadx-1.5.3.zip -d ~/.local/jadx
export PATH="$PATH:$HOME/.local/jadx/bin"
# Danach dauerhaft in Shell-Profil eintragen:
echo 'export PATH="$PATH:$HOME/.local/jadx/bin"' >> ~/.bashrc
# Starten
jadx-guiAuf Debian/Ubuntu-Systemen gibt es auch ein Community-Paket, aber prüfe die Version:
sudo apt install jadx
jadx --version # Sollte 1.5.x oder neuer seinmacOS
brew install jadx
jadx-guiWindows
jadx-1.5.3.zipvon github.com/skylot/jadx/releases herunterladen- In ein Verzeichnis deiner Wahl entpacken, z. B.
C:/Tools/jadx/ bin/jadx-gui.batausführen — kein Installer nötig
Java-Version
JADX benötigt Java 11 oder neuer. Prüfe mit java -version. Falls nicht vorhanden: OpenJDK von adoptium.net herunterladen. Auf macOS erledigt brew install jadx die Java-Abhängigkeit automatisch.
Erste Schritte — BLE-Beispiel: LED-Brille
Als konkretes Beispiel dient die App der LED-Brille: com.pinkysinyeeho.funkyglassesplus. Die APK kannst du mit ADB vom Testgerät extrahieren oder über einen APK-Mirror-Dienst herunterladen.
APK öffnen
jadx-gui com.pinkysinyeeho.funkyglassesplus.apkJADX lädt und dekompiliert die APK. Bei mittelgroßen Apps dauert das 20–60 Sekunden. Danach siehst du im linken Panel einen Paketbaum mit drei Hauptbereichen:
- Source code — dekompilierter Java-Code, gegliedert nach Paketnamen
- Resources — XML-Ressourcen, AndroidManifest.xml, strings.xml
- lib/ — native
.so-Bibliotheken (relevant für Phase 3)
Krypto-Code finden: die Agreement-Klasse
Öffne die globale Textsuche mit Strg+Shift+F. Suche nach Cipher.getInstance. JADX hebt alle Treffer hervor und zeigt sie in einer Liste. In der LED-Brille-App führt einer der Treffer zur Klasse:
com.pinkysinyeeho.funkyglassesplus.model.data.Agreement
Dort findest du:
public static byte[] getEncryptData(byte[] data) {
aes.cipher(data, data);
return data;
}Das Objekt aes ist vom Typ einer JNI-Wrapper-Klasse, die über System.loadLibrary("AES") geladen wird. Der eigentliche Schlüssel steckt nicht im Java-Code — er ist in der nativen Bibliothek libAES.so vergraben. Das ist ein typisches Muster, das Phase 3 (Ghidra) erfordert.
UUIDs per Regex suchen
Öffne die globale Suche (Strg+Shift+F), aktiviere Regular expressions und verwende dieses Muster:
[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}
Für die LED-Brille liefert das drei herstellerspezifische UUIDs, die den Control-, Data- und Notification-Charakteristiken entsprechen. Diese UUIDs brauchst du später, um den Wireshark-Traffic den richtigen Funktionen zuzuordnen.
Kurzform für Standard-UUIDs
Viele BLE-Charakteristiken nutzen Bluetooth-SIG-UUIDs im Format 0000XXXX-0000-1000-8000-00805f9b34fb. Suche zusätzlich nach dem Kurzmuster 0000fff oder 0000180 — das findet Standarddienste wie Battery Service (0x180F) oder Device Information (0x180A) schneller.
Wichtigste Features
Globale Textsuche (Strg+Shift+F)
Die mächtigste Funktion in JADX. Die Suche durchläuft den gesamten dekompilierten Code und alle Ressourcen. Aktiviere Regular expressions für Mustersuche:
| Suche | Regex? | Zweck |
|---|---|---|
Cipher.getInstance | Nein | AES/DES/RSA-Verwendung finden |
SecretKeySpec | Nein | Schlüssel-Initialisierung |
System.loadLibrary | Nein | Native Bibliotheken identifizieren |
[0-9a-f]{8}-[0-9a-f]{4} | Ja | UUID-Muster |
writeCharacteristic | Nein | BLE-Sendepfade |
0x[0-9a-fA-F]{2,4} | Ja | Hex-Literale (potenzielle Schlüsselbytes) |
Deobfuskierung
JADX enthält einen eingebauten Deobfuskierer. Er benennt Ein-Zeichen-Klassen (a, b, c) in sprechendere Namen um und rekonstruiert, wo möglich, ursprüngliche Strukturen. Aktiviere ihn unter Tools → Deobfuscation oder starte JADX mit:
jadx-gui --deobf target.apkDeobfuskierung verändert Klassennamen
Nach der Deobfuskierung stimmen die Klassennamen nicht mehr mit dem Stack Trace einer laufenden App überein. Wenn du Frida-Hooks schreibst oder Smali-Patches planst, arbeite ohne Deobfuskierung — sonst verlierst du die Zuordnung.
Resource Browser
Im linken Panel unter Resources findest du alle XML-Dateien der App. Besonders interessant:
- AndroidManifest.xml — App-Berechtigungen (Bluetooth, Location), deklarierte Services, Broadcast Receiver
- res/values/strings.xml — Hardcodierte Strings, manchmal inkl. Server-URLs, API-Schlüssel oder Versionsnummern
- assets/ — Zertifikate, Konfigurationsdateien, manchmal eingebettete Binärdaten
Cross-Reference-Navigation (X-Refs)
Rechtsklick auf eine Klasse, Methode oder Feld → Find usages. JADX zeigt alle Codestellen, die diesen Bezeichner referenzieren. Das ist besonders hilfreich, um den Datenpfad rückwärts zu verfolgen: von writeCharacteristic() zur Methode, die den Payload aufbaut, von dort zur Verschlüsselungsroutine.
Export als Gradle-Projekt
File → Save as Gradle project exportiert den dekompilierten Code in eine IDE-kompatible Struktur. Du kannst das Projekt dann in Android Studio oder IntelliJ IDEA öffnen und die IDE-eigene Navigation nutzen — hilfreich bei großen Apps mit hunderten Klassen.
Fortgeschrittene Techniken
Obfuskierungsmuster erkennen
Professionell geschützte Apps verwenden ProGuard (eingebaut in Android Studio) oder das deutlich aggressivere DexGuard. Erkennungsmerkmale:
| Merkmal | ProGuard | DexGuard |
|---|---|---|
| Klassennamen | a, b, c (Einbuchstaben) | Zufällige Unicode-Namen |
| Strings | Klartext | Verschlüsselt (Runtime-Entschlüsselung) |
| Reflection | Selten | Häufig für Methoden-Lookup |
| Zeitaufwand RE | 4–8 Stunden | 12–40 Stunden |
Bei stark obfuskierten Apps hilft Frida (dynamische Analyse) mehr als statisches RE mit JADX. Erkenne es früh: Wenn du nach 30 Minuten keine sinnvollen Klassen- oder Methodennamen siehst und alle Strings als byte-Array-Initialisierungen erscheinen, ist DexGuard im Spiel.
Smali-Ansicht bei Dekompilierungsfehlern
Manchmal erzeugt JADX für einzelne Methoden keinen gültigen Java-Code (Kommentar /* JADX ERROR: ... */). In solchen Fällen wechsle in die Smali-Ansicht: Rechtsklick auf die Klasse → Show Smali. Smali ist der Assembler-Code von Dalvik/ART, lesbarer als Hex, aber näher an der Maschine als Java.
Wichtige Smali-Opcodes für BLE-Analyse:
invoke-virtual {v0, v1}, Ljavax/crypto/Cipher;->doFinal([B)[B
# entspricht: cipher.doFinal(data)
iget-object v2, p0, Ljava/util/UUID;->mostSigBits:J
# entspricht: uuid.mostSigBits
Batch-Verarbeitung per CLI
JADX läuft auch ohne GUI. Das ist nützlich, wenn du mehrere APKs vergleichen oder Ergebnisse per grep weiterverarbeiten willst:
# Alle Klassen einer APK in ein Verzeichnis dekompilieren
jadx -d ./output/ target.apk
# Anschließend mit grep nach Krypto-Mustern suchen
grep -r "Cipher.getInstance\|SecretKeySpec\|MessageDigest" ./output/
# Nur Ressourcen dekompilieren (kein Java-Code)
jadx --no-src -d ./resources/ target.apk
# Mehrere APKs auf einmal
for apk in *.apk; do
jadx -d "./decoded_${apk%.apk}/" "$apk"
doneKrypto-Muster gezielt suchen
Eine strukturierte Suchstrategie deckt systematisch alle kryptografischen Konstrukte auf:
# Im CLI-Output suchen (nach jadx -d output/)
grep -rn "Cipher.getInstance" output/sources/
grep -rn "SecretKeySpec\|IvParameterSpec" output/sources/
grep -rn "MessageDigest.getInstance" output/sources/
grep -rn "Mac.getInstance" output/sources/ # HMAC
grep -rn "KeyAgreement.getInstance" output/sources/ # ECDH/DHDatenpfade von BLE-Writes zur Verschlüsselung verfolgen
Der entscheidende analytische Schritt: den Weg eines BLE-Befehls vom UI-Event bis zum tatsächlichen writeCharacteristic()-Aufruf nachverfolgen. Starte bei writeCharacteristic und arbeite rückwärts:
- X-Ref auf
writeCharacteristic-- zeigt, welche Methode den Schreibvorgang auslöst - Parameter der Methode -- enthält den Payload, oft als
byte[] - X-Ref auf die Payload-Methode -- zeigt, ob der Payload vorher verschlüsselt oder transformiert wird
- Verschlüsselungsaufruf --
Cipher.doFinal()oder ein JNI-Call an eine native Methode
Bei der LED-Brille führt dieser Pfad von BluetoothGattCharacteristic.writeCharacteristic() über eine Wrapper-Klasse zur Agreement.getEncryptData(), die den JNI-Call an libAES.so enthält. Drei Hops von der BLE-Schnittstelle zum Schlüssel.
Native Library Handoff erkennen
Der Übergang von Java zu nativem Code ist das Signal, JADX beiseite zu legen und Ghidra zu starten. Suche nach:
System.loadLibrary("AES"); // lädt libAES.so
System.loadLibrary("crypto"); // lädt libcrypto.so
native byte[] cipher(byte[] data, byte[] out); // JNI-DeklarationWenn du System.loadLibrary() und eine zugehörige native-Methoden-Deklaration findest, liegt der eigentliche Code in der .so-Datei unter lib/arm64-v8a/. Diese Datei extrahierst du aus der APK (sie ist ein ZIP-Archiv) und übergibst sie an Ghidra.
Häufige Probleme
OutOfMemoryError beim Öffnen großer APKs
JADX startet standardmäßig mit begrenztem Heap. Bei sehr großen Apps (Facebook, Google-Apps, einige Hersteller-Bloatware) reicht das nicht. Erhöhe den Heap über die JVM-Optionen:
# Über JAVA_OPTS (Linux/macOS)
export JAVA_OPTS="-Xmx8g"
jadx-gui target.apk
# Alternativ: Heap direkt in der Startdatei anpassen
# Öffne bin/jadx-gui und ändere die DEFAULT_JVM_OPTS-ZeileSpezifische Klassen können nicht dekompiliert werden
Manche Klassen enthalten Bytecode-Konstrukte, die JADX nicht sauber zurücktransformieren kann. Der Fehler erscheint als Kommentar im Code:
/* JADX ERROR: Method load error
jadx.core.utils.exceptions.DecodeException: ... */Lösung: In die Smali-Ansicht wechseln (Rechtsklick → Show Smali) oder die betreffende Datei mit apktool d target.apk entpacken und den Smali-Code direkt lesen.
Fehlende Ressourcen bei Split-APKs
Moderne Android-Apps werden als App Bundle (AAB) ausgeliefert, das der Play Store in mehrere Split-APKs aufteilt. Die Hauptdatei base.apk enthält nicht alle nativen Bibliotheken und Ressourcen — architekturspezifische Dateien liegen z. B. in split_config.arm64_v8a.apk.
# Alle Split-APKs vom Gerät extrahieren
adb shell pm path com.example.bleapp
# Gibt mehrere Pfade aus — alle mit adb pull herunterladen
adb pull /data/app/.../base.apk
adb pull /data/app/.../split_config.arm64_v8a.apk
# JADX kann alle APKs gleichzeitig öffnen:
# File → Open files → alle APKs auswählenKlassen fehlen nach der Dekompilierung
Wenn eine Klasse im Code referenziert wird, aber nicht im Paketbaum erscheint, ist sie wahrscheinlich Teil einer externen AAR-Bibliothek, die nicht mitgeliefert wurde, oder sie liegt in einem der Split-APKs. Prüfe mit:
# Dekompilieren und im Output nach fehlenden Klassen suchen
jadx -d ./output/ target.apk
grep -rn "kryptografie\|UUID\|ble" ./output/sources/JADX vs. apktool — wann welches?
JADX ist für Java-Code-Analyse. apktool ist für Ressourcen, AndroidManifest.xml und wenn du Smali-Code direkt patchen willst. Bei einer BLE-Sicherheitsanalyse startest du mit JADX, wechselst aber zu apktool, wenn du native Bibliotheken aus einem Split-APK brauchst oder Manifest-Berechtigungen prüfen willst, die JADX manchmal unvollständig darstellt.
Zusammenfassung
- JADX-GUI ist der Einstiegspunkt jeder APK-Analyse: Java-Bytecode zu lesbarem Quellcode
- Globale Suche (Strg+Shift+F) mit Regex findet UUIDs, Krypto-Klassen und BLE-Schreibpfade in Sekunden
System.loadLibrary()+native-Methode = Handoff an Ghidra für Phase 3- Smali-Ansicht rettet dich bei Dekompilierungsfehlern
- CLI-Modus (
jadx -d output/ target.apk) erlaubt Batch-Verarbeitung und Grep-Integration - Split-APKs immer gemeinsam öffnen — sonst fehlen native Bibliotheken