diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/MainFeatures.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/MainFeatures.java index 887f6f15..8755fa49 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/MainFeatures.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/MainFeatures.java @@ -43,6 +43,7 @@ import com.wmods.wppenhacer.xposed.features.general.ShareLimit; import com.wmods.wppenhacer.xposed.features.general.ShowEditMessage; import com.wmods.wppenhacer.xposed.features.general.StatusDownload; +import com.wmods.wppenhacer.xposed.features.general.Tasker; import com.wmods.wppenhacer.xposed.features.general.ViewOnce; import com.wmods.wppenhacer.xposed.features.privacy.FreezeLastSeen; import com.wmods.wppenhacer.xposed.features.privacy.GhostMode; @@ -211,7 +212,8 @@ private static void plugins(@NonNull ClassLoader loader, @NonNull XSharedPrefere ViewOnce.class, CallType.class, MediaPreview.class, - FilterGroups.class + FilterGroups.class, + Tasker.class }; for (var classe : classes) { diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/Unobfuscator.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/Unobfuscator.java index 29564d5d..e353a720 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/Unobfuscator.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/Unobfuscator.java @@ -1528,4 +1528,13 @@ public static Class getFilterView(ClassLoader loader) throws Exception { return results.get(0).getInstance(loader); }); } + + public static Class loadActionUser(ClassLoader loader) throws Exception { + return UnobfuscatorCache.getInstance().getClass(loader, () -> { + var results = dexkit.findClass(new FindClass().matcher(new ClassMatcher().addUsingString("UserActions/reportIfBadTime: time="))); + if (results.isEmpty()) throw new RuntimeException("ActionUser class not found"); + return results.get(0).getInstance(loader); + }); + } + } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java index 564000d5..e72dd058 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java @@ -7,6 +7,7 @@ import android.content.SharedPreferences; import android.graphics.drawable.Drawable; import android.view.Menu; +import android.widget.Toast; import androidx.annotation.Nullable; @@ -18,6 +19,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -43,6 +45,7 @@ public class WppCore { private static Object mContactManager; private static SharedPreferences privPrefs; private static Object mStartUpConfig; + private static Object mActionUser; public static void addMenuItemClass(Class aClass, OnMenuCreate listener) { var list = listenerMenu.computeIfAbsent(aClass, k -> new ArrayList<>()); @@ -56,6 +59,37 @@ public static void addMenuItemString(String className, OnMenuCreate listener) { list.add(listener); } + public static Object getConversation() { + return mConversation; + } + + public static void sendMessage(String number, String message) { + try { + var senderMethod = ReflectionUtils.findMethodUsingFilterIfExists(mActionUser.getClass(), (method) -> List.class.isAssignableFrom(method.getReturnType()) && ReflectionUtils.findIndexOfType(method.getParameterTypes(), String.class) != -1); + if (senderMethod != null) { + var userJid = createUserJid(number + "@s.whatsapp.net"); + if (userJid == null) { + Utils.showToast("UserJID not found", Toast.LENGTH_SHORT); + return; + } + var newObject = new Object[senderMethod.getParameterCount()]; + var index = ReflectionUtils.findIndexOfType(senderMethod.getParameterTypes(), String.class); + newObject[index - 1] = 0; + newObject[index] = message; + newObject[newObject.length - 1] = false; + newObject[newObject.length - 2] = false; + newObject[newObject.length - 3] = false; + var index2 = ReflectionUtils.findIndexOfType(senderMethod.getParameterTypes(), List.class); + newObject[index2] = Collections.singletonList(userJid); + senderMethod.invoke(mActionUser, newObject); + Utils.showToast("Message sent to " + number, Toast.LENGTH_SHORT); + } + } catch (Exception e) { + Utils.showToast("Error in sending message:" + e.getMessage(), Toast.LENGTH_SHORT); + XposedBridge.log(e); + } + } + public interface ObjectOnChangeListener { void onChange(Object object, String type); @@ -63,95 +97,106 @@ public interface ObjectOnChangeListener { } public static void Initialize(ClassLoader loader) throws Exception { - privPrefs = Utils.getApplication().getSharedPreferences("WaGlobal", Context.MODE_PRIVATE); + privPrefs = Utils.getApplication().getSharedPreferences("WaGlobal", Context.MODE_PRIVATE); - // init Main activity - XposedBridge.hookAllMethods(XposedHelpers.findClass("com.whatsapp.HomeActivity", loader), "onCreate", new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - mainActivity = param.thisObject; - } - }); + // init Main activity + XposedBridge.hookAllMethods(XposedHelpers.findClass("com.whatsapp.HomeActivity", loader), "onCreate", new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + mainActivity = param.thisObject; + } + }); - XposedBridge.hookAllMethods(XposedHelpers.findClass("com.whatsapp.HomeActivity", loader), "onResume", new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - mainActivity = param.thisObject; - } - }); - - XposedHelpers.findAndHookMethod(Activity.class, "onCreateOptionsMenu", Menu.class, new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - for (Class aClass : listenerMenu.keySet()) { - if (!aClass.isInstance(param.thisObject)) return; - for (OnMenuCreate listener : listenerMenu.get(aClass)) { - listener.onBeforeCreate((Activity) param.thisObject, (Menu) param.args[0]); - } + XposedBridge.hookAllMethods(XposedHelpers.findClass("com.whatsapp.HomeActivity", loader), "onResume", new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + mainActivity = param.thisObject; + } + }); + + XposedHelpers.findAndHookMethod(Activity.class, "onCreateOptionsMenu", Menu.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + for (Class aClass : listenerMenu.keySet()) { + if (!aClass.isInstance(param.thisObject)) return; + for (OnMenuCreate listener : listenerMenu.get(aClass)) { + listener.onBeforeCreate((Activity) param.thisObject, (Menu) param.args[0]); } } + } - @Override - protected void afterHookedMethod(MethodHookParam param) throws Throwable { - for (Class aClass : listenerMenu.keySet()) { - if (!aClass.isInstance(param.thisObject)) return; - for (OnMenuCreate listener : listenerMenu.get(aClass)) { - listener.onAfterCreate((Activity) param.thisObject, (Menu) param.args[0]); - } + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + for (Class aClass : listenerMenu.keySet()) { + if (!aClass.isInstance(param.thisObject)) return; + for (OnMenuCreate listener : listenerMenu.get(aClass)) { + listener.onAfterCreate((Activity) param.thisObject, (Menu) param.args[0]); } } - }); - - // init ContactManager - getContactMethod = Unobfuscator.loadGetContactInfoMethod(loader); - XposedBridge.hookAllConstructors(getContactMethod.getDeclaringClass(), new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) throws Throwable { - mContactManager = param.thisObject; - } - }); - - // init UserJID - var mSendReadClass = XposedHelpers.findClass("com.whatsapp.jobqueue.job.SendReadReceiptJob", loader); - var subClass = Arrays.stream(mSendReadClass.getConstructors()).filter(c -> c.getParameterTypes().length == 8).findFirst().orElse(null).getParameterTypes()[0]; - mGenJidClass = Arrays.stream(subClass.getFields()).filter(field -> Modifier.isStatic(field.getModifiers())).findFirst().orElse(null).getType(); - mGenJidMethod = Arrays.stream(mGenJidClass.getMethods()).filter(m -> m.getParameterCount() == 1 && !Modifier.isStatic(m.getModifiers())).findFirst().orElse(null); - // Bottom Dialog - bottomDialog = Unobfuscator.loadDialogViewClass(loader); - - // Conversation - var onStartMethod = Unobfuscator.loadAntiRevokeOnStartMethod(loader); - var onResumeMethod = Unobfuscator.loadAntiRevokeOnResumeMethod(loader); - convChatField = Unobfuscator.loadAntiRevokeConvChatField(loader); - chatJidField = Unobfuscator.loadAntiRevokeChatJidField(loader); - XposedBridge.hookMethod(onStartMethod, new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) { - mConversation = (Activity) param.thisObject; - for (ObjectOnChangeListener listener : listenerChat) { - listener.onChange(mConversation, "onStartConversation"); - } - } - }); - - XposedBridge.hookMethod(onResumeMethod, new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) { - mConversation = (Activity) param.thisObject; - for (ObjectOnChangeListener listener : listenerChat) { - listener.onChange(mConversation, "onResumeConversation"); - } + } + }); + + // init ContactManager + getContactMethod = Unobfuscator.loadGetContactInfoMethod(loader); + XposedBridge.hookAllConstructors(getContactMethod.getDeclaringClass(), new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + mContactManager = param.thisObject; + } + }); + + // init UserJID + var mSendReadClass = XposedHelpers.findClass("com.whatsapp.jobqueue.job.SendReadReceiptJob", loader); + var subClass = Arrays.stream(mSendReadClass.getConstructors()).filter(c -> c.getParameterTypes().length == 8).findFirst().orElse(null).getParameterTypes()[0]; + mGenJidClass = Arrays.stream(subClass.getFields()).filter(field -> Modifier.isStatic(field.getModifiers())).findFirst().orElse(null).getType(); + mGenJidMethod = Arrays.stream(mGenJidClass.getMethods()).filter(m -> m.getParameterCount() == 1 && !Modifier.isStatic(m.getModifiers())).findFirst().orElse(null); + // Bottom Dialog + bottomDialog = Unobfuscator.loadDialogViewClass(loader); + + // Conversation + var onStartMethod = Unobfuscator.loadAntiRevokeOnStartMethod(loader); + var onResumeMethod = Unobfuscator.loadAntiRevokeOnResumeMethod(loader); + convChatField = Unobfuscator.loadAntiRevokeConvChatField(loader); + chatJidField = Unobfuscator.loadAntiRevokeChatJidField(loader); + XposedBridge.hookMethod(onStartMethod, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) { + mConversation = (Activity) param.thisObject; + for (ObjectOnChangeListener listener : listenerChat) { + listener.onChange(mConversation, "onStartConversation"); } - }); - - // StartUpPrefs - var startPrefsConfig = Unobfuscator.loadStartPrefsConfig(loader); - XposedBridge.hookMethod(startPrefsConfig, new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - mStartUpConfig = param.thisObject; + } + }); + + XposedBridge.hookMethod(onResumeMethod, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) { + mConversation = (Activity) param.thisObject; + for (ObjectOnChangeListener listener : listenerChat) { + listener.onChange(mConversation, "onResumeConversation"); } - }); + } + }); + + // StartUpPrefs + var startPrefsConfig = Unobfuscator.loadStartPrefsConfig(loader); + XposedBridge.hookMethod(startPrefsConfig, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + mStartUpConfig = param.thisObject; + } + }); + + var actionUser = Unobfuscator.loadActionUser(loader); + XposedBridge.hookAllConstructors(actionUser, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + mActionUser = param.thisObject; + XposedBridge.log("mActionUser: " + mActionUser); + } + }); + + } public static int getDefaultTheme() { diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java new file mode 100644 index 00000000..fb459495 --- /dev/null +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/Tasker.java @@ -0,0 +1,94 @@ +package com.wmods.wppenhacer.xposed.features.general; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.wmods.wppenhacer.xposed.core.Feature; +import com.wmods.wppenhacer.xposed.core.Unobfuscator; +import com.wmods.wppenhacer.xposed.core.Utils; +import com.wmods.wppenhacer.xposed.core.WppCore; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XSharedPreferences; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +public class Tasker extends Feature { + private static Object fMessage; + + public Tasker(@NonNull ClassLoader classLoader, @NonNull XSharedPreferences preferences) { + super(classLoader, preferences); + } + + @Override + public void doHook() throws Throwable { + if (!prefs.getBoolean("tasker", false)) return; + hookReceiveMessage(); + registerSenderMessage(); + } + + @NonNull + @Override + public String getPluginName() { + return "Tasker"; + } + + private void registerSenderMessage() { + IntentFilter filter = new IntentFilter("com.wmods.wppenhacer.MESSAGE_SENT"); + ContextCompat.registerReceiver(Utils.getApplication(), new SenderMessageBroadcastReceiver(), filter, ContextCompat.RECEIVER_EXPORTED); + } + + public void hookReceiveMessage() throws Throwable { + var method = Unobfuscator.loadReceiptMethod(classLoader); + var method2 = Unobfuscator.loadReceiptOutsideChat(classLoader); + var newMessageMethod = Unobfuscator.loadNewMessageMethod(classLoader); + var fieldMessageKey = Unobfuscator.loadMessageKeyField(classLoader); + + XposedBridge.hookMethod(method2, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + fMessage = param.args[0]; + } + }); + + XposedBridge.hookMethod(method, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + if (param.args[4] == "sender" || param.args[1] == null) return; + var messageKey = fieldMessageKey.get(fMessage); + var userJid = XposedHelpers.getObjectField(messageKey, "A00"); + var rawJid = WppCore.getRawString(userJid); + var number = WppCore.stripJID(rawJid); + var msg = (String) newMessageMethod.invoke(fMessage); + new Handler(Utils.getApplication().getMainLooper()).post(() -> { + Intent intent = new Intent("com.wmods.wppenhacer.MESSAGE_RECEIVED"); + intent.putExtra("number", number); + intent.putExtra("message", msg); + Utils.getApplication().sendBroadcast(intent); + }); + } + }); + + } + + public static class SenderMessageBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + XposedBridge.log("Message sent"); + var number = intent.getStringExtra("number"); + var message = intent.getStringExtra("message"); + if (number == null || message == null) return; + number = number.replaceAll("\\D", ""); + WppCore.sendMessage(number, message); + } + } + + +} diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/utils/ReflectionUtils.java b/app/src/main/java/com/wmods/wppenhacer/xposed/utils/ReflectionUtils.java index 81d01a5e..f04a7fd6 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/utils/ReflectionUtils.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/utils/ReflectionUtils.java @@ -86,7 +86,12 @@ public static Object getField(Field loadProfileInfoField, Object thisObject) { public static int findIndexOfType(Object[] args, Class type) { for (int i = 0; i < args.length; i++) { - if (args[i] != null && type.isAssignableFrom(args[i].getClass())) return i; + if (args[i] == null) continue; + if (args[i] instanceof Class) { + if (type.isAssignableFrom((Class) args[i])) return i; + continue; + } + if (type.isAssignableFrom(args[i].getClass())) return i; } return -1; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bc173e79..28c7605b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -249,4 +249,6 @@ Call declined Unable to receive WhatsApp calls Not answered + Enable Tasker Automation + Enables the possibility of using intent to receive and send messages in Tasker diff --git a/app/src/main/res/xml/fragment_general.xml b/app/src/main/res/xml/fragment_general.xml index b07fe19b..cd2972aa 100644 --- a/app/src/main/res/xml/fragment_general.xml +++ b/app/src/main/res/xml/fragment_general.xml @@ -29,6 +29,12 @@ app:iconSpaceReserved="false" app:key="secondstotime" app:title="@string/textonahora" /> + + +