
🔬 Ein fortschrittliches Android-Forschungstool für die Echtzeit-Erfassung von VoIP-Audio (Uplink/Downlink) durch dynamisches Hooking von libaudioflinger.so. Getestet und entwickelt auf WhatsApp, Signal und Telegram unter Android 14.
Ziel: Demonstrieren der VoIP-Stream-Erfassung durch Hooking des Android-audioserver (insbesondere libaudioflinger.so) und Aufzeichnen der Uplink- (Mikrofon) und Downlink- (Lautsprecher) PCM-Puffer, wenn sich das System im Kommunikationsmodus befindet.
Controller App (Android)
UI mit 9 Schaltflächen zur Verwaltung der SELINUX-Richtlinieneinrichtung, Payload-Injektion, Datenübertragung und Wiedergabe.
Payload (libaudiohook.so)
C++-Shared-Library (als Teil des App-Projekts erstellt), die interne AudioFlinger-Methoden mit Dobby hookt und rohe PCM-Puffer in ein Sitzungsverzeichnis schreibt.
Post-Processing
Zusätzliches Tool, tools/audioparser.py konvertiert rohe .ac(Downlink)/.bc(Uplink)-Dateien in WAV. Der Dateimanager der App kann ebenfalls konvertieren und in der App abspielen.
Research Utilities
Frida-Skripte für anfängliches Funktionstracing & Offset-Ermittlung; Analysedateien für Symbol/Offset und andere Snippets.
Diese Android-Anwendung bietet eine grafische Oberfläche zur Verwaltung der VoIP-Aufzeichnung über den audioserver. Sie integriert einen nativen Payload, der in den Android-Audiostack eingreift, um Mikrofon- und Lautsprecheraudio von VoIP-Anwendungen zu erfassen.
Die App dient als Kontrollzentrum, mit dem Sie erforderliche SELinux-Richtlinien injizieren, die Überwachung starten/stoppen, aufgezeichnete Daten verwalten und erfasste VoIP-Audiodateien abspielen können.
Die Hauptaktivität enthält 9 Steuerschaltflächen:
Inject Policies
Injiziert die erforderlichen SELinux-Richtlinien, damit audioserver und diese App zusammenarbeiten können.
Start Monitoring
Injiziert den Shared-Library-Payload in audioserver und ermöglicht so die VoIP-Audioerfassung durch Hooking von RecordTrack und PlaybackTrack. Verwendet AndKittyInjector für die Prozessinjektion.
Stop Monitoring
Startet den audioserver-Prozess neu, stoppt die Überwachung und entfernt injizierte Hooks.
Copy Data
Kopiert erfasstes rohes PCM-Audio aus dem temporären Verzeichnis /data/local/tmp/voip nach /sdcard/voip.
View Logs
Zeigt Protokolle zu Injektion, Hooking und Aufzeichnungsstatus an.
Enable SELinux
Stellt den SELinux-Enforcing-Modus wieder her.
Disable SELinux
Setzt SELinux in den permissiven Modus. Verwenden, wenn injizierte Richtlinien fehlschlagen.
Play Audios
Öffnet den benutzerdefinierten VoIP-Dateimanager (/sdcard/voip/):
+----------------------+
| |
| App MainActivity |
| |
| |
|(9 Control Buttons UI)|
| |
| |
+----------+-----------+
|
|
|
+----------v-----------+
| |
| JNI Layer |
| |
| Selinux, Process Inje|
| ction, |
| |
| |
+----------------------+
Diese Shared Library wird in audioserver injiziert, um AUDIO_MODE_IN_COMMUNICATION zu erkennen und VoIP-Audiostreams direkt aus dem Android-Audiostack für eine vordefinierte Menge von Paketnamen zu erfassen.
Sie verwendet das Dobby Inline-Hooking-Framework, um kritische Methoden in libaudioflinger.so abzufangen.
Sowohl Uplink- (Mikrofon) als auch Downlink- (Lautsprecher) Audiostreams werden erfasst und zur späteren Verarbeitung in Sitzungsdateien geschrieben.
Die Bibliothek installiert Hooks auf den folgenden Funktionen in AudioFlinger und zugehörigen Klassen:
Die Bibliothek filtert Streams basierend auf der UID → Paket-Zuordnung.
Derzeit überwachte Apps:
com.whatsappcom.whatsapp.w4b (WhatsApp Business)org.thoughtcrime.securesms (Signal)org.telegram.messengerorg.telegram.messenger.webSie können andere Anwendungen auch in audioserver_hook.cpp hinzufügen:
static const char* kTargetPackages[] = {
"com.whatsapp",
"com.whatsapp.w4b",
"org.thoughtcrime.securesms",
"org.telegram.messenger",
"org.telegram.messenger.web"
};
Ein Sitzungsverzeichnis wird bei der Injektion in audioserver unter folgendem Pfad erstellt:
/data/local/tmp/voip/audioserver_session_<timestamp>/
Dateien werden zunächst mit einer .tmp-Erweiterung erstellt und beim Stoppen des Tracks umbenannt:
<packageName>_<sampleRate>_<timestamp>.bc<packageName>_<sampleRate>_<timestamp>.acBeispielsitzung:
/data/local/tmp/voip/audioserver_session_1725389200/
├── com.whatsapp_48000_1725389201_123456.ac
├── com.whatsapp_48000_1725389201_123789.bc
Da die Ziellibrary gestrippt ist und Methoden in libaudioflinger.so nicht exportiert werden, benötigen wir exakte Offsets der Methoden und anderer zugehöriger Komponenten für erfolgreiches Hooking.
Wir können diese Offsets aus der statischen Analyse mit IDA-PRO oder aus der dynamischen Analyse mit Frida extrahieren.
Sobald die Offsets bekannt sind, können wir sie in der Headerdatei offsets.h ersetzen.
android::AudioFlinger::setMode(audio_mode_t)_ZN7android12AudioFlinger7setModeE11audio_mode_tandroid::AudioFlinger::RecordThread::RecordTrack::getNextBuffer(android::AudioBufferProvider::Buffer *)_ZN7android12AudioFlinger12RecordThread11RecordTrack13getNextBufferEPNS_19AudioBufferProvider6BufferEandroid::AudioFlinger::PlaybackThread::Track::getNextBuffer(android::AudioBufferProvider::Buffer *)_ZN7android12AudioFlinger14PlaybackThread5Track13getNextBufferEPNS_19AudioBufferProvider6BufferEandroid::AudioFlinger::PlaybackThread::Track::stop(void)_ZN7android12AudioFlinger14PlaybackThread5Track4stopEvDiese können aus der statischen Analyse ermittelt werden.
libaudioflinger.soandroid::AudioFlinger::ThreadBase::TrackBase::TrackBaseTrackBase::TrackBase(
IAfThreadBase *thread,
const sp<Client>& client,
const audio_attributes_t& attr,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
size_t bufferSize,
audio_session_t sessionId,
pid_t creatorPid,
uid_t clientUid,
bool isOut,
const alloc_type alloc,
track_type type,
audio_port_handle_t portId,
std::string metricsId)
┌─────────────────────────────┐
│ VoIP Apps │
│ (WhatsApp / Signal / TG) │
└───────────────┬─────────────┘
│ Audio in/out
▼
┌─────────────────────────────┐
│ audioserver │
│ (libaudioflinger.so) │
└───────┬─────────┬───────────┘
│ │
uplink│ │downlink
(mic) │ │(speaker)
▼ ▼
┌───────────-──┐ ┌────────────-─┐
│ RecordTrack │ │ Track │
│ getNextBuffer│ │ getNextBuffer│
└───────┬────-─┘ └───────┬────-─┘
│ │
┌─────▼─────┐ ┌─────▼─────┐
│ hook_... │ │ hook_... │
│ (uplink) │ │ (downlink)│
└─────┬─────┘ └─────┬─────┘
│ │
└──────┬───┬──────┘
│ │
▼ ▼
┌───────────────────────────┐
│ /data/local/tmp/voip/ │
│ audioserver_session_* │
│ - *.bc (uplink) │
│ - *.ac (downlink) │
└───────────────────────────┘
Verwendeter Prozess:
AudioFlinger verwaltet Wiedergabe/Erfassung über PlaybackThread & RecordThread.PlaybackThread::Track (Downlink) und RecordThread::RecordTrack (Uplink) repräsentiert.app/src/main/cpp/include/offsets.h), um gestrippte Symbole zu überstehen.MODE_IN_COMMUNICATIONWir hooken AudioFlinger::setMode(int mode) und pflegen einen globalen Zustand:
g_currentAudioMode.g_currentAudioMode == AUDIO_MODE_IN_COMMUNICATION..
├── Android_App/
| ├── app/ # Android Studio project (App + Payload)
| │ ├── src/
| │ │ ├── main/
| │ │ │ ├── java/ # Controller App Java/Kotlin sources
| │ │ │ ├── cpp/ # Payload source (built with the app)
| │ │ │ │ └── include/
| │ │ │ │ └── offsets.h # Function offsets for tested builds
├── tools/
│ ├── audioparser.py # Converts .ac/.bc raw files → WAV
│ ├── frida/ # Frida scripts for initial hook discovery
│ │ ├── host_audioserver.py
│ │ ├── agent_audioserver.js
├── app-release.apk # Signed release apk
└── README.md # Root README (design, build, run instructions)
audioparser.pyapp/ in Android Studio.libaudiohook.so) als Teil des Projekts.adb install -r app/build/outputs/apk/debug/app-debug.apk
oder installiere die bereitgestellte app-release.apk:
adb install -r app-release.apk
Wenn du Artefakte trennst, kannst du die Shared Library auch zu Testzwecken übertragen:
adb push app/src/main/jniLibs/arm64-v8a/libaudiohook.so /data/local/tmp/
audioserver in deiner Testumgebung erforderlich sind.audioserver zu injizieren.audioserver neu./data/local/tmp/voip/… nach /sdcard/voip/ (und leert das temporäre Verzeichnis). adb pull /sdcard/voip/
python3 tools/audioparser.py voip/
Zusätzliche Schaltflächen:
- „View Logs“: Injektor-/Hook-Status anzeigen.
- „Enable SELinux“ / „Disable SELinux“: Enforcing/Permissive in deinem Labor umschalten, wenn Richtlinien zu streng sind.
- „Delete Data“:
/data/local/tmp/voip/und/sdcard/voip/leeren.
dlsym gefunden werden.dlsym kann fehlschlagen.offsets.h), validiert mit Frida-Symbol-Dumps und IDA-PRO.AudioFlinger::setMode(IN_COMMUNICATION); Übergänge protokollieren; ein globales Modus-Flag speichern.audioserver kann blockiert werden..tmp schreiben; bei stop() in (Downlink) oder (Uplink) umbenennen.frameworks/av/services/audioflinger (AudioFlinger, PlaybackThread, RecordThread)system/media/audio (audio formats, attributes, channel masks)Delete Data
Löscht alle Audiodaten aus /data/local/tmp/voip und /sdcard/voip.
HINWEIS: Nach dem Löschen der Daten müssen wir erneut in audioserver injizieren, damit das Verzeichnis zum Speichern von Daten erstellt wird.
| Function | Purpose |
|---|
AudioFlinger::setMode | Verfolgt Übergänge in den/aus dem IN_COMMUNICATION-Modus (VoIP aktiv). |
RecordTrack::getNextBuffer | Erfasst Mikrofon- (Uplink-) Audioframes. |
PlaybackThread::Track::getNextBuffer | Erfasst Lautsprecher- (Downlink-) Audioframes. |
Track::stop | Schließt und finalisiert die Downlink-Datei. |
RecordTrack::stop | Schließt und finalisiert die Uplink-Datei. |
android::AudioFlinger::RecordThread::RecordTrack::stop(void)_ZN7android12AudioFlinger12RecordThread11RecordTrack4stopEv.ac.bclibaudioflinger.so
RecordTrack::getNextBuffer, Track::getNextBuffer, usw.) sind nicht exportiert und libaudioflinger.so hat keine PLT/GOT-Einträge für sie.
dlsym()- oder PLT-basierte Hooking-Mechanismen nicht verwenden.target_addr = base_addr(libaudioflinger) + offset
DobbyHook(target_addr, hook_fn, &orig_fn)