
๐ฌ libaudioflinger.so๋ฅผ ๋์ ์ผ๋ก ํํน(hooking)ํ์ฌ ์ค์๊ฐ VoIP ์ค๋์ค ์บก์ฒ(Uplink/Downlink)๋ฅผ ์ํํ๋ ๊ณ ๊ธ Android ์ฐ๊ตฌ ๋๊ตฌ์ ๋๋ค. Android 14์ WhatsApp, Signal, Telegram์์ ํ ์คํธ ๋ฐ ๊ตฌ์ถ๋์์ต๋๋ค.
๋ชฉํ: Android์ audioserver(ํนํ libaudioflinger.so)๋ฅผ ํํนํ๊ณ ์์คํ
์ด ํตํ(communication) ๋ชจ๋์ ์์ ๋ ์
๋งํฌ(๋ง์ดํฌ) ๋ฐ ๋ค์ด๋งํฌ(์คํผ์ปค) PCM ๋ฒํผ๋ฅผ ๊ธฐ๋กํ์ฌ VoIP ์คํธ๋ฆผ ์บก์ฒ๋ฅผ ์์ฐํฉ๋๋ค.
์ปจํธ๋กค๋ฌ ์ฑ (Android)
SELINUX ์ ์ฑ
์ค์ , ํ์ด๋ก๋ ์ฃผ์
, ๋ฐ์ดํฐ ์ด๋, ์ฌ์์ ๊ด๋ฆฌํ๋ 9๊ฐ์ ๋ฒํผ์ด ์๋ UI์
๋๋ค.
ํ์ด๋ก๋ (libaudiohook.so)
์ฑ ํ๋ก์ ํธ์ ์ผ๋ถ๋ก ๋น๋๋๋ C++ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, Dobby๋ฅผ ์ฌ์ฉํ์ฌ ๋ด๋ถ AudioFlinger ๋ฉ์๋๋ฅผ ํํนํ๊ณ ์์ PCM ๋ฒํผ๋ฅผ ์ธ์
๋๋ ํฐ๋ฆฌ์ ๊ธฐ๋กํฉ๋๋ค.
ํ์ฒ๋ฆฌ
์ถ๊ฐ ๋๊ตฌ์ธ tools/audioparser.py๋ ์์ .ac(๋ค์ด๋งํฌ)/.bc(์
๋งํฌ) ํ์ผ์ WAV๋ก ๋ณํํฉ๋๋ค. ์ฑ์ ํ์ผ ๊ด๋ฆฌ์๋ ์ฑ ๋ด์์ ๋ณํ ๋ฐ ์ฌ์ํ ์ ์์ต๋๋ค.
์ฐ๊ตฌ ์ ํธ๋ฆฌํฐ
์ด๊ธฐ ํจ์ ์ถ์ ๋ฐ ์คํ์
๋ฐ๊ฒฌ์ ์ํ Frida ์คํฌ๋ฆฝํธ; ์ฌ๋ณผ/์คํ์
๋ฐ ๊ธฐํ ์ค๋ํซ์ ์ํ ๋ถ์ ํ์ผ.
์ด Android ์ ํ๋ฆฌ์ผ์ด์
์ audioserver๋ฅผ ํตํ VoIP ๋
น์์ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ทธ๋ํฝ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. Android ์ค๋์ค ์คํ์ ํํนํ์ฌ VoIP ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง์ดํฌ ๋ฐ ์คํผ์ปค ์ค๋์ค๋ฅผ ์บก์ฒํ๋ ๋ค์ดํฐ๋ธ ํ์ด๋ก๋์ ํตํฉ๋ฉ๋๋ค.
์ด ์ฑ์ ํ์ํ SELinux ์ ์ฑ ์ฃผ์ , ๋ชจ๋ํฐ๋ง ์์/์ค์ง, ๊ธฐ๋ก๋ ๋ฐ์ดํฐ ๊ด๋ฆฌ, ์บก์ฒ๋ VoIP ์ค๋์ค ํ์ผ ์ฌ์์ ํ ์ ์๋ ์ ์ด ์ผํฐ ์ญํ ์ ํฉ๋๋ค.
๋ฉ์ธ ์กํฐ๋นํฐ์๋ 9๊ฐ์ ์ ์ด ๋ฒํผ์ด ์์ต๋๋ค:
์ ์ฑ
์ฃผ์
audioserver์ ์ด ์ฑ์ด ํจ๊ป ์๋ํ๋ ๋ฐ ํ์ํ SELinux ์ ์ฑ
์ ์ฃผ์
ํฉ๋๋ค.
๋ชจ๋ํฐ๋ง ์์
๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ด๋ก๋๋ฅผ audioserver์ ์ฃผ์
ํ์ฌ RecordTrack ๋ฐ PlaybackTrack์ ํํนํจ์ผ๋ก์จ VoIP ์ค๋์ค ์บก์ฒ๋ฅผ ํ์ฑํํฉ๋๋ค. ํ๋ก์ธ์ค ์ฃผ์
์๋ **AndKittyInjector**๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ชจ๋ํฐ๋ง ์ค์ง
audioserver ํ๋ก์ธ์ค๋ฅผ ๋ค์ ์์ํ์ฌ ๋ชจ๋ํฐ๋ง์ ์ค์งํ๊ณ ์ฃผ์
๋ ํํฌ๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
๋ฐ์ดํฐ ๋ณต์ฌ
์บก์ฒ๋ ์์ PCM ์ค๋์ค๋ฅผ ์์ ๋๋ ํฐ๋ฆฌ /data/local/tmp/voip์์ /sdcard/voip๋ก ๋ณต์ฌํฉ๋๋ค.
๋ก๊ทธ ๋ณด๊ธฐ
์ฃผ์
, ํํน, ๋
น์ ์ํ์ ๊ด๋ จ๋ ๋ก๊ทธ๋ฅผ ํ์ํฉ๋๋ค.
SELinux ํ์ฑํ
SELinux ๊ฐ์ (enforcing) ๋ชจ๋๋ฅผ ๋ณต์ํฉ๋๋ค.
SELinux ๋นํ์ฑํ
SELinux๋ฅผ ํ์ฉ(permissive) ๋ชจ๋๋ก ์ค์ ํฉ๋๋ค. ์ฃผ์
๋ ์ ์ฑ
์ด ์คํจํ ๋ ์ฌ์ฉํฉ๋๋ค.
์ค๋์ค ์ฌ์
์ฌ์ฉ์ ์ง์ VoIP ํ์ผ ๊ด๋ฆฌ์(/sdcard/voip/)๋ฅผ ์ฝ๋๋ค:
๋ฐ์ดํฐ ์ญ์
/data/local/tmp/voip ๋ฐ ์ ๋ชจ๋ ์ค๋์ค ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํฉ๋๋ค.
: ๋ฐ์ดํฐ ์ญ์ ํ์๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋๋ ํฐ๋ฆฌ ์์ฑ์ ์ํด ์ ๋ค์ ์ฃผ์
ํด์ผ ํฉ๋๋ค.
+----------------------+
| |
| App MainActivity |
| |
| |
|(9 Control Buttons UI)|
| |
| |
+----------+-----------+
|
|
|
+----------v-----------+
| |
| JNI Layer |
| |
| Selinux, Process Inje|
| ction, |
| |
| |
+----------------------+
์ด ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ **audioserver**์ ์ฃผ์
๋์ด AUDIO_MODE_IN_COMMUNICATION์ ๊ฐ์งํ๊ณ ๋ฏธ๋ฆฌ ์ ์๋ ํจํค์ง ์ด๋ฆ ์งํฉ์ ๋ํด Android ์ค๋์ค ์คํ์์ ์ง์ VoIP ์ค๋์ค ์คํธ๋ฆผ์ ์บก์ฒํฉ๋๋ค.
libaudioflinger.so ๋ด๋ถ์ ์ค์ํ ๋ฉ์๋๋ฅผ ๊ฐ๋ก์ฑ๊ธฐ ์ํด Dobby ์ธ๋ผ์ธ ํํน ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์
๋งํฌ(๋ง์ดํฌ) ๋ฐ ๋ค์ด๋งํฌ(์คํผ์ปค) ์ค๋์ค ์คํธ๋ฆผ์ด ๋ชจ๋ ์บก์ฒ๋์ด ์ดํ ์ฒ๋ฆฌ๋ฅผ ์ํด ์ธ์
ํ์ผ์ ๊ธฐ๋ก๋ฉ๋๋ค.
์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ AudioFlinger ๋ฐ ๊ด๋ จ ํด๋์ค ๋ด๋ถ์ ๋ค์ ํจ์์ ํํฌ๋ฅผ ์ค์นํฉ๋๋ค:
์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ UID โ ํจํค์ง ๋งคํ์ ๊ธฐ๋ฐ์ผ๋ก ์คํธ๋ฆผ์ ํํฐ๋งํฉ๋๋ค.
ํ์ฌ ๋ชจ๋ํฐ๋ง๋๋ ์ฑ:
com.whatsappcom.whatsapp.w4b (WhatsApp Business)org.thoughtcrime.securesms (Signal)org.telegram.messengerorg.telegram.messenger.webaudioserver_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์ ๋ณด๊ด)์ผ๋ก ์ฃผ์๋ฅผ ํด์ํฉ๋๋ค.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.py์ฉ Pythonapp/์ ์ฝ๋๋ค.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 ์ํธ ์์ฉ์ ํ์ํ SELinux ๊ท์น์ ์ค๋นํฉ๋๋ค.audioserver์ ํ์ด๋ก๋๋ฅผ ์ฃผ์
ํฉ๋๋ค.audioserver๋ฅผ ๋ค์ ์์ํฉ๋๋ค./data/local/tmp/voip/โฆ์์ /sdcard/voip/๋ก ์ด๋ํฉ๋๋ค(์์ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ๋ฆฌํฉ๋๋ค). adb pull /sdcard/voip/
python3 tools/audioparser.py voip/
์ถ๊ฐ ๋ฒํผ:
- "๋ก๊ทธ ๋ณด๊ธฐ(View Logs)": ์ธ์ ํฐ/ํํฌ ์ํ๋ฅผ ํ์ธํฉ๋๋ค.
- "SELinux ํ์ฑํ" / "SELinux ๋นํ์ฑํ": ์ ์ฑ ์ด ๋๋ฌด ์๊ฒฉํ ๊ฒฝ์ฐ ๋ฉ์์ ๊ฐ์ /ํ์ฉ ๋ชจ๋๋ฅผ ์ ํํฉ๋๋ค.
- "๋ฐ์ดํฐ ์ญ์ (Delete Data)":
/data/local/tmp/voip/์/sdcard/voip/๋ฅผ ๋ชจ๋ ์ ๋ฆฌํฉ๋๋ค.
dlsym์ผ๋ก ์ฌ๋ณผ์ ์ง์ ์ฐพ์ ์ ์์ต๋๋ค.dlsym์ ์คํจํ ์ ์์ต๋๋ค.offsets.h)์ ๋ํด base + ํ๋์ฝ๋ฉ๋ ์คํ์
์ ์ฌ์ฉํ๊ณ , Frida ์ฌ๋ณผ ๋คํ์ IDA-PRO๋ก ๊ฒ์ฆํฉ๋๋ค.AudioFlinger::setMode(IN_COMMUNICATION)์์ ์บก์ฒ ํํฌ๋ฅผ ๊ฑธ๊ณ , ์ ํ์ ๊ธฐ๋กํ๋ฉฐ, ์ ์ญ ๋ชจ๋ ํ๋๊ทธ๋ฅผ ์ ์ฅํฉ๋๋ค.audioserver์์ IPC๊ฐ ์ฐจ๋จ๋ ์ ์์ต๋๋ค..tmp๋ก ์์ฑํ๊ณ , stop()์์ .ac(๋ค์ด๋งํฌ) ๋๋ .bc(์
๋งํฌ)๋ก ์ด๋ฆ์ ๋ณ๊ฒฝํฉ๋๋ค.frameworks/av/services/audioflinger (AudioFlinger, PlaybackThread, RecordThread)system/media/audio (์ค๋์ค ํ์, ์์ฑ, ์ฑ๋ ๋ง์คํฌ)/sdcard/voipaudioserver| Function | Purpose |
|---|
AudioFlinger::setMode | IN_COMMUNICATION ๋ชจ๋(VoIP ํ์ฑ)๋ก์ ์ ํ ๋ฐ ์ดํ์ ์ถ์ ํฉ๋๋ค. |
RecordTrack::getNextBuffer | ๋ง์ดํฌ(์ ๋งํฌ) ์ค๋์ค ํ๋ ์์ ์บก์ฒํฉ๋๋ค. |
PlaybackThread::Track::getNextBuffer | ์คํผ์ปค(๋ค์ด๋งํฌ) ์ค๋์ค ํ๋ ์์ ์บก์ฒํฉ๋๋ค. |
Track::stop | ๋ค์ด๋งํฌ ํ์ผ์ ๋ซ๊ณ ๋ง๋ฌด๋ฆฌํฉ๋๋ค. |
RecordTrack::stop | ์ ๋งํฌ ํ์ผ์ ๋ซ๊ณ ๋ง๋ฌด๋ฆฌํฉ๋๋ค. |
android::AudioFlinger::RecordThread::RecordTrack::stop(void)_ZN7android12AudioFlinger12RecordThread11RecordTrack4stopEvlibaudioflinger.so์ PLT ํํฌ ์์
RecordTrack::getNextBuffer, Track::getNextBuffer ๋ฑ)๋ ๋ด๋ณด๋ด์ง์ง ์์ผ๋ฉฐ libaudioflinger.so์๋ ์ด์ ๋ํ PLT/GOT ํญ๋ชฉ์ด ์์ต๋๋ค.
dlsym()์ด๋ PLT ๊ธฐ๋ฐ ํํน ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ ์ ์์์ต๋๋ค.target_addr = base_addr(libaudioflinger) + offset
DobbyHook(target_addr, hook_fn, &orig_fn)