apktool

APKs entpacken, Ressourcen lesen und modifizierte Apps bauen

Lernziel

Nach dieser Seite weißt du, wie du mit apktool eine APK vollständig dekodierst, AndroidManifest.xml und Ressourcen liest, BLE-Permissions erkennst und — falls nötig — eine modifizierte APK neu baust und signierst.


Was ist apktool?

apktool ist ein Open-Source-Tool zum Reverse Engineering von Android-APK-Dateien. Im Gegensatz zu JADX, das den Dalvik-Bytecode in lesbares Java zurückübersetzt, macht apktool zwei andere Dinge:

  1. Ressourcen dekodieren — XML-Dateien (AndroidManifest, Layouts, Strings) werden aus dem kompilierten Binärformat zurück in lesbares XML umgewandelt
  2. Smali-Disassemblierung — der Bytecode wird in Smali dekompiliert, eine assemblerähnliche Darstellung des Dalvik-Befehlssatzes

Für die BLE-Sicherheitsanalyse ist apktool primär interessant wegen AndroidManifest.xml: Dort sind alle angeforderten Permissions, deklarierte Services und declared BLE-Capabilities sichtbar — exakt so, wie sie zur Laufzeit gelten.

apktool vs. JADX — wann was?

JADX gibt dir lesbaren Java-Code: gut für Kryptoanalyse, UUID-Suche und Logikverständnis. apktool gibt dir die Original-Ressourcen und Smali: gut für Manifest-Analyse, String-Ressourcen und APK-Modifikation. In der Praxis nutzt du beide — JADX für den Code, apktool für das Manifest und die Ressourcen.


Installation

Voraussetzungen

apktool ist ein Java-Tool. Du brauchst Java 8 oder neuer:

java -version
# Sollte "openjdk version 11.x.x" oder höher ausgeben

Falls Java fehlt:

# Debian/Ubuntu
sudo apt install default-jre

# macOS (Homebrew)
brew install openjdk

apktool installieren

# Linux/macOS: Wrapper-Script und JAR herunterladen
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool \
     -O /usr/local/bin/apktool
wget https://github.com/iBotPeaches/Apktool/releases/download/v2.10.0/apktool_2.10.0.jar \
     -O /usr/local/bin/apktool.jar
chmod +x /usr/local/bin/apktool

# Version prüfen
apktool --version
# 2.10.0

Windows

Auf Windows: apktool.bat als Wrapper-Script statt apktool verwenden. Der Befehl ist identisch, nur der Dateiname des Scripts unterscheidet sich.


Praxisbeispiel: LED-Strip-APK dekodieren

Die App wl.smartled steuert den LED-Strip. Extrahiere die APK mit ADB und dekodiere sie mit apktool:

# APK vom Gerät extrahieren
adb shell pm path wl.smartled
# /data/app/wl.smartled-1/base.apk

adb pull /data/app/wl.smartled-1/base.apk ./ledstrip.apk

# APK mit apktool dekodieren
apktool d ledstrip.apk -o ledstrip_decoded

Das erzeugt folgende Verzeichnisstruktur:

ledstrip_decoded/
├── AndroidManifest.xml     ← decodiertes Manifest (lesbares XML)
├── apktool.yml             ← Metadaten für den Rebuild
├── res/                    ← decodierte Ressourcen
│   ├── layout/             ← XML-Layouts
│   ├── values/
│   │   ├── strings.xml     ← String-Ressourcen
│   │   └── public.xml      ← Ressourcen-IDs
│   └── drawable/
├── smali/                  ← Smali-Code (Dalvik-Assembly)
│   └── wl/smartled/...
└── lib/                    ← native .so-Dateien (falls vorhanden)
    └── arm64-v8a/

AndroidManifest.xml lesen

cat ledstrip_decoded/AndroidManifest.xml

Relevante Abschnitte für die BLE-Analyse:

<manifest package="wl.smartled" ...>

  <!-- Permissions: Welche BLE-Rechte verlangt die App? -->
  <uses-permission android:name="android.permission.BLUETOOTH"/>
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
  <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

  <!-- Feature-Deklaration: App setzt BLE voraus -->
  <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

  <application ...>
    <!-- Deklarierte Services (Background-Prozesse) -->
    <service android:name=".service.BleService"
             android:enabled="true"
             android:exported="false"/>
  </application>
</manifest>

Aus dem Manifest erkennst du:

  • Die App verlangt BLUETOOTH_SCAN und BLUETOOTH_CONNECT — das sind die Android-12-BLE-Permissions
  • ACCESS_FINE_LOCATION ist angegeben — die App scannt nach Geräten
  • Ein deklarierter BleService läuft im Hintergrund — BLE-Verbindungen werden dort verwaltet

Exported Services sind potenzielle Angriffspunkte

android:exported="true" an einem Service bedeutet, dass andere Apps (oder du via ADB) den Service direkt aufrufen können — ohne durch die normale App-UI zu gehen. Für die Sicherheitsanalyse ist das interessant: Ein exportierter BLE-Service könnte sich von außen instruieren lassen.

String-Ressourcen durchsuchen

grep -i "ble\|bluetooth\|uuid\|key\|secret" ledstrip_decoded/res/values/strings.xml

Manchmal liegen UUIDs oder API-Keys in den String-Ressourcen statt im Java-Code:

<string name="ble_service_uuid">0000fff0-0000-1000-8000-00805f9b34fb</string>
<string name="ble_char_write">0000fff3-0000-1000-8000-00805f9b34fb</string>

APK modifizieren und neu bauen

In manchen Analyseszenarien willst du die APK verändern: Debug-Logging aktivieren, ein Certificate-Pinning entfernen oder das Netzwerk-Security-Config patchen, damit du Traffic intercepten kannst.

Schritt 1: Smali-Code anpassen

Smali ist die Assemblersprache von Dalvik. Ein einfaches Beispiel: eine boolean-Return-Methode auf true zwingen:

# Original:
.method public isDevMode()Z
    .registers 2
    const/4 v0, 0x0    # return false
    return v0
.end method

# Modifiziert:
.method public isDevMode()Z
    .registers 2
    const/4 v0, 0x1    # return true
    return v0
.end method

Schritt 2: Netzwerk-Security-Config patchen

Um HTTPS-Traffic mit einem Proxy (z. B. Burp Suite) zu intercepten, musst du das Network Security Profile der App auf User-Certificates erweitern:

# res/xml/network_security_config.xml anlegen (oder anpassen)
mkdir -p ledstrip_decoded/res/xml
<!-- ledstrip_decoded/res/xml/network_security_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <base-config>
    <trust-anchors>
      <certificates src="system"/>
      <certificates src="user"/>   <!-- User-Certs werden akzeptiert -->
    </trust-anchors>
  </base-config>
</network-security-config>

Dann im AndroidManifest.xml das Attribut eintragen:

<application
  android:networkSecurityConfig="@xml/network_security_config"
  ...>

Schritt 3: APK neu bauen

apktool b ledstrip_decoded -o ledstrip_modified.apk

Schritt 4: Mit Debug-Keystore signieren

Android verweigert unsignierte APKs. Zum Testen reicht ein selbst-generierter Debug-Keystore:

# Keystore einmalig erstellen (falls noch nicht vorhanden)
keytool -genkey -v -keystore debug.keystore \
  -alias androiddebugkey -keyalg RSA -keysize 2048 \
  -validity 10000 -storepass android -keypass android \
  -dname "CN=Android Debug,O=Android,C=US"

# APK signieren
apksigner sign \
  --ks debug.keystore \
  --ks-key-alias androiddebugkey \
  --ks-pass pass:android \
  --key-pass pass:android \
  --out ledstrip_signed.apk \
  ledstrip_modified.apk

# APK auf Gerät installieren (vorher Original deinstallieren!)
adb uninstall wl.smartled
adb install ledstrip_signed.apk

Signature-Mismatch bei Updates

Eine mit einem anderen Keystore signierte APK kann nicht als Update über die Original-App installiert werden — Android prüft die Signatur. Deinstalliere die Original-App zuerst. Dabei gehen App-Daten (Login-Sessions, Cache) verloren.


Split-APKs aus App Bundles

Moderne Android-Apps werden oft als App Bundle (AAB) ausgeliefert und vom Google Play Store in mehrere Split-APKs aufgeteilt. Mit ADB holst du alle:

# Alle APK-Pfade der App anzeigen
adb shell pm path wl.smartled

# Ausgabe (Beispiel):
# package:/data/app/wl.smartled-1/base.apk
# package:/data/app/wl.smartled-1/split_config.arm64_v8a.apk
# package:/data/app/wl.smartled-1/split_config.de.apk

# Alle APKs extrahieren
adb pull /data/app/wl.smartled-1/ ./apks/

# Jede APK separat dekodieren
for apk in apks/*.apk; do
  apktool d "$apk" -o "decoded_$(basename "$apk" .apk)"
done

Native Bibliotheken liegen oft in split_config.arm64_v8a.apk — nicht in base.apk. Wenn du in base.apk kein lib/-Verzeichnis findest, schau in den Split-APKs.


Häufige Probleme

ProblemUrsacheLösung
brut.androlib.err.UndefinedResObjectFramework fehltapktool if framework-res.apk ausführen
Build schlägt fehl mit already installedFramework-Konfliktapktool empty-framework-dir und neu versuchen
APK nach Modifikation startet nichtSmali-SyntaxfehlerSmali-Diff prüfen; Android-Logcat lesen: `adb logcat
apksigner nicht gefundenAndroid SDK fehltAus Android SDK: build-tools/<version>/apksigner
INSTALL_PARSE_FAILED_NO_CERTIFICATESAPK unsigniertAPK mit apksigner signieren
Zipalign-FehlerAlignment fehltzipalign -v 4 in.apk out.apk vor dem Signieren

Framework-Installation

Manche Hersteller-Apps (insbesondere auf Samsung oder Xiaomi) nutzen herstellerspezifische Framework-Ressourcen. apktool benötigt dafür das Framework-APK des Geräts, das du einmalig mit apktool if /system/framework/framework-res.apk installierst (APK via ADB vom Gerät ziehen).


Zusammenfassung

  • apktool dekodiert APKs in lesbares XML (Manifest, Ressourcen) und Smali-Assembler — keine Java-Dekompilierung wie JADX
  • AndroidManifest.xml zeigt alle BLE-Permissions, deklarierte Services und Feature-Anforderungen
  • String-Ressourcen (res/values/strings.xml) können UUIDs und API-Konfigurationen enthalten
  • Der Decode → Modify → Build → Sign-Zyklus ermöglicht APK-Patching für Debug-Logging oder Certificate-Pinning-Bypass
  • Split-APKs aus App Bundles müssen separat extrahiert und dekodiert werden
  • Signatur-Mismatch erfordert Deinstallation der Original-App vor der Installation der modifizierten Version