x1ongzhu 1 anno fa
parent
commit
a49410e8e4

+ 10 - 4
app/build.gradle

@@ -40,8 +40,14 @@ dependencies {
     testImplementation libs.junit
     androidTestImplementation libs.ext.junit
     androidTestImplementation libs.espresso.core
-    implementation 'com.google.code.gson:gson:2.10.1'
-    implementation 'com.google.android.material:material:1.4.0'
-    implementation 'org.apache.commons:commons-lang3:3.14.0'
-    implementation 'commons-io:commons-io:2.16.1'
+    implementation libs.gson
+    implementation libs.commons.lang3
+    implementation libs.commons.collections4
+    implementation libs.commons.io
+    implementation(libs.socket.io.client) {
+        exclude group: 'org.json', module: 'json'
+    }
+    implementation (libs.socket.io.client) {
+        exclude group: 'org.json', module: 'json'
+    }
 }

+ 19 - 2
app/src/main/AndroidManifest.xml

@@ -2,6 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
 
+    <uses-permission android:name="android.permission.INTERNET" />
     <application
         android:allowBackup="true"
         android:dataExtractionRules="@xml/data_extraction_rules"
@@ -11,11 +12,27 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/Theme.Modifier"
+        android:usesCleartextTraffic="true"
         tools:targetApi="31">
+        <service
+            android:name=".ModifierService"
+            android:enabled="true"
+            android:exported="true"
+            android:label="@string/accessibility_service_label"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+
+            <meta-data
+                android:name="android.accessibilityservice"
+                android:resource="@xml/accessibility_service_config" />
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService" />
+            </intent-filter>
+        </service>
+
         <activity
             android:name=".MainActivity"
-            android:windowSoftInputMode="adjustResize"
-            android:exported="true">
+            android:exported="true"
+            android:windowSoftInputMode="adjustResize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 

+ 34 - 35
app/src/main/java/com/example/modifier/MainActivity.java

@@ -4,11 +4,13 @@ import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
 
 import androidx.activity.EdgeToEdge;
+import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.graphics.Insets;
 import androidx.core.view.ViewCompat;
@@ -29,6 +31,7 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
@@ -104,6 +107,33 @@ public class MainActivity extends AppCompatActivity {
             intent.putExtra("message", "Your Messenger verification code is G-" + otp);
             sendBroadcast(intent);
         });
+
+        checkRoot();
+        Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(intent);
+    }
+
+    private void checkRoot() {
+        boolean rootAccess = false;
+        try {
+            String res = runAsRoot("echo 'imrooted'");
+            if (res.contains("imrooted")) {
+                rootAccess = true;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (!rootAccess) {
+            new AlertDialog.Builder(this)
+                    .setTitle("No Root Access")
+                    .setMessage("Root access is required to run this app")
+                    .setCancelable(false)
+                    .setPositiveButton("Exit", (dialog, which) -> {
+                        finish();
+                    })
+                    .show();
+        }
     }
 
     private void onSave() {
@@ -238,7 +268,7 @@ public class MainActivity extends AppCompatActivity {
     }
 
 
-    private void runAsRoot(String... cmds) throws IOException, InterruptedException {
+    private String runAsRoot(String... cmds) throws IOException, InterruptedException {
         File outputDir = getCacheDir(); // context being the Activity pointer
         File outputFile = File.createTempFile("su0000000", ".log", outputDir);
         Log.i(TAG, "Output file: " + outputFile.getAbsolutePath());
@@ -258,7 +288,9 @@ public class MainActivity extends AppCompatActivity {
         outputStream.flush();
         p.waitFor();
         String res = FileUtils.readFileToString(outputFile, "UTF-8");
-        Log.i(TAG, "Command executed: \n" + res);
+        Log.i(TAG, "Command output: \n" + res);
+        outputFile.delete();
+        return res;
     }
 
     String generateIMEI() {
@@ -303,37 +335,4 @@ public class MainActivity extends AppCompatActivity {
 
         return imei;
     }
-
-
-    class StreamLogger implements Runnable {
-        private final InputStream is;
-
-        public StreamLogger(InputStream is) {
-            this.is = is;
-        }
-
-        @Override
-        public void run() {
-            try {
-                BufferedReader br = new BufferedReader(new InputStreamReader(is));
-                String line = null;
-                while ((line = br.readLine()) != null) {
-                    Log.i(TAG, "Cmd Output: " + line);
-                    try {
-                        Thread.sleep(500);
-                    } catch (InterruptedException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            } finally {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
 }

+ 86 - 0
app/src/main/java/com/example/modifier/ModifierService.java

@@ -0,0 +1,86 @@
+package com.example.modifier;
+
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import io.socket.client.IO;
+import io.socket.client.Socket;
+import io.socket.emitter.Emitter;
+
+public class ModifierService extends android.accessibilityservice.AccessibilityService implements Emitter.Listener {
+
+    private static final String TAG = "ModifierService";
+
+    private Socket mSocket;
+
+    public ModifierService() {
+        Log.i(TAG, "Creating ModifierService");
+        try {
+            mSocket = IO.socket("http://192.168.6.215:3000");
+            mSocket.on("message", this);
+            mSocket.on(Socket.EVENT_CONNECT, args -> {
+                Log.i(TAG, "Connected to server");
+            });
+            mSocket.on(Socket.EVENT_DISCONNECT, args -> {
+                Log.i(TAG, "Disconnected from server");
+            });
+            mSocket.on(Socket.EVENT_CONNECT_ERROR, args -> {
+                Log.i(TAG, "Connection error: " + args[0]);
+                if (args[0] instanceof Exception) {
+                    Exception e = (Exception) args[0];
+                    e.printStackTrace();
+                }
+            });
+        } catch (URISyntaxException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "Starting ModifierService");
+        mSocket.connect();
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+
+    }
+
+    @Override
+    public void onInterrupt() {
+
+    }
+
+    @Override
+    public void call(Object... args) {
+        if (args.length > 0) {
+            Log.i(TAG, "Received message: " + args[0]);
+            if (args[0] instanceof JSONObject) {
+                JSONObject json = (JSONObject) args[0];
+                String action = json.optString("action");
+                if ("send".equals(action)) {
+                    JSONObject data = json.optJSONObject("data");
+                    if (data != null) {
+                        String to = data.optString("to");
+                        String body = data.optString("body");
+                        Log.i(TAG, "Sending SMS to " + to + ": " + body);
+                        String cmd = "am start -a android.intent.action.SENDTO -d sms:" + to + " --es sms_body " + body + " --ez exit_on_sent true";
+                        try {
+                            Utils.runAsRoot(cmd);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+}

+ 4 - 0
app/src/main/java/com/example/modifier/MyApplication.java

@@ -0,0 +1,4 @@
+package com.example.modifier;
+
+public class MyApplication {
+}

+ 56 - 0
app/src/main/java/com/example/modifier/Utils.java

@@ -0,0 +1,56 @@
+package com.example.modifier;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+public class Utils {
+    private static final String TAG = "Modifier";
+
+    public static Context getContext() {
+        try {
+            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
+            Method currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread");
+            currentActivityThreadMethod.setAccessible(true);
+            Object currentActivityThread = currentActivityThreadMethod.invoke(null);
+            Method getApplicationMethod = activityThreadClass.getMethod("getApplication");
+            getApplicationMethod.setAccessible(true);
+            return (Context) getApplicationMethod.invoke(currentActivityThread);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static String runAsRoot(String... cmds) throws IOException, InterruptedException {
+        Log.i(TAG, "Trying to run as root");
+        Context context = getContext();
+        File outputDir = context.getCacheDir(); // context being the Activity pointer
+        File outputFile = File.createTempFile("su0000000", ".log", outputDir);
+
+        Process p = new ProcessBuilder("su")
+                .redirectErrorStream(true)
+                .redirectOutput(outputFile)
+                .start();
+
+        DataOutputStream outputStream = new DataOutputStream(p.getOutputStream());
+        for (String cmd : cmds) {
+            outputStream.writeBytes(cmd + "\n");
+            outputStream.flush();
+            Log.i(TAG, "Running command: " + cmd);
+        }
+        outputStream.writeBytes("exit\n");
+        outputStream.flush();
+        p.waitFor();
+        String res = FileUtils.readFileToString(outputFile, "UTF-8");
+        Log.i(TAG, "Command output: \n" + res);
+        outputFile.delete();
+        return res;
+    }
+}

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -1,3 +1,5 @@
 <resources>
     <string name="app_name">Modifier</string>
+    <string name="accessibility_service_label">ModifierService</string>
+    <string name="accessibility_service_description">ModifierService</string>
 </resources>

+ 9 - 0
app/src/main/res/xml/accessibility_service_config.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accessibilityEventTypes="typeAllMask"
+    android:accessibilityFeedbackType="feedbackGeneric"
+    android:accessibilityFlags="flagDefault"
+    android:canPerformGestures="true"
+    android:canRetrieveWindowContent="true"
+    android:description="@string/accessibility_service_description"
+    android:notificationTimeout="100" />

+ 10 - 0
gradle/libs.versions.toml

@@ -1,5 +1,9 @@
 [versions]
 agp = "8.3.2"
+commonsCollections4 = "4.4"
+commonsIo = "2.16.1"
+commonsLang3 = "3.14.0"
+gson = "2.10.1"
 junit = "4.13.2"
 junitVersion = "1.1.5"
 espressoCore = "3.5.1"
@@ -7,8 +11,13 @@ appcompat = "1.6.1"
 material = "1.11.0"
 activity = "1.8.0"
 constraintlayout = "2.1.4"
+socketIoClient = "2.0.0"
 
 [libraries]
+commons-collections4 = { module = "org.apache.commons:commons-collections4", version.ref = "commonsCollections4" }
+commons-io = { module = "commons-io:commons-io", version.ref = "commonsIo" }
+commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang3" }
+gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
 junit = { group = "junit", name = "junit", version.ref = "junit" }
 ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
 espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@@ -16,6 +25,7 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a
 material = { group = "com.google.android.material", name = "material", version.ref = "material" }
 activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
 constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+socket-io-client = { module = "io.socket:socket.io-client", version.ref = "socketIoClient" }
 
 [plugins]
 androidApplication = { id = "com.android.application", version.ref = "agp" }