꿈을꾸는 파랑새

오늘은 스마트폰 최적화 앱을 위장하는 악성코드인 EasyCleaner 에 대해 글을 적어보겠습니다. 일단 기본적으로 삼성 스마트폰 같은 것은 경우에는 디바이스 케어 라는 기능이 있어서 쉽게 사용을 할 수가 있습니다. 그런데 여기서 조금 더 기능이 많은 스마트폰 최적화 앱을 원하시는 분들은 별도로 해당 앱을 구글 플레이 스토어 에서 설치해서 사용하고 있습니다. 그런데 문제는 일부 앱 들은 악성코드를 포함하고 있습니다. 오늘은 그중에 하나인 EasyCleaner 에 대해 글을 적어 보겠습니다. 일단 구글 플레이 스토어 에서 유포된 주소는 다음과 같습니다.

https://play.google(.)com/store/apps/details?id=com.easy.clean.ipz&ref=apkcombo.com

악성코드 EasyCleaner 안드로이드 권한
악성코드 EasyCleaner 안드로이드 권한

물론 현재는 삭제 처리되었지만 일단 100K+ 다운로드 정도 다운로드가 되었으며 정크 파일을 삭제하거나 기기 관리를 위해 배터리를 최적화하는 데 도움이 되는 클리너 앱으로 위장하는 것이 특징이며 특징이라고 하면 악성코드는 피해자에게 광고를 숨기고 지속적으로 표시하며 또한 앱을 실행하지 않고 설치 시 악성 서비스를 자동으로 실행하는 것이 특징입니다.

즉 보통의 악성코드는 일단 설치하는 것은 악성코드가 작동하지 않지만, 해당 악성코드 제작자는 생각을 조금 바꾸어서 설치하고 나서 악성코드를 실행하기 위해서 만들어졌습니다. 사용자가 앱을 알아채거나 삭제하지 못하도록 은폐를 시도하면 대부분은 구글 플레이 스토어 또는 설정 아이콘으로 변경해서 사용자가 이런 악성코드를 임의적으로 삭제를 못 하게 하는 전술을 사용하고 있습니다.

그리고 사용자에게 광고를 갑작스럽게 표시하게 하면서 사용자가 기기에 앱을 설치, 제거 또는 업데이트할 때 앱을 실행하도록 유도를 하는 것도 특징입니다. 악성코드를 유포하기 위해서 의심을 피하고자 페이스북을 활용합니다.

연락처 제공자이라는 사용을 하며 응용 프로그램에서 해당 데이터에 접근하고 장치와 온라인 서비스 간에 데이터를 전송할 수도 있도록 이를 위해 Google은 ContactContract 클래스를 제공하는데 이것을 악용하는 것이 특징입니다.
구글에서 제공하는 안드로이드 개발자용에 있는 내용을 보면 다음과 같이 정리합니다.

EasyCleaner ContactsContract Directory
EasyCleaner ContactsContract Directory

ContactsContract.Contacts 테이블
행은 원시 연락처 행의 집계에 기초하여 각기 다른 사람을 나타냄
ContactsContract.RawContacts 테이블
사용자 계정과 유형을 기준으로 한 사람에 대한 데이터 요약이 들어 있는 행
ContactsContract.Data 테이블
이메일 주소나 전화번호와 같은 원시 연락처의 세부정보가 들어 있는 행
ContactsContract에는 Directory라는 클래스가 있으며 고유한 권한을 가진 콘텐츠 제공자로 구현 가능하면 개발자는 사용자 지정 디렉터리를 구현하려는 경우 사용할 수 있습니다. 연락처 제공자는 매니페스트 파일의 특수 메타데이터를 확인하여 앱이 사용자 지정 디렉터리를 사용하고 있음을 확인할 수가 있습니다.

일단 해당 악성코드 해쉬값은 다음과 같습니다.

파일명:EasyCleaner_2.1.apk
사이즈:14.1 MB
CRC32:92498909
MD5:4c445cc5185cb8e15153804c24a0e63a
SHA-1:1314091d507a00d91dcce7fefe1b7ac8c9de89ea
SHA-256:64d8bd033b4fc7e4f7fd747b2e35bce83527aa5d6396aab49c37f1ac238af4bd
이며 DEX 파일 정보는 다음과 같습니다.
Dex File Name:classes.dex
File Size:9051036 bytes
MD5:78d4e0f8ed638c06beb34401f7b0fd39
Class Size:8528
Method Size:65456
String Size:61002
Dex File Name:classes2.dex
File Size:9261716 bytes
MD5:dbfc7c2137302072885b1ff9f7598197
Class Size:9503
Method Size:65404
String Size:59261
Dex File Name:classes3.dex
File Size:3001832 bytes
MD5:13732add2a948391a29c4aa1abaa1fb2
Class Size:2447
Method Size:21313
String Size:18457
그리고 해당 악성코드 EasyCleaner의 악성코드는 다음과 같습니다.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

입니다. 일단 보면 기본적으로 외장 디스크 즉 마이크로 SD카드 읽고 쓰기, 인터넷 연결,액세스 네트워크 상태 그리고 와이파이 상태 확인, 스마트폰 번호, 기기 고유 id 등 단말기 정보 가져오기, 스마트폰 기기 켜진 상태 유지 등을 확인할 수가 있습니다.
<meta-data android:name="android.content.ContactDirectory" android:value="true"/>
연락처 제공자가 새로 설치되거나 교체된 패키지를 자동으로 검색하면 그래서 특수 메타데이터가 포함된 패키지를 설치하면 항상 연락처 제공자가 자동으로 호출하는 것이 특징입니다.
com.n.p.h.y.CGCoreService 에서는 악성코드의 첫 번째 활동은 광고를 표시하기 위한 영구적인 악성 서비스를 생성하는 것이 목적으로 관련 코드는 다음과 같습니다.

Override // android.os.Handler.Callback
    public boolean handleMessage(Message message) {
        if (message.what == 1) {
            g.a(a() + " handleMessage stopPlay");
            h();
        }
        if (message.what == 2) {
            g.a(a() + " handleMessage startPlay");
            g();
        }
        return true;
    }

    public static void a(Context context, String str) {
        b(context, new Intent(context, CGCoreService.class));
        b(context, new Intent(context, CGCoreService2.class));
    }

    public static void a(Context context) {
        a(context, new Intent(context, CGCoreService.class));
        a(context, new Intent(context, CGCoreService2.class));
    }

<activity-alias> 태그를 사용하여 아이콘과 이름을 변경 및 은폐를 시도합니다. 관련 코드는 다음과 같습니다.

악성코드 아이콘 변경 및 은폐
악성코드 아이콘 변경 및 은폐

<activity-alias android:label="@string/kl_google" android:icon="@drawable/kl_gl_pl_ic" android:name="com.n.p.h.y.ui.SplashActivity3" android:enabled="false" android:excludeFromRecents="true"

해당 악성코드를 압축을 풀어 보면 EasyCleaner_2.1\res\drawable-xxhdpi-v4 부분에 kl_gl_pl_ic.png 을 사용을 하는 것을 확인할 수가 있습니다.

악성코드가 사용을 하는 구글 플레이 스토어 아이콘
악성코드가 사용을 하는 구글 플레이 스토어 아이콘

그리고 악성코드에 포함된 주소들은 다음과 같습니다.

http://cpi.functionads(.)com/index.jsp
http://hw.log.functionads(.)com:8100/api/
http://hw.sdk.functionads(.)com
http://hw.sdk.functionads(.)com:8100/api/
http://market.android(.)com/
http://schemas.android(.)com/apk/res/android
https(:)//%s
https://api16-access-sg.pangle(.)io/api/ad/union/sdk/get_ads/?aid=1371&device_platform=android&version_code=4250
https://app.adjust(.)com
https://app.adjust.net(.)in
https://app.adjust(.)world
https://app.eu.adjust(.)com
https://app.tr.adjust(.)com
https://app.us.adjust(.)com
https://da.chartboost(.)com
https://gdpr.adjust(.)com
https://gdpr.adjust.net(.)in
https://gdpr.adjust(.)world
https://gdpr.eu.adjust(.)com
https://gdpr.tr.adjust(.)com
https://gdpr.us.adjust(.)com
https://lf-hs-sg.ibytedtos(.)com/obj/union-platform-i18n/union_platform_gdpr_607_en.html
https://live.chartboost(.)com
https://log-mva.isnssdk(.)com/service/2/app_log/
https://log.sgsnssdk(.)com/service/2/app_log/
https://p0.ipstatp(.)com/origin/ad-site-i18n-sg/202011255d0d219920adb0fd474eac28
https://pagead2.googlesyndication(.)com/pagead/gen_204?id=gmob-apps
https://pangle-global(.)io/
https://play.google(.)com/store/apps/details?id=
https://sf-tb-sg.ibytedtos(.)com/obj/ad-pattern-sg/renderer/package_sg.json
https://sf16-muse-va.ibytedtos(.)com/obj/ad-pattern-va/renderer/package_va.json
https://ssp-events.chartboost(.)com/track/sdk
https://subscription.adjust(.)com
https://subscription.adjust.net(.)in
https://subscription.adjust(.)world
https://subscription.eu.adjust(.)com
https://subscription.tr.adjust(.)com
https://subscription.us.adjust(.)com
https://www.baidu(.)com/
https://www.example(.)com
https://www.googleapis(.)com/auth/appstate
https://www.googleapis(.)com/auth/datastoremobile
https://www.googleapis(.)com/auth/drive
https://www.googleapis(.)com/auth/drive.appdata
https://www.googleapis(.)com/auth/drive.apps
https://www.googleapis(.)com/auth/drive.file
https://www.googleapis(.)com/auth/games
https://www.googleapis(.)com/auth/games.firstparty
https://www.googleapis(.)com/auth/games_lite
https://www.googleapis(.)com/auth/plus.login
https://www.googleapis(.)com/auth/plus.me

모바일 국가 코드 (Mobile Country Code)을 얻기 위한 코드는 com.adjust.sdk.Util 부분에 있으며 다음과 같습니다.

모바일 국가 코드 (Mobile Country Code) 관련 코드
모바일 국가 코드 (Mobile Country Code) 관련 코드

public static String getMcc(Context context) {
        try {
            String networkOperator = ((TelephonyManager) context.getSystemService("phone")).getNetworkOperator();
            if (TextUtils.isEmpty(networkOperator)) {
                AdjustFactory.getLogger().warn("Couldn't receive networkOperator string to read MCC", new Object[0]);
                return null;
            }
            return networkOperator.substring(0, 3);
        } catch (Exception unused) {
            AdjustFactory.getLogger().warn("Couldn't return mcc", new Object[0]);
            return null;
        }
    }

    public static String getMnc(Context context) {
        try {
            String networkOperator = ((TelephonyManager) context.getSystemService("phone")).getNetworkOperator();
            if (TextUtils.isEmpty(networkOperator)) {
                AdjustFactory.getLogger().warn("Couldn't receive networkOperator string to read MNC", new Object[0]);
                return null;
            }
            return networkOperator.substring(3);
        } catch (Exception unused) {
            AdjustFactory.getLogger().warn("Couldn't return mnc", new Object[0]);
            return null;
        }
    }

    public static int getNetworkType(Context context) {
        int networkType;
        try {
            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService("phone");
            if (Build.VERSION.SDK_INT >= 30) {
                networkType = telephonyManager.getDataNetworkType();
            } else {
                networkType = telephonyManager.getNetworkType();
            }
            return networkType;
        } catch (Exception e2) {
            getLogger().warn("Couldn't read network type (%s)", e2.getMessage());
            return -1;
        }

IMEI 관련 코드는 com.apm.insight.ICommonParams 에 있으며 다음과 같습니다.

IMEI 관련 코드
IMEI 관련 코드

package com.apm.insight;

import java.util.List;
import java.util.Map;

/* loaded from: classes.dex */
public interface ICommonParams {
    Map<String, Object> getCommonParams();

    String getDeviceId();

    List<String> getPatchInfo();

    Map<String, Integer> getPluginInfo();

    String getSessionId();

    long getUserId();
}

입니다.
암호화 관련 코드는 androidx.browser.trusted.PackageIdentityUtils 부문에 있습니다.

악성코드 광고 표시
악성코드 광고 표시

/* loaded from: classes.dex */
public class PackageIdentityUtils {
    public static final String TAG = "PackageIdentity";

    /* JADX INFO: Access modifiers changed from: package-private */
    @RequiresApi(28)
    /* loaded from: classes.dex */
    public static class Api28Implementation implements SignaturesCompat {
        @Override // androidx.browser.trusted.PackageIdentityUtils.SignaturesCompat
        @Nullable
        public List<byte[]> getFingerprintsForPackage(String str, PackageManager packageManager) throws PackageManager.NameNotFoundException {
            PackageInfo packageInfo = packageManager.getPackageInfo(str, 134217728);
            ArrayList arrayList = new ArrayList();
            SigningInfo signingInfo = packageInfo.signingInfo;
            if (signingInfo.hasMultipleSigners()) {
                for (Signature signature : signingInfo.getApkContentsSigners()) {
                    arrayList.add(PackageIdentityUtils.getCertificateSHA256Fingerprint(signature));
                }
            } else {
                arrayList.add(PackageIdentityUtils.getCertificateSHA256Fingerprint(signingInfo.getSigningCertificateHistory()[0]));
            }
            return arrayList;
        }

EasyCleaner 악성코드 인증서 정보는 다음과 같습니다.

EasyCleaner 악성코드 인증서 정보
EasyCleaner 악성코드 인증서 정보

서명 검증 성공
유효한 APK 서명 v1을(를) 찾았습니다.
서명자 BNDLTOOL.RSA (META-INF/BNDLTOOL.SF)
유형: X.509
버전: 3
시리얼 번호: 0xb3d411573acff791ff9f955ed7c83310bb19d8f
소유자: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
유효 시작 시각: Tue Mar 15 12:35:06 GMT+09:00 2022
유효 종료 시각: Fri Mar 15 12:35:06 GMT+09:00 2052
공개키 타입: RSA
지수: 65537
모듈러스 크기 (비트): 4096
모듈러스: 753681728316862977903877516397311124692425881104575753250989069944543816095112570321119390186989551862793699655488041363617884705127355993412845169501734456057832329420904810831080050889636367424525335752463892865014916738160663671448901685247808691250213296406936862324827550462436163148750709243552410002668813758902311045391884288080899927847831417928615301888996778913383754030046668362397470991883192734625595520739649894031835398339715662098755370862110798448878966000412388932599068568709699894031376212523622653419588614323968038163643896839202463753365226079781054135849165690099164771612401403383351846543461737785505791291959980354041930707750116818948979220167601780931223792064260991761390589815226061295467884216721708527032225671091714110003296177275544098800302825233483493938725065987865842308049273134986628013399667877697535249187833261374172017015036582733560394622448705455482526800718453864361874944082006903648887597618469854559408958464221166814354467101860753206173532194199244188044935161523442494365345628948818436547903556372642122169728718086120567157632056268570908722611233507044733090861108582151308438695827143132317981632641476103239311601264244542860508186152086684119570160519540759454421395825271
서명 유형: SHA256withRSA
서명 OID: 1.2.840.113549.1.1.11
MD5 지문: 40 C3 BA 17 BE 6E A8 41 7B F9 EB 3A 6E 95 02 76 
SHA-1 지문: 41 BE D4 1E 91 6F 6E C4 82 53 2F 64 C2 35 73 72 6A 5C 47 58 
SHA-256 지문: 47 06 6F 51 47 C5 2F 5E 00 7B B7 71 1B F4 C3 3D B0 A0 DE DA 21 77 84 27 F0 D2 30 24 90 BA 04 B7

2022-08-01 12:04:22 UTC 기준으로 VirusTotal(바이러스 토탈)에서 탐지하는 보안 업체들은 다음과 같습니다.
Avira (no cloud):ANDROID/Hiddad.srpim
BitDefenderFalx:Android.Riskware.HiddenAds.KY
Cynet:Malicious (score: 99)
DrWeb:Android.HiddenAds.3363
ESET-NOD32:A Variant Of Android/Hiddad.AWY
F-Secure:Malware.ANDROID/Hiddad.srpim
Fortinet:Android/Hiddad.AWY!tr
Ikarus:Trojan.AndroidOS.Hiddad
K7GW:Trojan (005953f81 )
Kaspersky:Not-a-virus:UDS:AdWare.AndroidOS.HiddenAd.wq
McAfee:Artemis!4C445CC5185C
McAfee-GW-Edition:Artemis!Trojan
Symantec:Trojan.Gen.MBT
Symantec Mobile Insight:AppRisk:Generisk
Trustlook:Android.PUA.General
ZoneAlarm by Check Point:Not-a-virus:UDS:AdWare.AndroidOS.HiddenAd.w
입니다. 뭐 예방 방법은 간단합니다. 기본적으로 신뢰할 수가 있는 보안 업체에서 제공하는 백신 앱을 사용을 하면 기본적으로 이런 최적화 앱 같은 경우에는 이름 있는 글로벌 기업들 제품을 사용하는 것을 추천합니다.
이상 해당 최적화 앱으로 위장을 해서 구글 플레이 스토어에서 악성코드를 유포했던 EasyCleaner(이지 클리너)라는 악성코드에 대해 글을 적어 보았습니다.

그리드형

공유하기

facebook twitter kakaoTalk kakaostory naver band