Skip to content

Commit a65fc72

Browse files
committed
Refactor SeparateGroup and Unobfuscator
Refactored the `SeparateGroup` feature to simplify the process of adding a tab icon. Instead of using a complex chain of field lookups, it now hooks `addMenuAndroidX`.
1 parent acff81c commit a65fc72

File tree

2 files changed

+44
-83
lines changed

2 files changed

+44
-83
lines changed

app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java

Lines changed: 15 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import androidx.annotation.Nullable;
2020

2121
import com.wmods.wppenhacer.xposed.core.WppCore;
22+
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp;
2223
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
2324
import com.wmods.wppenhacer.xposed.utils.Utils;
2425

@@ -395,54 +396,6 @@ public synchronized static Method loadIconTabMethod(ClassLoader classLoader) thr
395396
});
396397
}
397398

398-
public synchronized static Field loadPreIconTabField(ClassLoader classLoader) throws Exception {
399-
return UnobfuscatorCache.getInstance().getField(classLoader, () -> {
400-
Class<?> cls = loadIconTabMethod(classLoader).getDeclaringClass();
401-
Class<?> clsType = findFirstClassUsingStringsFilter(classLoader, "X.", StringMatchType.Contains, "Tried to set badge");
402-
if (clsType == null) throw new Exception("PreIconTabField not found");
403-
Field result = null;
404-
for (var field1 : cls.getFields()) {
405-
Object checkResult = Arrays.stream(field1.getType().getFields()).filter(f -> f.getType().equals(clsType)).findFirst().orElse(null);
406-
if (checkResult != null) {
407-
result = field1;
408-
break;
409-
}
410-
}
411-
if (result == null) throw new Exception("PreIconTabField not found 2");
412-
return result;
413-
});
414-
}
415-
416-
public synchronized static Field loadIconTabField(ClassLoader classLoader) throws Exception {
417-
return UnobfuscatorCache.getInstance().getField(classLoader, () -> {
418-
Class<?> cls = loadIconTabMethod(classLoader).getDeclaringClass();
419-
Class<?> clsType = findFirstClassUsingStringsFilter(classLoader, "X.", StringMatchType.Contains, "Tried to set badge");
420-
if (clsType == null) throw new Exception("IconTabField not found");
421-
for (var field1 : cls.getFields()) {
422-
var result = Arrays.stream(field1.getType().getFields()).filter(f -> f.getType().equals(clsType)).findFirst().orElse(null);
423-
if (result != null) return result;
424-
}
425-
throw new Exception("IconTabField not found 2");
426-
});
427-
}
428-
429-
public synchronized static Field loadIconTabLayoutField(ClassLoader classLoader) throws Exception {
430-
return UnobfuscatorCache.getInstance().getField(classLoader, () -> {
431-
Class<?> clsType = loadIconTabField(classLoader).getType();
432-
Class<?> framelayout = findFirstClassUsingStringsFilter(classLoader, "X.", StringMatchType.Contains, "android:menu:presenters");
433-
var result = Arrays.stream(clsType.getFields()).filter(f -> f.getType().equals(framelayout)).findFirst().orElse(null);
434-
if (result == null) throw new Exception("IconTabLayoutField not found");
435-
return result;
436-
});
437-
}
438-
439-
public synchronized static Field loadIconMenuField(ClassLoader classLoader) throws Exception {
440-
return UnobfuscatorCache.getInstance().getField(classLoader, () -> {
441-
Class<?> clsType = loadIconTabLayoutField(classLoader).getType();
442-
Class<?> menuClass = findFirstClassUsingStringsFilter(classLoader, "X.", StringMatchType.Contains, "Maximum number of items");
443-
return Arrays.stream(clsType.getFields()).filter(f -> f.getType().equals(menuClass)).findFirst().orElse(null);
444-
});
445-
}
446399

447400
public synchronized static Method loadTabCountMethod(ClassLoader classLoader) throws Exception {
448401
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
@@ -1482,7 +1435,7 @@ public synchronized static Class getFilterView(ClassLoader loader) throws Except
14821435

14831436
public synchronized static Class loadActionUser(ClassLoader loader) throws Exception {
14841437
return UnobfuscatorCache.getInstance().getClass(loader, () -> {
1485-
for (String s : List.of("UserActions/userActionDeleteMessages", "UserActions/reportIfBadTime: time=", "UserActions/createFMessageTextFromUserInputs", "UserActions/userActionKeepInChat", "UserActions/userActionSendMediaMessages")) {
1438+
for (String s : List.of("UserActions/userActionDeleteMessages", "UserActions/reportIfBadTime: time=", "UserActions/createFMessageTextFromUserInputs", "UserActions/userActionKeepInChat", "UserActions/userActionSendMediaMessages", "UserActions/userActionForwardMessage")) {
14861439
var clazz = findFirstClassUsingStrings(loader, StringMatchType.Contains, s);
14871440
if (clazz != null)
14881441
return clazz;
@@ -1867,11 +1820,15 @@ public static synchronized Class loadCachedMessageStore(ClassLoader loader) thro
18671820

18681821
public static synchronized Class loadAbstractMediaMessageClass(ClassLoader loader) throws Exception {
18691822
return UnobfuscatorCache.getInstance().getClass(loader, () -> {
1870-
var fmessage = loadFMessageClass(loader);
1871-
var classList = dexkit.findClass(FindClass.create().matcher(ClassMatcher.create().addUsingString("first_viewed_timestamp").superClass(fmessage.getName())));
1872-
if (classList.isEmpty())
1873-
throw new RuntimeException("AbstractMediaMessage class not found");
1874-
return classList.get(0).getInstance(loader);
1823+
for (var str : List.of("first_viewed_timestamp", "Field is set but is null in MediaDataV2")) {
1824+
var classList = dexkit.findClass(FindClass.create().matcher(ClassMatcher.create().addUsingString(str)));
1825+
for (var clazz : classList) {
1826+
var clazzInstance = clazz.getInstance(loader);
1827+
if (FMessageWpp.checkUnsafeIsFMessage(loader, clazzInstance))
1828+
return clazzInstance;
1829+
}
1830+
}
1831+
throw new ClassNotFoundException("AbstractMediaMessage Not Found");
18751832
});
18761833
}
18771834

@@ -2053,4 +2010,8 @@ public static Method loadAddOptionSearchBarMethod(ClassLoader classLoader) throw
20532010
return methodData.get(0).getMethodInstance(classLoader);
20542011
});
20552012
}
2013+
2014+
public static Method loadAddMenuAndroidX(ClassLoader classLoader) throws Exception {
2015+
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, "Maximum number of items supported by"));
2016+
}
20562017
}

app/src/main/java/com/wmods/wppenhacer/xposed/features/customization/SeparateGroup.java

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.wmods.wppenhacer.xposed.core.db.MessageStore;
1717
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
1818
import com.wmods.wppenhacer.xposed.core.devkit.UnobfuscatorCache;
19+
import com.wmods.wppenhacer.xposed.utils.DebugUtils;
1920
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
2021
import com.wmods.wppenhacer.xposed.utils.Utils;
2122

@@ -24,6 +25,7 @@
2425
import java.util.HashMap;
2526
import java.util.List;
2627
import java.util.Objects;
28+
import java.util.Set;
2729
import java.util.regex.Pattern;
2830

2931
import de.robv.android.xposed.XC_MethodHook;
@@ -137,37 +139,35 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
137139
private void hookTabIcon() throws Exception {
138140
var iconTabMethod = Unobfuscator.loadIconTabMethod(classLoader);
139141
logDebug(Unobfuscator.getMethodDescriptor(iconTabMethod));
140-
var iconField = Unobfuscator.loadIconTabField(classLoader);
141-
var iconFrameField = Unobfuscator.loadIconTabLayoutField(classLoader);
142-
var iconMenuField = Unobfuscator.loadIconMenuField(classLoader);
142+
var menuAddAndroidX = Unobfuscator.loadAddMenuAndroidX(classLoader);
143+
logDebug(menuAddAndroidX);
143144

144145
XposedBridge.hookMethod(iconTabMethod, new XC_MethodHook() {
145-
@SuppressLint("ResourceType")
146-
@Override
147-
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
148-
var obj = param.thisObject;
149-
var superClass = obj.getClass().getSuperclass();
150-
151-
// for 23.xx, superClass != iconTabMethod.getDeclaringClass()
152-
if (!(superClass != null && superClass == iconTabMethod.getDeclaringClass())) {
153-
var preIconTabField = Unobfuscator.loadPreIconTabField(classLoader);
154-
var field0 = getObjectField(obj, preIconTabField.getName());
155-
superClass = field0.getClass().getSuperclass();
156-
obj = field0;
157-
}
158146

159-
var field1 = superClass.getDeclaredField(iconField.getName()).get(obj);
160-
var field2 = getObjectField(field1, iconFrameField.getName());
161-
if (field2 == null) return;
162-
var menu = (Menu) getObjectField(field2, iconMenuField.getName());
163-
if (menu == null) return;
164-
// add Icon to menu
165-
var menuItem = (MenuItem) menu.findItem(GROUPS);
166-
if (menuItem != null) {
167-
menuItem.setIcon(Utils.getID("home_tab_communities_selector", "drawable"));
147+
private Unhook hooked;
148+
149+
@Override
150+
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
151+
hooked = XposedBridge.hookMethod(menuAddAndroidX, new XC_MethodHook() {
152+
@Override
153+
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
154+
if (param.args.length > 2 && ((int) param.args[1]) == GROUPS) {
155+
MenuItem menuItem = (MenuItem) param.getResult();
156+
menuItem.setIcon(Utils.getID("home_tab_communities_selector", "drawable"));
157+
}
158+
}
159+
});
160+
}
161+
162+
@SuppressLint("ResourceType")
163+
@Override
164+
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
165+
if (hooked != null) {
166+
hooked.unhook();
167+
}
168+
}
168169
}
169-
}
170-
});
170+
);
171171
}
172172

173173
@SuppressLint("ResourceType")
@@ -225,7 +225,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
225225
XposedBridge.hookMethod(getTabMethod, new XC_MethodHook() {
226226
@Override
227227
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
228-
var tabId = ((Number) tabs.get((int) param.args[0])).intValue();
228+
var tabId = tabs.get((int) param.args[0]).intValue();
229229
if (tabId == GROUPS || tabId == CHATS) {
230230
var convFragment = cFrag.newInstance();
231231
param.setResult(convFragment);
@@ -234,7 +234,7 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
234234

235235
@Override
236236
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
237-
var tabId = ((Number) tabs.get((int) param.args[0])).intValue();
237+
var tabId = tabs.get((int) param.args[0]).intValue();
238238
tabInstances.remove(tabId);
239239
tabInstances.put(tabId, param.getResult());
240240
}

0 commit comments

Comments
 (0)