Phase 1: APK-Analyse
App-Dekompilierung und statische Analyse mit JADX
Lernziel
Nach dieser Seite weißt du, wie du eine Android-App extrahierst, dekompilierst und systematisch nach BLE-relevanten Informationen durchsuchst: UUIDs, Kryptografie-Code, native Bibliotheken und versteckte Schlüssel.
Was ist APK-Analyse und warum fangen wir damit an?
Stell dir vor, du willst verstehen, wie ein Schloss funktioniert — aber du hast keinen Schlüssel und keine Anleitung. Die einfachste Methode: Du schaust dir die App an, die das Schloss steuert. Dort stecken alle Informationen drin.
Eine APK-Datei (Android Package) ist im Grunde ein ZIP-Archiv, das den kompilierten Java-Code, Ressourcen und native Bibliotheken enthält. Mit dem richtigen Werkzeug lässt sich der kompilierte Code wieder in lesbares Java zurückwandeln — das nennt sich Dekompilierung.
Warum Phase 1 zuerst?
Die APK-Analyse ist die günstigste Phase: Du brauchst keine Spezial-Hardware, kein physisches Gerät und hinterlässt keine Spuren. Viele Schwachstellen — hardcodierte Schlüssel, UUID-Strukturen, Verschlüsselungslogik — sind direkt im App-Code sichtbar, bevor du auch nur ein einziges Paket sniffst.
Zeitaufwand: 5–8 Stunden für ein unbekanntes Gerät.
Schritt 1: App vom Gerät extrahieren (ADB)
ADB (Android Debug Bridge) ist das Standard-Werkzeug zum Kommunizieren mit Android-Geräten. Du brauchst dafür USB-Debugging, das in den Entwickleroptionen deines Testgeräts aktiviert sein muss.
# Verbindung prüfen
adb devices
# App-Paketname herausfinden
adb shell pm list packages | grep -i "bluetooth\|ble\|smart"
# Pfad zur APK auf dem Gerät ermitteln
adb shell pm path com.example.bleapp
# APK auf deinen Rechner kopieren
adb pull /data/app/com.example.bleapp-1/base.apk ./target.apkApp-Namen kennen
Du kennst den Paketnamen meistens nicht im Voraus. Öffne die App auf dem Gerät, verbinde dich via ADB und führe adb shell dumpsys window windows | grep mCurrentFocus aus — das zeigt dir den Paketnamen der aktiven App.
Alternativ kannst du die APK direkt aus dem Google Play Store herunterladen, z. B. über den Dienst APKPure oder mit dem Tool apkeep:
apkeep -a com.example.bleapp -d google-play ./Schritt 2: Dekompilierung mit JADX-GUI
JADX-GUI (Version 1.5.3) ist der De-facto-Standard zum Dekompilieren von APKs. Es wandelt den .dex-Bytecode zurück in lesbares Java — nicht perfekt, aber gut genug für die Analyse.
# JADX-GUI starten
jadx-gui target.apkNach dem Öffnen siehst du auf der linken Seite einen Paketbaum. Die drei wichtigsten Bereiche:
- Source code — dekompilierter Java-Code
- Resources — XML-Dateien, Strings, Manifest
- lib/ — native
.so-Bibliotheken (wichtig für Phase 3)
Dekompilierung ist keine magische Umkehrung
JADX erzeugt lesbares Java, aber nicht das Original. Variablennamen sind oft verloren (bArr, i2, str3). Klassen können leicht umbenannt sein. Das ist normal — konzentriere dich auf die Logik, nicht die Namen.
Schritt 3: Systematische Suche — was suchst du?
Öffne in JADX-GUI die globale Suche (Strg+Shift+F). Du suchst nach vier Kategorien:
3a. BLE UUIDs
UUIDs (Universally Unique Identifiers) identifizieren GATT-Services und Charakteristiken. Sie haben das Format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
# Regex-Suchmuster für UUIDs im JADX-Textsuche
[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}
# Oder kürzer nach 16-bit UUIDs suchen (Standard-Bluetooth-Format)
0000[0-9a-fA-F]{4}-0000-1000-8000-00805f9b34fb
Praxisbeispiel LED-Brille (Sonhomay): Die Suche nach 0xfff0 oder fff0 führt direkt zum herstellerspezifischen Service. Drei Charakteristiken wurden gefunden:
| Funktion | UUID | Permissions |
|---|---|---|
| Control | d44bc439-...-9600 | WRITE, WRITE_NO_RESP |
| Data | d44bc439-...-960a | WRITE, WRITE_NO_RESP |
| Notification | d44bc439-...-9601 | NOTIFY |
Praxisbeispiel LED-Strip (wl.smartled): Service UUID 0000fff0-...-00805f9b34fb, Steuer-Charakteristik 0000fff3-....
Praxisbeispiel Körperwaage (Lebenlang): Keine Custom-GATT-UUIDs — die Waage sendet ausschließlich über BLE-Advertisements. Das erkennt man daran, dass im Code kein writeCharacteristic()-Aufruf für Messdaten existiert, nur Advertisement-Parsing-Code.
3b. Kryptografie-Code
# In JADX-Textsuche eingeben:
Cipher.getInstance
SecretKeySpec
AES
javax.crypto
MessageDigest
Praxisbeispiel LED-Brille: Die Suche nach Cipher.getInstance führt zur Klasse com.pinkysinye eho.funkyglassesplus.model.data.Agreement. Dort findet sich:
public static byte[] getEncryptData(byte[] data) {
aes.cipher(data, data);
return data;
}Der Aufruf aes.cipher() delegiert an die native Bibliothek libAES.so — ein starkes Signal, dass der eigentliche Schlüssel nicht im Java-Code steht, sondern in der .so-Datei vergraben ist. Das wird dann Thema von Phase 3.
Praxisbeispiel LED-Strip: Die Klasse EncryptUtil enthält einen XOR-Schlüssel direkt im Java-Code — sichtbar als ASCII-String im Klartext:
byte[] key = {89, 76, 90, 75, 53, 41, 33, 41, 62, 72, 64,
118, 100, 98, 81, 68, 94, 68, 63, data_num};
// ASCII: "YLZK51!)>H@vdbQD^D?" + Counter-ByteXOR ist keine Verschlüsselung
Dieser 19-Byte-XOR-Schlüssel klingt beeindruckend, ist aber mathematisch trivial: Durch iteratives XOR aller 19 Bytes miteinander kollabiert er zu einem einzigen Byte (0x66). Das ergibt genau 256 mögliche Werte — ein Brute-Force in Millisekunden.
Praxisbeispiel Körperwaage: Keine Crypto-Klassen gefunden. Kein Cipher-Aufruf im Datenpfad. Die Entropie-Analyse des Advertisement-Payloads (ca. 4,5 bits/byte, Schwellenwert für Klartext: unter 6,0 bits/byte) bestätigt: keine Verschlüsselung.
3c. BLE-Schreib-Aufrufe
# Suche nach BLE-Kommunikation
writeCharacteristic
writeDescriptor
setCharacteristicNotification
BluetoothGattCallback
onCharacteristicChanged
Diese Aufrufe zeigen dir, wo im Code tatsächlich Daten gesendet und empfangen werden. Schau dir den Kontext an: Welche Daten werden übergeben? Werden sie vorher verschlüsselt?
3d. Hardcodierte Credentials und Schlüssel
# Suche nach verdächtigen Werten
password
secret
key
token
hardcoded
Auch direkte Byte-Array-Literale sind verdächtig:
// Beispiel eines hardcodierten Schlüssels (fiktiv)
byte[] key = new byte[]{0x34, 0x52, 0x2A, 0x5B, ...};Strings-Ressourcen nicht vergessen
Manche Schlüssel stehen nicht im Java-Code, sondern in res/values/strings.xml oder anderen Ressourcen-Dateien. Durchsuche in JADX auch den Resources-Bereich.
Schritt 4: Native Bibliotheken extrahieren
Wenn Java-Code auf System.loadLibrary("AES") oder ähnliches verweist, liegt der eigentliche Code in einer .so-Datei (Shared Object — eine native Bibliothek für Android, vergleichbar mit .dll auf Windows).
Diese Bibliotheken findest du im APK unter:
lib/
arm64-v8a/ ← 64-bit ARM (moderne Geräte)
armeabi-v7a/ ← 32-bit ARM (ältere Geräte)
x86_64/ ← für Emulatoren
# APK ist ein ZIP — entpacken
unzip target.apk -d apk_extracted
# Native Bibliotheken finden
find apk_extracted/lib -name "*.so" -type f
# Für Phase 3 kopieren
mkdir -p ./native_libs
cp apk_extracted/lib/arm64-v8a/*.so ./native_libs/Praxisbeispiel LED-Brille: Unter lib/arm64-v8a/ liegt libAES.so. Der JNI-Einstiegspunkt (JNI = Java Native Interface, die Brücke zwischen Java und nativem Code) heißt Java_csh_tiro_cc_aes_keyExpansionDefault. Darin steckt der hardcodierte AES-128-Schlüssel — zu sehen in Phase 3.
Welche Architektur?
Nimm für Phase 3 immer arm64-v8a — das ist der 64-bit ARM-Code moderner Geräte. Ghidra analysiert ihn am besten. Falls nur armeabi-v7a vorhanden ist, funktioniert die Analyse genauso, nur 32-bit.
Schritt 5: Ergebnisse dokumentieren
Am Ende von Phase 1 solltest du eine Liste haben:
- Alle gefundenen UUIDs (Service + Charakteristiken + Permissions)
- Verwendete Kryptoverfahren (AES, XOR, nichts)
- Hinweise auf native Bibliotheken und deren Namen
- Verdächtige Byte-Arrays oder Strings im Code
- Ob Verschlüsselung stattfindet und wo
Diese Liste ist die Grundlage für Phase 2 (Traffic-Analyse) und Phase 3 (Reverse Engineering der nativen Bibliotheken).
Zusammenfassung der drei Geräte
| Gerät | Klassen | Krypto | Native Lib | Schlüssel sichtbar? |
|---|---|---|---|---|
| LED-Brille | 155 | AES-128 (ECB) | libAES.so | Nein (in .so) |
| LED-Strip | ~80 | XOR | Keine | Ja (Java-Klartext) |
| Körperwaage | ~60 | Keine | Keine | Entfällt |
Zusammenfassung
- APKs lassen sich mit
adb pullvom Gerät extrahieren und mit JADX-GUI dekompilieren - Systematische Textsuche nach UUIDs,
Cipher.getInstance,SecretKeySpecundwriteCharacteristicdeckt BLE-Logik auf - Native
.so-Bibliotheken imlib/arm64-v8a/-Ordner enthalten oft den eigentlichen Krypto-Code - Ein XOR-Schlüssel im Java-Klartext ist keine echte Verschlüsselung — mathematisch bricht er zu einem einzigen Byte zusammen
- Fehlende Crypto-Aufrufe im Datenpfad sind ein starkes Indiz für Klartext-Übertragung
Nur eigene Geräte analysieren
Die hier beschriebenen Techniken gelten ausschließlich für Geräte, die du selbst besitzt oder für die du eine schriftliche Genehmigung hast. Unautorisierte APK-Analyse fremder Systeme kann nach §202a StGB (Ausspähen von Daten) strafbar sein. Mehr dazu im Rechtlichen Rahmen.
Phase-1-Checkliste
0/8Du findest in der JADX-Analyse folgenden Code: aes.cipher(data, data) — was bedeutet das für deine Analyse?