> 분석일: 2026-06-14
> 분석 레벨: static_deep → ml_level (C2 라이브 확인 + 엔드포인트 매핑 + 방어기제 전면 파훼)
> 패밀리: wavegrid (RuoYi `[비공개] 계열, 연락처+갤러리 탈취형)
> 원본 파일명: Fun.zip(위장) → Fun.apk (Telegram 배포 추정)
Tunf은 초대코드 기반 연락처·갤러리 탈취 악성앱이다. 정상 앱처럼 보이는 단일 로그인 화면 뒤에서, 권한이 부여되는 즉시 피해자의 전체 주소록 + 전화번호 + 통신사 정보 + 갤러리 사진 전량을 RuoYi 기반 C2 서버([비공개], [비공개])로 전송한다.
핵심 특징:
· 정적 분석 방해: 629개 액티비티 중 627개가 난수 이름의 더미(클래스 부풀리기)
· 실제 로직은 단 3개 액티비티(Login/Home/Base) + 6개 유틸 클래스
· 암호화·패킹 없음: C2 URL은 평문 상수, 통신 페이로드도 평문 JSON
· SSL 검증 자체 무력화(unsafe OkHttpClient) → 운영자 편의이자 분석가에게 MITM 자유 제공
· C2 라이브, 한국어 응답("초대코드가 잘못되었습니다") → 한국 피해자 표적
항목 · 값
패키지명 · `com.pdutcbi.bctdimp`
표시 라벨 · `Tunf`
versionName / Code · 3.0.29 / 3029
minSdk / targetSdk · 29 / 34
런처 액티비티 · `com.pdutcbi.bctdimp.view.LoginActivity`
APK SHA-256 · `4a636e12f6e195534affe8a021224e575e60c88270a02f4811fed4cd39db6646`
APK MD5 · `048188123da7d78ee71fa9d46a0d21f8`
파일 크기 · 23,355,535 bytes (≈22.3 MB)
서명 주체(DN) · `OU=pdutcbi` (자체 서명)
서명 SHA-256 · `63e12b8b782afa2df4f6f624cd185534a40853cdf27f239edea1383fc4bf10c5`
DEX 구성 · classes.dex(10.3MB) + classes2.dex(10.1MB), multidex
네이티브 코드 · 없음 (.so 0개)
서명 DN OU=pdutcbi가 패키지명 앞부분(pdutcbi)과 일치 → 운영자가 동일 빌드 파이프라인으로 자체 생성.
권한 · 목적
`READ_CONTACTS` · **주소록 전량 탈취**
`READ_MEDIA_IMAGES` / `READ_MEDIA_VIDEO` · **갤러리 사진/영상 탈취** (SDK 33+)
`READ_EXTERNAL_STORAGE` (maxSdk 32) · 구버전 갤러리 접근
`READ_PHONE_STATE` / `READ_PHONE_NUMBERS` · **[피해자 정보 비공개] 전화번호 획득**(`getLine1Number`)
`INTERNET` / `ACCESS_NETWORK_STATE` · C2 통신
SMS·위치·카메라 권한은 요청하지 않음. 단 코드(StatusUtils)에는 SMS 수집 메서드가 잔존(다른 변종에서 재사용된 흔적) — 본 빌드에서는 권한 미선언으로 비활성.
# · 방어기제 · 실태 · 파훼 결과
1 · **클래스 부풀리기** · 629 activity / 30 서브패키지(그중 26개·1,251 클래스가 더미) · `deobfuscate_core.py` **reachability BFS**로 자동 분리. 코어가 더미를 **0회 참조** → unreachable 디코이 확정
2 · **디코이 암호화 문자열** · `strings.xml`의 `cvknjykupldphsu`, `xleezfmzqobllzqapindz` (Base62 외형) · 추적 결과 **더미 액티비티의 Toast 메시지**일 뿐. 암호 키 아님 → 무시
3 · **SSL 인증서 검증 무력화** · `HttpUtil.buildUnsafeOkHttpClient`: X509TrustManager `getAcceptedIssuers`=빈 배열, `hostnameVerifier`=항상 `true` · 운영자 자해성 방어. **분석가는 MITM/프록시로 평문 가로채기 자유**
4 · **평문 트래픽 허용** · `network_security_config.xml`: `cleartextTrafficPermitted=true` · HTTP 다운그레이드 가능. 트래픽 가시성 100%
5 · 안티-분석(루팅/에뮬/Frida/디버거) · **전무** (코어 패키지 grep 0건) · 에뮬레이터·동적 분석 제약 없음
6 · 패킹/안티-탬퍼 · **없음** (dex 평문, assets 암호화 페이로드 없음) · jadx 완전 디컴파일 성공
결론: 유일하게 유효한 방어는 #1 클래스 부풀리기뿐이며, 이는 패키지 명명 통계 + 코어 참조 BFS로 완전 우회됨. 나머지는 디코이거나 오히려 분석가에게 유리.
방법: 참조 도달성(reachability) BFS. 런처 액티비티 패키지(Manifest에서 자동 추출 = view)를
시드로, 코어가 참조하는 서브패키지만 transitive하게 확장 → 나머지는 unreachable 디코이.
명명(모음비 등)에 의존하지 않으므로 다른 변종에 그대로 재사용 가능.
```
method: reachability BFS (seed=launcher activity package)
seed_subpackage: view
total_subpackages: 30 (core 4: view·util·bean·respon / dummy 26)
dummy_classes_total: 1251
dummy_classes_referenced_by_core: [] ← 0개 = PASS
real_logic: LoginActivity / HomeActivity / BaseActivity
+ ContainValue / HttpUtil / StatusUtils / GlobuleValue / PermissDialog
+ bean.InfoBeanDTO / bean.CollectBeanDTO / respon.ResposeResult
```
> 부수 발견: api 서브패키지(HttpsUtils)도 unreachable → 선언만 되고 미사용.
> 실제 통신은 전적으로 util.HttpUtil이 수행. (명명 휴리스틱으로는 잡히지 않을 사실)
항목 · 값
C2 Base · `[비공개]
해석 IP · **[비공개]**
프레임워크 · RuoYi (Spring Boot, `/prod-api` 게이트웨이 prefix, `{code,msg,data}` 응답)
상태 · **LIVE** (2026-06-14 검증, HTTP 200, 초대코드 검증 작동)
URL 저장 위치 · `util.ContainValue.Api` (평문 상수)
응답 언어 · 한국어 → 한국 [피해자 정보 비공개]
C2 base URL이 난수 도메인 + .rest TLD인 점은 wavegrid 패밀리의 도메인 회전(rotation) 전술과 일치. 기존 등록 변종 [비공개]과 동일 엔드포인트 구조([비공개], /saveAddressBook`).
Method · Endpoint · 목적 · 파라미터
POST · `[비공개] · 초대코드 인증 · `name`(초대코드), `cId`(UUID)
POST · `[비공개] · **연락처/번호/통신사 탈취** · `userName`(초대코드), `model`, `bjPhone`(피해자번호), `operatorName`, `phoneContent`(연락처 JSON)
POST(multipart) · `[비공개] · **갤러리 사진 업로드** · `file`(JPEG), `other_field=yuvaluejing`
상세 페이로드 구조는 Tunf_data_transmission_report.md 참조.
```
LoginActivity
└ 초대코드 입력 → POST /webapp/login {name, cId=UUID}
└ code==200 → INVITE_CODE/UUID 저장 → HomeActivity
HomeActivity (btn_submit 클릭)
└ getPerInfo(): PermissionX로 연락처+미디어+전화번호 권한 요청
├ 전체 허용 → shareCOntain()
│ ├ getLine1Number() → [피해자 정보 비공개] 번호(codeValue)
│ ├ startNextInfo() → POST /webapp/saveAddressBook (연락처 전량)
│ └ startImgShowInfo()→ 갤러리 전체 → Luban 압축 → /webapp/image/{code} 반복 업로드
└ 부분/거부 → showActiveDialog(): APPLICATION_DETAILS_SETTINGS로 유도 후 재시도
└ 성공 시 IS_UPLOAD=true 저장 → "동기화 성공" 다이얼로그 → 버튼 비활성
```
stamswj()는 빈 본문의 디코이 메서드.
취약점 · 내용 · 영향
SSL 검증 무력화 · 모든 인증서 신뢰 + 호스트명 검증 무시 · 제3자 MITM 가능 / 분석가 트래픽 가로채기
평문 페이로드 · 연락처·번호가 암호화 없이 JSON 전송 · 네트워크 캡처만으로 피해 데이터 전량 노출
인증 부재 · C2 게이트가 초대코드 단일 의존, 토큰/서명 없음 · 초대코드 확보 시 임의 데이터 주입/조회 가능성
도메인 평문 상수 · C2가 단일 상수에 하드코딩 · 차단·싱크홀링 용이
```
package com.pdutcbi.bctdimp
label Tunf
versionName 3.0.29 (3029)
apk_sha256 4a636e12f6e195534affe8a021224e575e60c88270a02f4811fed4cd39db6646
apk_md5 048188123da7d78ee71fa9d46a0d21f8
cert_sha256 63e12b8b782afa2df4f6f624cd185534a40853cdf27f239edea1383fc4bf10c5
cert_sha1 77e9638fb7d4d015582b1d0972528c883d303f90
domain [비공개]
ip [비공개]
endpoints [비공개] upload_marker other_field=yuvaluejing
INVITECODE / UUIDVALUE / ISUPLOAD / IFFIRST
```
라이브러리 · 용도
`com.blankj:utilcode` (AndroidUtilCode) · SPUtils 등 (중국계 유틸)
`com.permissionx.guolindev:PermissionX` · 런타임 권한 요청 UX
`top.zibin.luban:Luban` · 업로드 전 이미지 압축
`okhttp3` + `gson` · 네트워크/직렬화
```
🔬 기법 점검:
· 시도한 기법:
· STR-001 (문자열/상수 C2 추출)
· SA-253 OBF-REACHABILITY (참조 도달성 BFS로 디코이 클래스 분리) ← 자동화 스크립트
· NET-PROBE (C2 라이브 검증, OPSEC-safe 더미 페이로드)
· SIG-FINGERPRINT (서명 DN/해시로 빌더 귀속)
· 확장된 기법:
· NET-PROBE — HTTP status와 application code(RuoYi {code})를 분리 보고하여
"서버 가동"과 "데이터 수신 성공"의 혼동 차단(code-review 반영)
· 신규 기법:
· SA-253 OBF-REACHABILITY — 런처 액티비티 패키지를 시드로 한 transitive 참조 BFS로
Manifest 등록 but unreachable한 디코이 패키지를 명명 무관하게 정확 분리.
(초기 모음비 휴리스틱은 fragile하여 reachability로 근본 재설계 — false positive 0)
· 한계 발견:
· 동적 트래픽(실기기 saveAddressBook 평문 캡처)은 미수행 — 정적+C2프로브로 흐름 확정.
추가 확증이 필요하면 에뮬레이터 + MITM 프록시로 평문 바디 1회 캡처 권장.
· saveAddressBook가 login 없이도 초대코드만으로 호출 가능한지(차등 인증)는 동적 확인 필요.
```
```
· 새 아이디어/시도: 패키지 명명 통계 → (code-review 후) 참조 도달성 BFS로 근본 재설계
· 결과: 성공. reachability가 명명 휴리스틱이 못 잡는 사실까지 포착
(api/HttpsUtils가 선언만 되고 미사용 = unreachable 임을 자동 발견).
26 더미 패키지 / 1,251 클래스 격리, 코어 4패키지, false positive 0.
· 기법 카탈로그 반영: SA-253 OBF-REACHABILITY 신규 등재
· 다음 앱에서 시도할 아이디어: reachability를 smali 메서드 호출 그래프로 확장해
"등록 but 미도달(dead) 액티비티" 비율을 패밀리별 난독화 지문으로 정량화
```
본 보고서는 주식회사 아크링크 Deep-Coding 보안연구소가 피싱·몸캠피싱 피해자 구제를 목적으로 작성했습니다. 전체 열람·피해 상담: arklink.co.kr