From ccde52ba69a7469dd67e79713c2bbc81d46d1c09 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 15 Oct 2024 04:49:44 +0300 Subject: [PATCH 1/8] feat: Add initial 21.xx support for WA + WAB --- .../xposed/core/devkit/Unobfuscator.java | 10 +++++++++- .../xposed/features/media/StatusDownload.java | 15 +++++++++++++-- app/src/main/res/values/arrays.xml | 3 +++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java index 0aeb8f9c..cce031c2 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java @@ -539,6 +539,13 @@ public synchronized static Field loadStatusDownloadFileField(ClassLoader classLo var clazz = loadStatusDownloadMediaClass(classLoader); var clazz2 = clazz.getField("A01").getType(); var field = ReflectionUtils.getFieldByType(clazz2, File.class); + + // for 21.xx, it returns null + if (field == null) { + clazz2 = clazz.getField("A02").getType(); + field = ReflectionUtils.getFieldByType(clazz2, File.class); + } + if (field == null) throw new Exception("StatusDownloadFile field not found"); return field; }); @@ -1073,7 +1080,8 @@ public synchronized static Method loadGetEditMessageMethod(ClassLoader loader) t if (methodData == null) throw new RuntimeException("GetEditMessage method not found"); var invokes = methodData.getInvokes(); for (var invoke : invokes) { - if (invoke.getParamTypes().isEmpty() && Objects.equals(invoke.getDeclaredClass(), methodData.getParamTypes().get(0))) { + // for 21.xx, it returns a method with one argument instead of zero + if (Objects.equals(invoke.getDeclaredClass(), methodData.getParamTypes().get(0))) { return invoke.getMethodInstance(loader); } } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java index 7c71e742..49257d32 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java @@ -100,8 +100,19 @@ private void sharedStatus(FMessageWpp fMessageWpp) { private void downloadFile(FMessageWpp fMessage) { try { - var fileData = XposedHelpers.getObjectField(fMessage.getObject(), "A01"); - if (!fieldFile.getDeclaringClass().isInstance(fileData)) { + Object fileData = null; + var fileData1 = XposedHelpers.getObjectField(fMessage.getObject(), "A01"); + if (fieldFile.getDeclaringClass().isInstance(fileData1)) { + fileData = fileData1; + } + + // for 21.xx, A01 is not File + var fieldData2 = XposedHelpers.getObjectField(fMessage.getObject(), "A02"); + if (fieldFile.getDeclaringClass().isInstance(fieldData2)) { + fileData = fieldData2; + } + + if (fileData == null) { Utils.showToast(Utils.getApplication().getString(ResId.string.msg_text_status_not_downloadable), Toast.LENGTH_SHORT); return; } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 2eb514db..35bd5b9f 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -120,12 +120,15 @@ 2.24.18.xx 2.24.19.xx 2.24.20.xx + 2.24.21.xx 2.24.16.xx 2.24.17.xx 2.24.18.xx 2.24.19.xx + 2.24.20.xx + 2.24.21.xx image/* From 3068d8fa8d3d2e73da1f2ebb70289f10b9d017c6 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 15 Oct 2024 04:58:56 +0300 Subject: [PATCH 2/8] perf: Typo fix for variable names --- .../wppenhacer/xposed/features/media/StatusDownload.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java index 49257d32..bc6c9fa0 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java @@ -107,9 +107,9 @@ private void downloadFile(FMessageWpp fMessage) { } // for 21.xx, A01 is not File - var fieldData2 = XposedHelpers.getObjectField(fMessage.getObject(), "A02"); - if (fieldFile.getDeclaringClass().isInstance(fieldData2)) { - fileData = fieldData2; + var fileData2 = XposedHelpers.getObjectField(fMessage.getObject(), "A02"); + if (fieldFile.getDeclaringClass().isInstance(fileData2)) { + fileData = fileData2; } if (fileData == null) { From beb82ebbb748cd279d5b2daf61b41cc74d5e7e9a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 15 Oct 2024 05:31:02 +0300 Subject: [PATCH 3/8] fix: GetEditMessage is static on 21.xx --- .../wppenhacer/xposed/features/general/ShowEditMessage.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java index 94063ffb..49629b56 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/general/ShowEditMessage.java @@ -28,6 +28,7 @@ import com.wmods.wppenhacer.xposed.utils.ResId; import com.wmods.wppenhacer.xposed.utils.Utils; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Objects; @@ -65,7 +66,10 @@ public void doHook() throws Throwable { XposedBridge.hookMethod(onMessageEdit, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - var editMessage = getEditMessage.invoke(param.args[0]); + // for 21.xx, getEditMessage is static + var editMessage = Modifier.isStatic(getEditMessage.getModifiers()) + ? getEditMessage.invoke(null, param.args[0]) + : getEditMessage.invoke(param.args[0]); if (editMessage == null) return; long timestamp = XposedHelpers.getLongField(editMessage, "A00"); var fMessage = new FMessageWpp(param.args[0]); From bfe83a3ca856f0c56132770765a24c2329a55980 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 15 Oct 2024 06:11:51 +0300 Subject: [PATCH 4/8] fix: Complete edit history --- .../wppenhacer/xposed/core/devkit/Unobfuscator.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java index cce031c2..c1362a29 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java @@ -1080,8 +1080,13 @@ public synchronized static Method loadGetEditMessageMethod(ClassLoader loader) t if (methodData == null) throw new RuntimeException("GetEditMessage method not found"); var invokes = methodData.getInvokes(); for (var invoke : invokes) { - // for 21.xx, it returns a method with one argument instead of zero - if (Objects.equals(invoke.getDeclaredClass(), methodData.getParamTypes().get(0))) { + // pre 21.xx method + if (invoke.getParamTypes().isEmpty() && Objects.equals(invoke.getDeclaredClass(), methodData.getParamTypes().get(0))) { + return invoke.getMethodInstance(loader); + } + + // 21.xx+ method (static) + if (Modifier.isStatic(invoke.getMethodInstance(loader).getModifiers()) && Objects.equals(invoke.getParamTypes().get(0), methodData.getParamTypes().get(0))) { return invoke.getMethodInstance(loader); } } From 2b61464411d5b49cc31c397b9de68884d649dc57 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 15 Oct 2024 07:04:40 +0300 Subject: [PATCH 5/8] fix: find workarounds for tablet UI to fix crashes --- .../main/java/com/wmods/wppenhacer/xposed/core/WppCore.java | 5 +++++ 1 file changed, 5 insertions(+) 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 8cce5300..e44c573a 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 @@ -352,6 +352,11 @@ public static Activity getCurrentConversation() { if (mCurrentActivity == null) return null; Class conversation = XposedHelpers.findClass("com.whatsapp.Conversation", mCurrentActivity.getClassLoader()); if (conversation.isInstance(mCurrentActivity)) return mCurrentActivity; + + // for tablet UI, they're using HomeActivity instead of Conversation + // TODO: Add more checks for ConversationFragment + Class home = XposedHelpers.findClass("com.whatsapp.HomeActivity", mCurrentActivity.getClassLoader()); + if (mCurrentActivity.getResources().getConfiguration().smallestScreenWidthDp >= 600 && home.isInstance(mCurrentActivity)) return mCurrentActivity; return null; } From 7590f1e398211715fe122d60161e8554f309dcaa Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 16 Oct 2024 18:12:49 +0300 Subject: [PATCH 6/8] feat: Use more compatible method for StatusDownload --- .../xposed/core/devkit/Unobfuscator.java | 14 +++++--------- .../xposed/features/media/StatusDownload.java | 17 ++++------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java b/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java index c1362a29..92cf0d90 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java @@ -537,17 +537,13 @@ public synchronized static Method loadMenuStatusMethod(ClassLoader loader) throw public synchronized static Field loadStatusDownloadFileField(ClassLoader classLoader) throws Exception { return UnobfuscatorCache.getInstance().getField(classLoader, () -> { var clazz = loadStatusDownloadMediaClass(classLoader); - var clazz2 = clazz.getField("A01").getType(); - var field = ReflectionUtils.getFieldByType(clazz2, File.class); - - // for 21.xx, it returns null - if (field == null) { - clazz2 = clazz.getField("A02").getType(); - field = ReflectionUtils.getFieldByType(clazz2, File.class); + for (Field clazzField : clazz.getFields()) { + var clazz2 = clazzField.getType(); + var field = ReflectionUtils.getFieldByType(clazz2, File.class); + if (field != null) return field; } - if (field == null) throw new Exception("StatusDownloadFile field not found"); - return field; + throw new Exception("StatusDownloadFile field not found"); }); } diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java index bc6c9fa0..db35e112 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java @@ -100,22 +100,13 @@ private void sharedStatus(FMessageWpp fMessageWpp) { private void downloadFile(FMessageWpp fMessage) { try { - Object fileData = null; - var fileData1 = XposedHelpers.getObjectField(fMessage.getObject(), "A01"); - if (fieldFile.getDeclaringClass().isInstance(fileData1)) { - fileData = fileData1; - } - - // for 21.xx, A01 is not File - var fileData2 = XposedHelpers.getObjectField(fMessage.getObject(), "A02"); - if (fieldFile.getDeclaringClass().isInstance(fileData2)) { - fileData = fileData2; - } - - if (fileData == null) { + Field fileField = ReflectionUtils.getFieldByType(fMessage.getObject().getClass(), fieldFile.getDeclaringClass()); + if (fileField == null) { Utils.showToast(Utils.getApplication().getString(ResId.string.msg_text_status_not_downloadable), Toast.LENGTH_SHORT); return; } + + Object fileData = XposedHelpers.getObjectField(fMessage.getObject(), fileField.getName()); var file = (File) ReflectionUtils.getField(fieldFile, fileData); var userJid = fMessage.getUserJid(); var fileType = file.getName().substring(file.getName().lastIndexOf(".") + 1); From 413681dd78fd507a2933cbaacb5db13869a0a3a5 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 16 Oct 2024 18:37:13 +0300 Subject: [PATCH 7/8] perf: Use more readable variable names --- .../wppenhacer/xposed/features/media/StatusDownload.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java index db35e112..97db61ab 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/media/StatusDownload.java @@ -100,13 +100,13 @@ private void sharedStatus(FMessageWpp fMessageWpp) { private void downloadFile(FMessageWpp fMessage) { try { - Field fileField = ReflectionUtils.getFieldByType(fMessage.getObject().getClass(), fieldFile.getDeclaringClass()); - if (fileField == null) { + Field fieldFileInMessage = ReflectionUtils.getFieldByType(fMessage.getObject().getClass(), fieldFile.getDeclaringClass()); + if (fieldFileInMessage == null) { Utils.showToast(Utils.getApplication().getString(ResId.string.msg_text_status_not_downloadable), Toast.LENGTH_SHORT); return; } - Object fileData = XposedHelpers.getObjectField(fMessage.getObject(), fileField.getName()); + var fileData = XposedHelpers.getObjectField(fMessage.getObject(), fieldFileInMessage.getName()); var file = (File) ReflectionUtils.getField(fieldFile, fileData); var userJid = fMessage.getUserJid(); var fileType = file.getName().substring(file.getName().lastIndexOf(".") + 1); From d3c3b8b7a78c3d99755f674780b60b1446b7389d Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 16 Oct 2024 20:00:30 +0300 Subject: [PATCH 8/8] feat: Try to fix google translate --- .../features/others/GoogleTranslate.java | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/others/GoogleTranslate.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/others/GoogleTranslate.java index 864c80f1..c091d411 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/others/GoogleTranslate.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/others/GoogleTranslate.java @@ -10,10 +10,13 @@ import java.io.IOException; import java.lang.reflect.Method; import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.concurrent.CompletableFuture; import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XC_MethodReplacement; import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; @@ -46,18 +49,43 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } }); - XposedHelpers.findAndHookMethod("com.whatsapp.messagetranslation.UnityMessageTranslation", classLoader, "translate", classLoader.loadClass("java.lang.String"), - new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - var texto = (String) param.args[0]; - var currentMethod = (Method) param.method; - var unityTranslationResultClass = currentMethod.getReturnType(); - var translation = translateGoogle(texto, Locale.getDefault().getLanguage()).get(); - var unityTranslationResult = unityTranslationResultClass.getConstructor(String.class, float.class, int.class).newInstance(translation, 1, 0); - param.setResult(unityTranslationResult); + Class translatorClazz = XposedHelpers.findClass("com.whatsapp.messagetranslation.UnityMessageTranslation", classLoader); + + var pre21Method = XposedHelpers.findMethodExactIfExists(translatorClazz, "translate", String.class); + if (pre21Method != null) { + XposedHelpers.findAndHookMethod(translatorClazz, pre21Method.getName(), String.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + var texto = (String) param.args[0]; + var currentMethod = (Method) param.method; + var unityTranslationResultClass = currentMethod.getReturnType(); + var translation = translateGoogle(texto, Locale.getDefault().getLanguage()).get(); + return unityTranslationResultClass.getConstructor(String.class, float.class, int.class).newInstance(translation, 1, 0); + } + }); + } + + var newMethod = XposedHelpers.findMethodExactIfExists(translatorClazz, "translate", List.class); + if (newMethod != null) { + XposedHelpers.findAndHookMethod(translatorClazz, "translate", List.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + var list = (List) param.args[0]; + var translated = new ArrayList(); + + for (var texto : list) { + var translation = translateGoogle((String) texto, Locale.getDefault().getLanguage()).get(); + translated.add(translation); } - }); + + var currentMethod = (Method) param.method; + var unityTranslationResultClass = currentMethod.getReturnType(); + return unityTranslationResultClass.getConstructor(String[].class, float.class, int.class).newInstance(translated.toArray(new String[0]), 1, 0); + } + }); + } + + if (pre21Method == null && newMethod == null) throw new Exception("GoogleTranslate method not found"); } public CompletableFuture translateGoogle(String text, String languageDest) {