
🔬 An advanced Android research tool for real-time VoIP audio capture (Uplink/Downlink) by dynamically hooking libaudioflinger.so. Tested and built on WhatsApp, Signal, and Telegram on Android 14.
Goal: Demonstrate VoIP stream capture by hooking Android's audioserver (specifically libaudioflinger.so) and recording uplink (mic) and downlink (speaker) PCM buffers when the system is in communication mode.
Controller App (Android)
UI with 9 buttons to manage SELINUX policy setup, payload injection, data movement, and playback.
Payload (libaudiohook.so)
C++ shared library (built as part of the app project) that hooks internal AudioFlinger methods using Dobby and writes raw PCM buffers to a session directory.
Post-Processing
Additional tool, tools/audioparser.py converts raw .ac(Downlink)/.bc(Uplink) files to WAV. The app’s file manager can also convert & play in-app.
Research Utilities
Frida scripts for initial function tracing & offset discovery; analysis files for symbol/offset and other snippets.
This Android application provides a graphical interface for managing VoIP recording through the audioserver. It integrates with a native payload that hooks into the Android audio stack to capture microphone and speaker audio from VoIP applications.
The app serves as a control center, allowing you to inject required SELinux policies, start/stop monitoring, manage recorded data, and play captured VoIP audio files.
The main activity contains 9 control buttons:
Inject Policies
Injects the required SELinux policies for audioserver and this app to work together.
Start Monitoring
Injects the shared library payload into audioserver, enabling VoIP audio capture by hooking RecordTrack and PlaybackTrack. Uses AndKittyInjector for Process Injection.
Stop Monitoring
Restarts the audioserver process, stopping monitoring and removing injected hooks.
Copy Data
Copies captured raw PCM audio from temp directory /data/local/tmp/voip to /sdcard/voip.
View Logs
Displays logs related to injection, hooking, and recording status.
Enable SELinux
Restores SELinux enforcing mode.
Disable SELinux
Sets SELinux to permissive mode, Use when injected policies fail.
Play Audios
Opens the custom VoIP File Manager (/sdcard/voip/):
Delete Data
Deletes all audio data from both /data/local/tmp/voip and /sdcard/voip.
NOTE: After delete data, we need to reinject into audioserver for directory creation to save data.
+----------------------+
| |
| App MainActivity |
| |
| |
|(9 Control Buttons UI)|
| |
| |
+----------+-----------+
|
|
|
+----------v-----------+
| |
| JNI Layer |
| |
| Selinux, Process Inje|
| ction, |
| |
| |
+----------------------+
This shared library is injected into audioserver to detect AUDIO_MODE_IN_COMMUNICATION and capture VoIP audio streams directly from Android’s audio stack for predefined set of package names.
It uses the Dobby inline hooking framework to intercept critical methods inside libaudioflinger.so.
Both uplink (microphone) and downlink (speaker) audio streams are captured and written to session files for later processing.
The library installs hooks on the following functions inside AudioFlinger and related classes:
| Function | Purpose |
|---|---|
AudioFlinger::setMode | Tracks transitions into/out of IN_COMMUNICATION mode (VoIP active). |
RecordTrack::getNextBuffer | Captures microphone (uplink) audio frames. |
PlaybackThread::Track::getNextBuffer | Captures speaker (downlink) audio frames. |
Track::stop | Closes and finalizes downlink file. |
RecordTrack::stop | Closes and finalizes uplink file. |
The library filters streams based on UID → Package mapping.
Currently monitored apps:
com.whatsappcom.whatsapp.w4b (WhatsApp Business)org.thoughtcrime.securesms (Signal)org.telegram.messengerorg.telegram.messenger.webYou can add other applications also iniside audioserver_hook.cpp:
static const char* kTargetPackages[] = {
"com.whatsapp",
"com.whatsapp.w4b",
"org.thoughtcrime.securesms",
"org.telegram.messenger",
"org.telegram.messenger.web"
};
A session directory is created at injection into audioserver under:
/data/local/tmp/voip/audioserver_session_<timestamp>/
Files are first created with a .tmp extension, then renamed on track stop:
<packageName>_<sampleRate>_<timestamp>.bc<packageName>_<sampleRate>_<timestamp>.acExample session:
/data/local/tmp/voip/audioserver_session_1725389200/
├── com.whatsapp_48000_1725389201_123456.ac
├── com.whatsapp_48000_1725389201_123789.bc
Since target library is stripped and methods are not exported in libaudioflinger.so, we need exact offsets of methods and other related components for successful hooking.
We can extract those offsets from static analysis using IDA-PRO or from dynamic analysis using frida.
Once offsets are known we can replace them inside offsets.h header file.
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)_ZN7android12AudioFlinger14PlaybackThread5Track4stopEvandroid::AudioFlinger::RecordThread::RecordTrack::stop(void)_ZN7android12AudioFlinger12RecordThread11RecordTrack4stopEv