미디어 플레이어로 위장한 프록시웨어 분석

Post image

안녕하세요. 분석팀의 Jiyong입니다.

최근 보이스피싱 악성 앱이나 정보 탈취형 악성코드에 대한 분석 사례는 많이 공유되고 있지만, 오늘은 조금 다른 유형의 위협을 소개해 드리려 합니다. 바로 프록시웨어(Proxyware) 입니다.

프록시웨어란 사용자 몰래 디바이스를 프록시 서버로 전환하여 제 3자의 인터넷 트래픽이 피해자의 네트워크를 경유하도록 만드는 악성코드입니다. 피해자 기기에서 직접 데이터를 탈취하거나 금전을 요구하는 방식이 아니어서 피해가 드러나지 않을 뿐, 그 위험성은 결코 낮지 않습니다.

피해자의 IP 주소가 사이버 공격의 경유지로 활용될 수 있으며 피해자 본인은 이를 전혀 인지하지 못한 채 범죄 인프라의 일부가 될 수 있습니다.

이번에 분석한 샘플은 VLC Media Player로 위장한 프록시웨어로, 기기의 홈 런처를 탈취하여 실행 상태를 지속적으로 유지하면서 프록시 터널을 구성하는 정교한 구조를 가지고 있습니다. 정적 분석부터 네이티브 라이브러리, 실제 네트워크 패킷까지 코드 레벨에서 파헤쳐본 결과를 공유합니다.

앱 개요

분석 대상 앱의 기본 정보는 다음과 같습니다.

항목
파일명 4E3ADAD4E96E09ED78F1584F286128EA.apk
파일 크기 19,708,152 bytes (약 18.8 MB)
MD5 4E3ADAD4E96E09ED78F1584F286128EA
패키지명 com.obluem.tea412
앱 이름 VLC Media Player
minSdk / targetSdk 24 (Android 7.0) / 34 (Android 14)
인증서 DN CN=Build, OU=Auto, O=Auto, L=City, ST=State, C=US
인증서 SHA-256 fb25eb8b26063796e5204cdb7a7045cb28fa347c86b19b17aeab3f9ba8c59237

[표 1] 앱 기본 정보

패키지명 com.obluem.tea412의 끝부분인 tea412는 여러 곳에서 식별자로 반복 사용됩니다. Runtime.setBrand("tea412")로 네이티브 엔진에 전달되고 C2 통신 경로(/launch/tea412/…)와 핸드셰이크 페이로드(1.9.1-tea412)에도 포함됩니다. 이러한 구조로 볼 때, tea412는 이 앱의 배포 채널을 식별하는 고유 값으로 사용되는 것으로 보입니다.

인증서의 CN=Build, OU=Auto, O=Auto는 자동 생성 서명의 전형적 패턴으로 정식 개발사에서 발급한 인증서가 아닙니다. 런처에는 아이콘이 표시되지 않으며 기본 홈 앱 설정 화면에서만 확인할 수 있습니다.

image01.png

[그림 1] 기본 홈 앱 설정 화면에서 “VLC Media Player”로 표시되는 모습

분석 결과, 본 앱은 기본 홈 앱으로 등록되어 런처에 아이콘 없이 실행되며 네이티브 라이브러리(libsdklib.so)가 별도 프로세스에서 QUIC 기반 프록시 터널을 구동합니다. 서비스 종료 시 자동 재시작 메커니즘이 작동하고 부팅 시 자동 시작 및 배터리 최적화 예외까지 확보하여 사실상 종료가 불가능한 구조입니다. 또한 clearwatch.tv를 통한 기기 등록과 Bugfender를 통한 원격 로그 모니터링으로 정보 유출이 이루어지며, 앱 제거 시에는 “업데이트 완료” 위장 다이얼로그를 띄워 재설치를 유도합니다.

이어지는 챕터에서 각 악성 행위를 코드 레벨에서 상세히 분석합니다.

앱 위장 및 설치 유도

본 앱은 패키지명 com.obluem.tea412로 정식 VLC 앱(org.videolan.vlc)과는 완전히 다른 패키지입니다. 그러나 앱 이름을 “VLC Media Player"로 설정하고 파란색 재생 버튼 아이콘을 사용하여 사용자가 정상 앱으로 오인하도록 유도합니다.

또한, AndroidManifest.xmlcategory.LAUNCHER 인텐트 필터가 등록되어 있지 않아 런처에 아이콘이 표시되지 않습니다. 대신 category.HOME 인텐트 필터가 등록되어 있어, 사용자가 직접 “기본 홈 앱"으로 선택해야만 동작이 시작됩니다.

이러한 구조로 볼 때, 설치 과정에서 사회공학적 기법을 통해 사용자를 유도하는 것으로 추정됩니다. 예를 들어 “업데이트를 완료하려면 홈 앱을 변경해주세요"와 같은 안내를 통해 피해자가 직접 설정을 변경하도록 유도했을 가능성이 있습니다.

사용자가 해당 앱을 기본 홈 앱으로 등록하면 앱은 MainActivity.onResume()에서 배터리 최적화 예외, 알림 권한, 홈 앱 등록 여부를 순차적으로 확인합니다. 각 단계가 충족되지 않으면 해당 권한을 요청하고, 모든 조건이 충족되면 HomeProxyActivity로 전환하여 본격적인 악성 행위를 시작합니다.

image02.png

[그림 2] 권한 요청 순서

프록시 서비스 구조

앞서 살펴본 홈 앱 설정 유도는 단순히 앱을 숨기기 위한 것이 아닙니다. 기본 홈 앱으로 등록되면 Android 시스템이 해당 프로세스를 높은 우선순위로 유지하기 때문에, 프록시 서비스의 영구 실행을 보장하는 핵심 수단이 됩니다.

HomeProxyActivityandroid.intent.category.HOME 인텐트 필터를 등록하여 시스템 홈 앱으로 동작합니다. 최초 실행 시 기존 런처의 패키지명과 클래스명을 quic_prefs에 저장해두고, 이후 홈 버튼이 눌릴 때마다 기존 런처로 포워딩합니다. 사용자 입장에서는 홈 버튼이 정상 동작하는 것처럼 보이므로 악성 앱이 홈 앱으로 등록되어 있다는 사실을 인지하기 어렵습니다.

image03.png

[그림 3] 기존 런처 저장 및 포워딩 로직

실제 프록시 동작은 SdkService에서 수행됩니다. 이 서비스는 AndroidManifest에 :quicService로 선언되어 앱 본체와 별도 프로세스에서 실행됩니다. 별도 프로세스를 사용하면 메인 앱이 종료되더라도 서비스가 독립적으로 유지되며 메모리 관리도 분리됩니다.

onStartCommand()에서의 초기화 순서는 다음과 같습니다.

// 포그라운드 서비스 알림 생성
startForeground(notificationId, notification);

// WakeLock 획득 → CPU 수면 방지
PowerManager.WakeLock wakeLock = powerManager
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SdkService");
wakeLock.acquire();

// NativeProxyThread에서 네이티브 프록시 루프 실행
Runtime runtime = new Runtime();
runtime.loadLibrary();           // libsdklib.so 로드
runtime.setBrand("tea412");      
runtime.setDeviceId(deviceId);   // SHA-256 디바이스 해시
runtime.run();                   // 프록시 루프 진입

// START_STICKY 반환 → 시스템이 서비스 종료 후 재생성
return START_STICKY;

또한, 해당 앱은 서비스 종료를 감지하는 4개의 콜백 모두에서 AlarmManager를 통해 2.5초 후 서비스를 재시작하는 지속성 유지 구조를 가지고 있습니다.

image04.png

[그림 4] 서비스 재시작 로직

네이티브 라이브러리 분석

SdkService에서 Runtime.loadLibrary()로 로드되는 libsdklib.so는 프록시의 핵심 엔진입니다.

해당 앱의 com.coinsurf.Runtime 클래스가 JNI를 통해 호출하는 네이티브 함수는 다음과 같습니다.

함수명 IDA 주소 역할
Java_com_coinsurf_Runtime_run 0x19F95C 메인 프록시 루프 진입
Java_com_coinsurf_Runtime_setBrand 0x19F960 배포판 식별자 설정 (“tea412”)
Java_com_coinsurf_Runtime_setDeviceId SHA-256 디바이스 ID 전달

[표 2] 네이티브 라이브러리 내 주요 함수

Java_com_coinsurf_Runtime_run 함수는 JNI_thunk로, 내부의 실제 프록시 루프 함수 run()(0x19AF64)을 호출합니다. 이 함수는 디컴파일 결과가 약 54KB에 달하며, Rust 컴파일러 최적화로 인해 심볼이 소실된 상태입니다.

image05.png

[그림 5] JNI thunk → run() 호출부

run() 함수에서 호출하는 sub_17E804(0x17E804)는 프록시 서버 설정을 수신하는 함수입니다. 이 함수의 디컴파일 결과에서 다음과 같은 연결된 문자열이 확인됩니다.

image06.png

[그림 6] sub_17E804(0x17E804) : 프록시 설정 수신 URL 및 구조체 참조

SkipServerVerification 문자열은 TLS 인증서 검증을 우회하는 옵션으로 추정되며, ServerEntry 구조체는 수신한 설정에서 프록시 서버 정보를 파싱하는 데 사용되는 것으로 보입니다.

또한, 바이너리에 포함된 Rust 의존성 패키지 문자열을 통해 프록시의 기술 스택을 확인할 수 있습니다.

크레이트 버전 역할
quinn 0.11.8 QUIC 프로토콜 구현체
quinn-proto 0.11.12 QUIC 프로토콜 상태 머신
rustls 0.23.27 TLS 1.3 구현체
tokio 1.45.1 비동기 런타임
ureq 3.0.11 HTTP 클라이언트 (설정 API 호출용)
serde / serde_json 1.0.210 / 1.0.140 JSON 직렬화/역직렬화

[표 3] libsdklib.so 내 Rust 크레이트 목록

이를 종합하면, libsdklib.so는 QUIC+TLS 1.3 기반의 프록시 터널을 구현하고 있다고 볼 수 있으며, 네트워크 트래픽을 통해 검증해 보겠습니다.

네트워크 통신 분석

감염된 기기는 총 4개 도메인과 통신하며, 각각 역할이 분리되어 있습니다.

순서 도메인 프로토콜 역할
1 clearwatch.tv HTTPS GET 기기 등록
2 api.bugfender.com HTTPS POST 원격 로그 모니터링
3 coinsurf.com HTTPS 프록시 설정 수신
4 srv.coinsurf.com DNS 프록시 릴레이 서버 IP 목록

[표 4] 감염 기기의 외부 통신 채널

기기 등록(clearwatch.tv)과 원격 모니터링(Bugfender)은 정보 유출 채널 파트에서 상세히 다루고, 먼저 프록시 통신 흐름에 집중하겠습니다.

네이티브 라이브러리 분석에서 확인한 sub_17E804 함수가 다음 URL로 설정을 요청합니다.

HTTPS → https://coinsurf.com/api/v4/client/settings

ureq HTTP 클라이언트를 사용하며, 응답에는 프록시 서버 연결에 필요한 설정이 포함되는 것으로 추정됩니다.

패킷 캡처에서 srv.coinsurf.com에 대한 DNS 응답을 확인할 수 있습니다.

image07.png

[그림 7] DNS 응답 - coinsurf.com 릴레이 서버 목록

응답을 보면 TTL이 300초로 짧아 서버 목록이 주기적으로 갱신됨을 알 수 있습니다. DNS 응답 직후, 기기는 수신한 7개의 릴레이 서버 IP에 대해 동시 연결을 시도합니다. 각 IP에 :443:5051 두 포트로 접속하며 전체 연결은 약 0.15초 이내에 일괄 발송됩니다. 이 중 가장 빠르게 응답한 서버와 연결을 수립하는 race 방식입니다.

트래픽 분석 결과, 초기 핸드셰이크(153바이트)에는 api_key, device_hash, user_agent 등의 인증 정보가 평문으로 포함되어 있습니다.

필드 의미
api_key f90719822-cb99-4ccd-95a4-8f5d5ccc6ca4 CoinSurf 프록시 인프라 API 키
device_hash 92c240ac…484808 Runtime.setDeviceId()로 전달된 SHA-256 해시
user_agent android#Unknown#1.9.1-tea412 “OS#기기모델#SDK버전-브랜드” 형식

[표 5] 초기 핸드셰이크 페이로드 (153바이트, 평문)

연결 수립 이후에는 암호화된 데이터(1,201바이트)가 전송되며, 이 시점부터 QUIC+TLS 1.3 터널을 통한 프록시 트래픽 중계가 시작됩니다.

image08.png

[그림 8] 암호화된 프록시 트래픽

앞서 네트워크 패킷에서 식별한 정보를 종합하면, 분석 대상 앱의 프록시 동작 구조는 다음과 같습니다.

image09.png

[그림 9] 프록시 동작 구조

  1. CoinSurf 고객(프록시 구매자)이 릴레이 서버에 프록시 요청
  2. 릴레이 서버가 QUIC+TLS 1.3 터널을 통해 피해자 기기에 트래픽 전달
  3. 피해자 기기가 목적지에 대신 접속 → 목적지는 피해자 IP를 접속자로 인식
  4. 응답을 역순으로 반환

감염 기기의 사용자는 자신의 기기가 프록시 노드로 동작하고 있다는 사실을 알 수 없습니다. 따라서 해당 과정에서 발생하는 행위의 법적 책임이 피해자에게 전가될 위험이 있습니다.

정보 유출 채널

[표 4]에서 확인한 4개의 외부 통신 채널 중, 프록시 설정 수신과 릴레이 서버 목록은 앞서 다루었습니다. 이번에는 나머지 두 채널인 기기 등록과 원격 로그 모니터링을 분석해보겠습니다.

분석 대상 앱은 HomeProxyActivity.onResume()에서 홈 런처 탈취 직후, 다음 URL로 기기 등록 요청을 전송합니다.

GET https://clearwatch.tv/launch/tea412/android/allowedLauncher?id=<deviceId>
파라미터 출처
tea412 배포판 식별자(브랜드) Runtime.setBrand("tea412")
android 플랫폼 하드코딩
id SHA-256 디바이스 해시 Runtime.setDeviceId()와 동일 값

[표 6] clearwatch.tv 요청 파라미터

deviceId는 다음 우선순위로 생성됩니다.

  1. /etc/machine-id 또는 /etc/hostid
  2. Settings.Secure.ANDROID_ID
  3. UUID 생성 → device_id_prefs에 영구 저장

생성된 값은 SHA-256 해시를 거쳐 전송됩니다. HTTP 요청의 User-Agent는 Android <VERSION> (SDK <API>) / <MANUFACTURER> <MODEL> 형식으로, 기기의 OS 버전과 모델명이 함께 노출됩니다.

이 요청은 앱 실행 후 최초 1회만 실행되며 URL 경로의 allowedLauncher는 기기가 프록시 노드로 등록 가능한 상태인지 확인하는 용도로 추정됩니다.

image10.png

[그림 10] clearwatch 등록 요청 패킷

한편, SdkApplication.onCreate()에서 초기화된 Bugfender SDK는 기기 상태를 api.bugfender.com으로 전송합니다. BrandName이라는 커스텀 태그에 배포판 식별자 tea412를 값으로 등록합니다. 이를 통해 공격자는 Bugfender 대시보드에서 배포판별로 감염 기기를 필터링하고 관리할 수 있습니다.

image11.png

[그림 11] Bugfender 키값 등록 요청 패킷

이후 기기 상태 정보를 지속적으로 api.bugfender.com에 전송합니다.

image12.png

[그림 12] Bugfender 기기 상태 전송

Bugfender는 앱 개발자가 디버깅 목적으로 사용하는 합법적인 SaaS 로그 플랫폼입니다. 그러나 본 앱에서는 사용자 동의 없이 기기 식별 정보와 상태를 원격으로 수집하는 모니터링 도구로 악용되고 있습니다.

마치며

분석 결과를 요약하자면, 이 앱은 VLC Media Player를 사칭한 CoinSurf SDK 기반 프록시웨어 입니다. 홈 런처 탈취와 재시작 메커니즘으로 서비스가 지속적으로 실행되도록 보장합니다. 이를 통해 사용자 모르게 기기를 제3자의 프록시 노드로 동작시킵니다.

만약 해당 앱에 감염되었다면 즉시 설정 > 앱에서 해당 앱을 강제 종료 및 삭제하고, 기본 홈 앱 설정이 변경되지 않았는지 확인하시기 바랍니다. 프록시를 통해 중계된 트래픽은 피해자의 IP로 기록되므로 감염 기간 중 비정상적인 네트워크 사용량이 발생했는지도 함께 점검할 필요가 있습니다.

프록시웨어는 기기에 눈에 띄는 이상을 일으키거나 데이터를 탈취하지 않기 때문에 피해를 체감하기 어렵지만, 자신도 모르는 사이에 스크래핑, 광고 사기, 계정 탈취 등에 자신의 IP가 사용될 수 있다는 점에서 결코 가볍게 볼 수 없는 위협입니다.

이번 포스팅이 프록시웨어라는 비교적 생소한 유형의 악성코드에 대한 이해를 넓히는 데 도움이 되었으면 합니다.

긴 글 읽어주셔서 감사합니다.

You May Also Like

국민서비스포털 사칭 보이스피싱 앱 분석
국민서비스포털 사칭 보이스피싱 앱 분석

안녕하세요. 분석팀의 Jiyong입니다. 최근 보이스피싱 범죄가 날로 고도화되고 있습니다. 경찰청 보이스피싱 현항에 따르면 기관사칭형 보이스피싱 …

안녕하세요. 분석팀의 Jiyong입니다. 최근 보이스피싱 범죄가 날로 고도화되고 있습니다. 경찰청 보이스피싱 현항에 따르면 기관사칭형 보이스피싱 발생 건수는 2016년 3,384건에서 2025년 13,323건으로 꾸준한 증가세를 보이고 있으며, 2025년 피해액은 9,884억원에 달합니다. 최근 보이스피싱 범죄는 대부분 악성 앱 설치를 통한 개인정보 탈취로 시작되며, 카드 배송이나 사건 조회 등으로 위장해 피해자의 휴대전화에 악성 앱을 설치하도 …

안드로이드 악성코드 ALBIRIOX 심층 분석
안드로이드 악성코드 ALBIRIOX 심층 분석

안녕하세요. 분석팀의 Jiyong입니다. 모바일 악성코드가 단순한 정보 유출을 넘어 사용자의 가상화폐 지갑을 직접 노리는 형태로 고도화되고 있습 …

안녕하세요. 분석팀의 Jiyong입니다. 모바일 악성코드가 단순한 정보 유출을 넘어 사용자의 가상화폐 지갑을 직접 노리는 형태로 고도화되고 있습니다. 오늘은 보안 업계에서 이슈가 됐었던 악성코드를 직접 입수하여, 껍데기인 드로퍼부터 악성 행위의 심장부까지 코드 레벨에서 파헤쳐본 분석 결과를 공유하려 합니다.