
🔬 Продвинутый исследовательский инструмент для Android для захвата VoIP-аудио в реальном времени (Uplink/Downlink) путём динамического хука libaudioflinger.so. Протестирован и собран на WhatsApp, Signal и Telegram на Android 14.
Цель: Продемонстрировать захват VoIP-потока путем перехвата audioserver в Android (конкретно libaudioflinger.so) и записи PCM-буферов восходящего (микрофон) и нисходящего (динамик) каналов, когда система находится в коммуникационном режиме.
Приложение-контроллер (Android)
Интерфейс с 9 кнопками для управления настройкой политики SELinux, инъекцией payload, перемещением данных и воспроизведением.
Payload (libaudiohook.so)
C++-библиотека (собирается как часть проекта приложения), которая перехватывает внутренние методы AudioFlinger с помощью Dobby и записывает сырые PCM-буферы в директорию сессии.
Постобработка
Дополнительный инструмент tools/audioparser.py преобразует сырые файлы .ac (Downlink)/.bc (Uplink) в WAV. Файловый менеджер приложения также может конвертировать и воспроизводить их прямо в приложении.
Исследовательские утилиты
Frida-скрипты для первоначального трассирования функций и поиска смещений; файлы анализа для символов/смещений и другие фрагменты.
Это Android-приложение предоставляет графический интерфейс для управления записью VoIP через audioserver. Оно интегрируется с нативным payload, который перехватывает аудиостек Android для захвата звука с микрофона и динамика от VoIP-приложений.
Приложение служит центром управления: позволяет внедрять необходимые политики SELinux, запускать/останавливать мониторинг, управлять записанными данными и воспроизводить захваченные VoIP-аудиофайлы.
Главная активность содержит 9 кнопок управления:
Инъекция политик
Внедряет необходимые политики SELinux для совместной работы audioserver и этого приложения.
Запуск мониторинга
Внедряет payload (общую библиотеку) в audioserver, включая захват VoIP-аудио через перехват RecordTrack и PlaybackTrack. Для инъекции в процесс используется AndKittyInjector.
Остановка мониторинга
Перезапускает процесс audioserver, останавливая мониторинг и удаляя внедренные хуки.
Копирование данных
Копирует захваченный сырой PCM-аудио из временной директории /data/local/tmp/voip в /sdcard/voip.
Просмотр журналов
Отображает журналы, связанные с инъекцией, перехватом и статусом записи.
Включить SELinux
Восстанавливает enforcing-режим SELinux.
Отключить SELinux
Переводит SELinux в permissive-режим. Используйте, если внедренные политики не срабатывают.
Воспроизведение аудио
Открывает собственный VoIP-файловый менеджер (/sdcard/voip/):
+----------------------+
| |
| App MainActivity |
| |
| |
|(9 Control Buttons UI)|
| |
| |
+----------+-----------+
|
|
|
+----------v-----------+
| |
| JNI Layer |
| |
| Selinux, Process Inje|
| ction, |
| |
| |
+----------------------+
Эта общая библиотека внедряется в audioserver для обнаружения AUDIO_MODE_IN_COMMUNICATION и захвата VoIP-аудиопотоков напрямую из аудиостека Android для заданного набора имен пакетов.
Для перехвата критических методов внутри libaudioflinger.so используется фреймворк inline-хукинга Dobby.
Аудиопотоки восходящего канала (микрофон) и нисходящего канала (динамик) захватываются и записываются в файлы сессии для последующей обработки.
Библиотека устанавливает хуки на следующие функции внутри AudioFlinger и связанных классов:
Библиотека фильтрует потоки на основе маппинга UID → пакет.
Текущие отслеживаемые приложения:
com.whatsappcom.whatsapp.w4b (WhatsApp Business)org.thoughtcrime.securesms (Signal)org.telegram.messengerorg.telegram.messenger.webВы также можете добавлять другие приложения внутри audioserver_hook.cpp:
static const char* kTargetPackages[] = {
"com.whatsapp",
"com.whatsapp.w4b",
"org.thoughtcrime.securesms",
"org.telegram.messenger",
"org.telegram.messenger.web"
};
При инъекции в audioserver создается директория сессии по пути:
/data/local/tmp/voip/audioserver_session_<timestamp>/
Файлы сначала создаются с расширением .tmp, затем переименовываются при остановке трека:
<packageName>_<sampleRate>_<timestamp>.bc<packageName>_<sampleRate>_<timestamp>.acПример сессии:
/data/local/tmp/voip/audioserver_session_1725389200/
├── com.whatsapp_48000_1725389201_123456.ac
├── com.whatsapp_48000_1725389201_123789.bc
Поскольку целевая библиотека лишена символов (stripped), и методы не экспортируются в libaudioflinger.so, для успешного перехвата нам нужны точные смещения методов и других связанных компонентов.
Эти смещения можно получить из статического анализа с помощью IDA-PRO или из динамического анализа с помощью Frida.
Когда смещения известны, их можно заменить в заголовочном файле offsets.h.
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)_ZN7android12AudioFlinger14PlaybackThread5Track4stopEvИх можно получить с помощью статического анализа.
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) │
└───────────────────────────┘
Используемый процесс:
AudioFlinger управляет воспроизведением/захватом через PlaybackThread и RecordThread.PlaybackThread::Track (нисходящий канал) и RecordThread::RecordTrack (восходящий канал).app/src/main/cpp/include/offsets.h), что позволяет работать со stripped-символами.MODE_IN_COMMUNICATIONМы перехватываем AudioFlinger::setMode(int mode) и поддерживаем глобальное состояние:
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/ в Android Studio.libaudiohook.so) как часть проекта.adb install -r app/build/outputs/apk/debug/app-debug.apk
или установите предоставленный app-release.apk:
adb install -r app-release.apk
Если вы разделяете артефакты, вы также можете отправить общую библиотеку для тестирования:
adb push app/src/main/jniLibs/arm64-v8a/libaudiohook.so /data/local/tmp/
audioserver в вашем тестовом окружении.audioserver.audioserver./data/local/tmp/voip/… -> /sdcard/voip/ (и очищает временную директорию). adb pull /sdcard/voip/
python3 tools/audioparser.py voip/
Дополнительные кнопки:
- «View Logs»: просмотр статуса инъекции/хуков.
- «Enable SELinux» / «Disable SELinux»: переключение enforcing/permissive в вашей лабораторной среде, если политики слишком строгие.
- «Delete Data»: очистка
/data/local/tmp/voip/и/sdcard/voip/.
Stripped-символы
dlsym.Разные символы/смещения в разных сборках
dlsym может завершиться ошибкой.offsets.h), проверенные с помощью Frida-дампов символов и IDA-PRO.Точность определения режима
AudioFlinger::setMode(IN_COMMUNICATION); логируют переходы; сохраняют глобальный флаг режима.SELinux
audioserver могут быть заблокированы.Жизненный цикл файлов и переименование
.tmp; при переименовывать в (нисходящий канал) или (восходящий канал).frameworks/av/services/audioflinger (AudioFlinger, PlaybackThread, RecordThread)system/media/audio (аудиоформаты, атрибуты, маски каналов)Удаление данных
Удаляет все аудиоданные из /data/local/tmp/voip и /sdcard/voip.
ПРИМЕЧАНИЕ: После удаления данных необходимо повторно выполнить инъекцию в audioserver, чтобы создать директорию для сохранения данных.
| Функция | Назначение |
|---|
AudioFlinger::setMode | Отслеживает переходы в/из режима IN_COMMUNICATION (VoIP активен). |
RecordTrack::getNextBuffer | Захватывает кадры аудио с микрофона (восходящий канал). |
PlaybackThread::Track::getNextBuffer | Захватывает кадры аудио с динамика (нисходящий канал). |
Track::stop | Закрывает и финализирует файл нисходящего канала. |
RecordTrack::stop | Закрывает и финализирует файл восходящего канала. |
android::AudioFlinger::RecordThread::RecordTrack::stop(void)_ZN7android12AudioFlinger12RecordThread11RecordTrack4stopEvstop().ac.bcОтсутствие PLT-хуков в libaudioflinger.so
RecordTrack::getNextBuffer, Track::getNextBuffer и т.д.) не экспортируются, и в libaudioflinger.so нет записей PLT/GOT для них.
dlsym() или механизмы хукинга на основе PLT.target_addr = base_addr(libaudioflinger) + offset
DobbyHook(target_addr, hook_fn, &orig_fn)