꿈을꾸는 파랑새

오늘은 파일 복구 앱을 위장하면서 개인정보 전송하는 악성코드인 File Recovery and Data Recovery(2023.07.08) 에 대해 글을 적어 보겠습니다. 해당 악성코드는 많은 과도한 사용자 데이터를 수집하고 있으며 사용자의 상호 작용 없이 시작하여 민감한 데이터를 훔쳐 중국의 서버 보낼 수가 있으며 해당 악성코드는 스마트폰에서 파일 복구 및 데이터 복구라는 이름으로 악성코드가 유포하고 있습니다.
com.spot.music.filedate 로 식별되는 파일 복구 및 데이터 복구는 최소 100만 회 설치가 되었으며 보안 솔루션 회사인 Pradeo의 행동 분석 엔진에 의해 발견되었으며 구글 플레이 스토어 항목의 데이터 보안 섹션에서 장치로부터 사용자 데이터를 수집하지 않는다고 했지만 민감한 데이터를 수집을 하는 악성코드입니다.
일단 유포 주소는 다음과 같습니다.

https://play.google(.)com/store/apps/details?id=com.spot.music.filedate&hl=en_US

File Recovery & Data Recovery 구글 플레이 스토어File Recovery & Data Recovery 데이터 안전도
File Recovery & Data Recovery 구글 플레이 스토어

먼저 해당 악성코드 권한은 다음과 같습니다.

File Recovery and Data Recovery 악성코드 권한
File Recovery and Data Recovery 악성코드 권한

다음은 주어진 코드 스니펫에서 사용된 Android 권한의 요약 및 설명입니다.:
android.permission.READ_BASIC_PHONE_STATE: 기본 전화 상태 읽기
사용자의 기본 전화 상태에 대한 읽기 권한을 제공
android.permission.READ_MEDIA_IMAGES:미디어 이미지 읽기
사용자의 디바이스 에서 이미지 미디어 파일을 읽을 수 있는 권한을 제공
android.permission.READ_MEDIA_VIDEO: 미디어 비디오 읽기
사용자의 디바이스 에서 비디오 미디어 파일을 읽을 수 있는 권한을 제공
android.permission.READ_MEDIA_AUDIO: 미디어 오디오 읽기
사용자의 디바이스 에서 오디오 미디어 파일을 읽을 수 있는 권한을 제공
android.permission.READ_EXTERNAL_STORAGE: 외부 저장소 읽기
사용자의 외부 저장소에서 파일을 읽을 수 있는 권한을 제공
android:maxSdkVersion="32":속성이 추가되어 SDK 버전이 32 이하인 경우에만 유효
android.permission.WRITE_EXTERNAL_STORAGE: 외부 저장소 쓰기
사용자의 외부 저장소에 파일을 쓸 수 있는 권한을 제공
android:maxSdkVersion="32" 속성이 추가되어 SDK 버전이 32 이하인 경우에만 유효
android.permission.INTERNET: 인터넷 액세스
앱이 인터넷에 연결되어 리소스를 내려받거나 네트워크 작업을 수행할 수 있는 권한을 제공
android.permission.ACCESS_NETWORK_STATE: 네트워크 상태 액세스
앱이 현재 네트워크 연결 상태를 확인할 수 있는 권한을 제공
android.permission.BLUETOOTH: 블루투스 액세스
앱이 블루투스에 액세스하고 블루투스 기기와 상호 작용할 수 있는 권한을 제공
android.permission.BLUETOOTH_ADMIN: 블루투스 관리
앱이 블루투스 관리 작업을 수행할 수 있는 권한을 제공
com.android.alarm.permission.SET_ALARM:알람 설정
앱이 알람을 설정할 수 있는 권한을 제공
com.google.android.gms.permission.AD_ID: 광고 ID 액세스
앱이 Google 광고 ID에 액세스할 수 있는 권한을 제공
android.permission.ACCESS_WIFI_STATE: Wi-Fi 상태 액세스
앱이 현재 Wi-Fi(와이 파이) 연결 상태를 확인할 수 있는 권한을 제공
android.permission.AUTHENTICATE_ACCOUNTS: 계정 인증
앱이 사용자의 계정을 인증하고 관리할 수 있는 권한을 제공
android.permission.GET_ACCOUNTS: 계정 가져오기
앱이 기기에 저장된 계정 목록에 액세스할 수 있는 권한을 제공
android:maxSdkVersion="22" 속성이 추가되어 SDK 버전이 22 이하인 경우에만 유효
android.permission.MANAGE_ACCOUNTS: 계정 관리
앱이 사용자 계정을 관리할 수 있는 권한을 제공
android.permission.READ_SYNC_SETTINGS: 동기화 설정 읽기
앱이 동기화 설정을 읽을 수 있는 권한을 제공
android.permission.WRITE_SYNC_SETTINGS: 동기화 설정 쓰기
앱이 동기화 설정을 변경할 수 있는 권한을 제공
android.permission.READ_SYNC_STATS:동기화 통계 읽기
앱이 동기화 통계 정보를 읽을 수 있는 권한을 제공
android.permission.RECEIVE_BOOT_COMPLETED: 부팅 완료 시 수신
앱이 디바이스 부팅이 완료되고 시스템으로부터 알림을 수신할 수 있는 권한을 제공
android.permission.WAKE_LOCK: 화면 깨우기
앱이 잠금 화면이나 화면 꺼진 상태에서도 동작하도록 화면을 켜고 유지할 수 있는 권한을 제공
android.permission.FOREGROUND_SERVICE:포그라운드 서비스
앱이 포그라운드에서 실행되는 서비스를 제공할 수 있는 권한을 제공

해쉬값은 다음과 같습니다.
파일명:File Recovery and Data Recovery.apk
사이즈:15.9 MB
CRC32:a93011cf
MD5:b4f0bd7ee1beb3745daf9b03d679284b
SHA-1:d936878b59f20ce69425954a3408368f1d6f251d
SHA-256:90418d717c53f85561d0d6f3c0d7f4526b1ab8cc841544b7650399da1642b265
구글 플레이 스토어에서 위에서 언급한 애플리케이션의 프로필은 사용자 기기에서 데이터를 수집하지 않는다고 발표 이는 잘못된 정보로 확인 또한 데이터가 수집되면 사용자는 삭제를 요청할 수 없으며 이는 GDPR과 같은 대부분의 데이터 보호법에 위배
일단 먼저 문자 보내기 관련 코드입니다. 

문자 보내기 위한 코드
문자 보내기 위한 코드

해당 코드는 com.blankj.utilcode.util.IntentUtils 부분에 있습니다.

public static Intent getSendSmsIntent(@NonNull String str, String str2) {
        Intent intent = new Intent("android.intent.action.SENDTO", 
        Uri.parse("smsto:" + Uri.encode(str)));
        intent.putExtra("sms_body", str2);
        return getIntent(intent, true);
    }

해당 메서드는 안드로이드 앱에서 SMS(문자) 메시지를 보내려고 사용할 수 있는 Intent 객체를 반환하는 정적(static) 메서드 해당 메서드는 두 개의 매개변수를 사용합니다. 수신자의 전화번호와 메시지 본문
해당 메서드는 다음과 같은 순서로 동작합니다.:
1.android.intent.action.SENDTO  액션과 smsto: + Uri.encode(str) 데이터 Uri를 사용하여 Intent 객체를 생성 이를 통해 SMS 메시지를(문자 메세지) 보내기 위한 Intent를 생성
android.intent.action.SENDTO: SMS 메시지를 보내기 위한 액션입
smsto:+ Uri.encode(str):문자 메시지를 받을 전화번호를 smsto:스키마를 사용하여 Uri로 변환
전화번호는 Uri.encode(str)를 통해 인코딩되어 URI에 포함
sms_body 라는 엑스트라에 메시지 본문을 설정
sms_body 는 문자 메시지의 본문을 나타내는 키
메시지 본문은 매개변수로 전달된 str2 변수의 값으로 설정
Intent 객체를 반환
해당 메서드는 안드로이드 앱에서 SMS 메시지(문자 메세지)를 보내려고 유용하게 사용될 수 있는 유틸리티 메서드 해당 Intent를 실행하면 SMS 메시지 앱으로 이동하고 수신자와 메시지 본문이 미리 채워진 상태로 메시지 작성 화면이 표시 악용을 했을 때 스팸, 개인정보 유출, 부적절한 메시지 전송(예를 들어 성적 수치침을 나타내는 문자)

com.apm.insight.entity.C3874a 에서는 다음과 같은 코드 들이 있습니다.

악성코드 크래시 레포트 저장 코드
악성코드 크래시 레포트 저장 코드

public static C3874a m25488a(long j, Context context, String str) {
        C3874a c3874a = new C3874a();
        c3874a.m25483a("is_dart", (Object) 1);
        c3874a.m25483a("crash_time", Long.valueOf(j));
        c3874a.m25483a("process_name", (Object) C3943a.m25181c(context));
        c3874a.m25483a("data", (Object) str);
        C3943a.m25187a(context, c3874a.m25457h());
        return c3874a;
    }

해당 코드 해석은 다음과 같습니다.
주어진 코드 스니펫은 크래시 레포트를 생성하는 데 사용되는 메서드입니다. 각각의 동작은 다음과 같습니다:
C3874a 객체를 생성하여 c3874a 변수에 할당
c3874a.m25483a("is_dart", (Object) 1)을 호출하여 is_dart 라는 속성을 1 로 설정 해당 속성은 Dart 언어로 작성된 앱에서 발생한 크래시인지 여부를 나타냄
c3874a.m25483a("crash_time", Long.valueOf(j)) 을 호출하여 crash_time 이라는 속성을 j 변수의 값으로 설정 해당 속성은 크래시가 발생한 시간을 나타냄
c3874a.m25483a("process_name", (Object) C3943a.m25181c(context)) 을 호출하여 process_name 이라는 속성을 C3943a.m25181c(context) 의 반환값으로 설정
C3943a.m25181c(context) 는 현재 실행 중인 프로세스의 이름을 가져오는 메서드
c3874a.m25483a("data", (Object) str) 을 호출하여 data 라는 속성을 str 변수의 값으로 설정
해당 속성은 크래시와 관련된 데이터를 저장
C3943a.m25187a(context, c3874a.m25457h()) 를 호출하여 context 와 c3874a.m25457h() 를 인자로 전달하면 해당 부분은 크래시 레포트를 저장하거나 전송하는 메서드를 호출하는 것으로 추측할 수 있음
c3874a 객체를 반환
주어진 코드는 앱에서 발생한 크래시 정보를 수집하고 이를 크래시 레포트로 구성하는 역할을 수행합
해당 크래시 레포트는 앱의 상태와 실행 중인 프로세스, 크래시 시간 등의 정보를 포함할 수 있으며 이렇게 생성된 크래시 레포트는 이후에 저장되거나 전송되어 디버깅 및 문제 해결에 사용될 수 있음

악성코드 getDeviceId 코드 부분
악성코드 getDeviceId 코드 부분

androidx.core.telephony.TelephonyManagerCompat 부분에서는 getDeviceId 관련 코드들이 있는 것을 확인할 수가 있습니다.

public static String getImei(@NonNull TelephonyManager telephonyManager) {
        if (Build.VERSION.SDK_INT >= 26) {
            return Api26Impl.getImei(telephonyManager);
        }
        int subscriptionId = getSubscriptionId(telephonyManager);
        if (subscriptionId != Integer.MAX_VALUE && subscriptionId != -1) {
            return Api23Impl.getDeviceId(telephonyManager, SubscriptionManagerCompat.
            getSlotIndex(subscriptionId));
        }
        return telephonyManager.getDeviceId();
    }

해당 코드 설명은 다음과 같습니다.
주어진 코드는 IMEI(국제 모바일 장치 식별자)를 가져오기 위한 정적(static) 메서드
getImei 메서드는 TelephonyManager객체를 매개변수로 받음
현재 안드로이드 SDK 버전이 26(Android 8.0) 이상이면 Api26Impl.getImei(telephonyManager)을 호출하여 IMEI 값을 가져오고 Api26Impl 은 안드로이드 8.0 이상 버전에서 사용되는 IMEI 관련 구현
현재 안드로이드 SDK 버전이 26(안드로이드 8.0) 미만이면 getSubscriptionId(telephonyManager)를 호출하여 SIM 카드의 구독 ID를 가져오고 만약 subscriptionId 값이 Integer.MAX_VALUE 이거나 -1 이 아니라면 Api23Impl.getDeviceId(telephonyManager, SubscriptionManagerCompat.getSlotIndex(subscriptionId)) 을 호출하여 해당 SIM 카드(유심)의 장치 ID를 가져옴
SubscriptionManagerCompat.getSlotIndex(subscriptionId) 는 구독 ID를 기반으로 SIM 카드(유심)의 슬롯 인덱스를 가져옴
위의 조건에 해당하지 않는 경우 telephonyManager.getDeviceId() 를 호출하여 기기의 장치 ID를 가져온 이전에 사용되던 방식으로서 SDK 버전이 낮은 경우에 사용될 수 있음
가져온 안드로이드 스마트폰 IMEI 값을 반환을 진행합니다.
위의 코드는 안드로이드 기기의 IMEI 값을 가져오는 유틸리티 메서드로 사용될 수 있으며 안드로이드 SDK 버전에 따라 적절한 방법을 사용하여 IMEI 값을 가져옴
해당 코드를 악용하면 다음과 같은 문제가 발생합니다.
개인 정보 유출: IMEI는 기기의 고유한 식별자이기 때문에 IMEI를 획득하면 기기의 소유자를 추적하거나 기기를 도용할 수 있음
악성코드가 이 코드를 악용하여 기기의 IMEI 값을 획득하면 악성 활동을 수행하는 데 사용될 수 있으며 해당 악성코드는 IMEI 값을 사용하여 기기 식별, 인증 우회, 권한 요구 등의 악성 행위를 수행할 수가 있습니다.
사용자의 동의 없는 데이터를 수집을 할 수가 있으며 사용자의 위치, 통화 기록, 메시지 내용 등에 접근하여 개인정보 침해를 당할 수가 있습니다.

악성코드 IMEI 관련코드
악성코드 IMEI 관련코드

androidx.core.telephony.TelephonyManagerCompat 에서는 IMEI 관련 코드가 있습니다.

/* loaded from: classes.dex */
    public static class Api26Impl {
        private Api26Impl() {
        }

        @SuppressLint({"MissingPermission"})
        @Nullable
        @RequiresPermission(Permission.READ_PHONE_STATE)
        @DoNotInline
        public static String getImei(TelephonyManager telephonyManager) {
            String imei;
            imei = telephonyManager.getImei();
            return imei;
        }
    }

    @RequiresApi(23)
    /* loaded from: classes.dex */
    public static class Api23Impl {
        private Api23Impl() {
        }

        @SuppressLint({"MissingPermission"})
        @Nullable
        @RequiresPermission(Permission.READ_PHONE_STATE)
        @DoNotInline
        public static String getDeviceId(TelephonyManager telephonyManager, int i) {
            return telephonyManager.getDeviceId(i);
        }
    }
}

Api26Impl 클래스:
Android API 버전이 26 이상(안드로이드 8.0 오레어)인 경우 사용
getImei 메서드는 TelephonyManager 객체를 매개변수로 받음
telephonyManager.getImei()를 호출하여 IMEI 값을 가져오고 IMEI 값을 반환
Api23Impl 클래스:
@RequiresApi(23) 어노테이션으로 주석 처리되어 있으며 Android API 버전이 23 이상이면 사용
getDeviceId 메서드는 TelephonyManager 객체와 슬롯 인덱스를 매개변수로 받음
telephonyManager.getDeviceId(i)를 호출하여 해당 슬롯 인덱스의 장치 ID 값을 가져오고 나서 장치 ID 값을 반환
IMEI 값은 기기를 고유하게 식별하는 데 사용되는 정보이고 IMEI 값을 악용하여 사용자의 개인정보를 수집하거나 추적할 수 있으며 위치, 통신 기록 등을 추적하거나 개인정보를 유출할 수 있으며 IMEI 값을 이용하여 앱 권한을 우회하거나

기기 식별을 위조할 수 있어 이를 통해서 보안 취약점을 악용하거나 앱의 기능을 부정하게 사용할 수 있게 되며 IMEI 값을 악용하여 악성 행위를 수행할 수 있습니다. 예를 들어 IMEI 값을 이용하여 부정한 활동, 스팸 메시지 전송, 사기 행위 등을 수행할 수 있음

PhoneUtils getIMSI 코드
PhoneUtils getIMSI 코드

com.blankj.utilcode.util.PhoneUtils 에서는 getIMSI 메서드 관련 코드들이 있습니다.

@RequiresPermission(Permission.READ_PHONE_STATE)
    @SuppressLint({"HardwareIds"})
    public static String getIMSI() {
        if (Build.VERSION.SDK_INT >= 29) {
            try {
                getTelephonyManager().getSubscriberId();
            } catch (SecurityException e) {
                e.printStackTrace();
                return "";
            }
        }
        return getTelephonyManager().getSubscriberId();
    }

    public static int getPhoneType() {
        return getTelephonyManager().getPhoneType();
    }

    public static boolean isSimCardReady() {
        return getTelephonyManager().getSimState() == 5;
    }

    public static String getSimOperatorName() {
        return getTelephonyManager().getSimOperatorName();
    }

코드 설명은 다음과 같습니다.
getIMSI 메서드: IMSI(국제 모바일 사용자 식별자) 값을 가져오는 메서드
@RequiresPermission(Permission.READ_PHONE_STATE) 어노테이션으로 주석 처리되어 있으므로, 해당 권한이 필요
안드로이드 SDK 버전이 29(Android 10) 이상이면 getSubscriberId()를 호출하여 IMSI 값을 가져옴 그러나 앱에 READ_PHONE_STATE 권한이 없는 경우 SecurityException이 발생하고 빈 문자열("")을 반환
안드로이드 SDK 버전이 29 미만이면 getSubscriberId()를 호출하여 IMSI 값을 가져 오고 IMSI 값을 반환
getPhoneType 메서드:기기의 전화 유형을 가져오는 메서드이며 getTelephonyManager().getPhoneType()을 호출하여 전화 유형을 가져옴 그리고 전화 유형에 해당하는 정수 값을 반환
isSimCardReady 메서드: SIM 카드의 준비 상태를 확인하는 메서드이며 getTelephonyManager().getSimState()를 호출하여 SIM 카드 상태를 가져옴
SIM 카드 상태가 5(READY)인 경우 true를 반환 및 그 외의 경우에는 false를 반환
getSimOperatorName 메서드:
SIM 카드(유심)의 운영자 이름을 가져오는 메서드
getTelephonyManager().getSimOperatorName()을 호출하여 SIM 카드의 운영자 이름을 가져온 SIM 카드 운영자 이름을 반환합니다.
IMSI 값은 전화 통신사와 연관되며, 위치 추적 등의 우려가 있음
악용자가 특정 권한 없이 getIMSI 메서드를 호출하는 경우 SecurityException이 발생하고 빈 문자열("")을 반환 이를 우회하여 권한 없이 IMSI 값을 가져오려고 할 수 있으며 이는 앱의 보안을 침해할 수 있음
악용자가 SIM 카드(유심) 상태와 운영자 이름을 악용하여 스팸 메시지 전송, 부정한 컨텐츠 전송 등의 활동을 수행할 수 있습니다.
해당 악성코드의 악성코드 인증서 정보는 다음과 같습니다.

악성코드 안드로이드 인증서
악성코드 안드로이드 인증서

서명자 1
유형: X.509
버전: 3
시리얼 번호: 0xc82552e43e524f6444c26d2c1ee4a2311646d4e1
소유자: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
유효 시작 시각: Sat May 06 20:38:43 GMT+09:00 2023
유효 종료 시각: Tue May 06 20:38:43 GMT+09:00 2053
공개키 타입: RSA
지수: 65537
모듈러스 크기 (비트): 4096
서명 유형: SHA256withRSA
서명 OID: 1.2.840.113549.1.1.11
MD5 지문: 38 E9 B2 99 C2 2B 1F 1B 2A ED D9 C2 F1 5A B9 06 
SHA-1 지문: 93 70 13 44 1F 65 BD C1 FD C4 E4 06 66 62 46 B8 A3 5C 92 EA 
SHA-256 지문: 72 1D 4E 09 8E FB F1 97 FC A5 03 8B 0D C2 6C 53 1B 04 47 2E A6 6B 07
98 88 F1 1C 7F 45 61 6B 52

 

결론:해당 악성코드가 수집하고 악용하는 것은 다음과 같습니다.
장치 메모리, 연결된 이메일 계정 및 소셜 네트워크의 사용자 연락처 목록
애플리케이션 내에서 관리 또는 복구되는 사진, 오디오 및 비디오
실시간 사용자 위치
모바일 국가 코드
네트워크 공급자 이름
SIM 공급자의 네트워크 코드
운영 체제 버전 번호
장치 브랜드 및 모델

ESET Mobile Security 탐지
ESET Mobile Security 탐지

해당 악성코드 특징은 다운로드 수는 많았고 리뷰는 거의 없음 홈 화면 아이콘을 숨겨서 찾아서 제거하기 어렵게 만들었음

2023-07-08 10:49:35 UTC 기준 바이러스토탈에서 탐지하는 보안 업체는 다음과 같습니다.
Antiy-AVL:Trojan/Generic.ASMalwAD.39
DrWeb:Android.HiddenAds.3706
ESET-NOD32:Android/Hiddad.BBA
Fortinet:Android/Hiddad.BBA!tr
Google:Detected
Ikarus:AdWare.AndroidOS.Hiddad
K7GW:Trojan ( 005a83571 )
Kaspersky:Not-a-virus:HEUR:AdWare.AndroidOS.HiddenAd.aan
McAfee:Artemis!B4F0BD7EE1BE
McAfee-GW-Edition:Artemis!PUP
Sophos:Andr/HiddAd-AR
Symantec:PUA.Gen.2
Symantec Mobile Insight:AppRisk:Generisk
Trustlook:Android.PUA.General
ZoneAlarm by Check Point:Not-a-virus:HEUR:AdWare.AndroidOS.Hidden
언제나 이야기하듯이 구글 플레이 스토어 에서도 악성코든 존재하니 AV-TEST 통과한 백신 앱을 사용을 하는 것이 안전하게 안드로이드 스마트폰을 사용하는 데 도움이 될 것입니다.

공유하기

facebook twitter kakaoTalk kakaostory naver band