Skip to content

Commit

Permalink
Merge branch 'Dev4Mod:master' into theme
Browse files Browse the repository at this point in the history
  • Loading branch information
Strange-IPmart authored Oct 23, 2024
2 parents 8b12b62 + df2467f commit 4e5afec
Show file tree
Hide file tree
Showing 36 changed files with 725 additions and 215 deletions.
11 changes: 11 additions & 0 deletions .idea/other.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</queries>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
private static void initComponents(ClassLoader loader, XSharedPreferences pref) throws Exception {
AlertDialogWpp.initDialog(loader);
FMessageWpp.init(loader);
Utils.init(loader);
}

private static void registerReceivers() {
Expand Down
39 changes: 35 additions & 4 deletions app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@ public class WppCore {
private static Object mActionUser;
private static SQLiteDatabase mWaDatabase;
public static BaseClient client;
private static boolean isBridgeInitialized;
private static Object mCachedMessageStore;


public static void Initialize(ClassLoader loader) throws Exception {
privPrefs = Utils.getApplication().getSharedPreferences("WaGlobal", Context.MODE_PRIVATE);


// init UserJID
var mSendReadClass = XposedHelpers.findClass("com.whatsapp.jobqueue.job.SendReadReceiptJob", loader);
var subClass = ReflectionUtils.findConstructorUsingFilter(mSendReadClass, (constructor) -> constructor.getParameterCount() == 8).getParameterTypes()[0];
Expand All @@ -86,13 +85,24 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
}
});

// ActionUser
var actionUser = Unobfuscator.loadActionUser(loader);
XposedBridge.hookAllConstructors(actionUser, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
mActionUser = param.thisObject;
}
});

// CachedMessageStore
var cachedMessageStore = Unobfuscator.loadCachedMessageStore(loader);
XposedBridge.hookAllConstructors(cachedMessageStore, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
mCachedMessageStore = param.thisObject;
}
});

// Load wa database
loadWADatabase();
initBridge(Utils.getApplication());
Expand Down Expand Up @@ -135,7 +145,6 @@ private static boolean tryConnectBridge(BaseClient baseClient) throws Exception
CompletableFuture<Boolean> canLoadFuture = baseClient.connect();
Boolean canLoad = canLoadFuture.get();
if (!canLoad) throw new Exception();
isBridgeInitialized = true;
} catch (Exception e) {
return false;
}
Expand Down Expand Up @@ -258,6 +267,17 @@ public static String getWppContactName(Object userJid) {
return name == null ? "" : name;
}

public static Object getFMessageFromKey(Object messageKey) {
if (messageKey == null) return null;
try {
var methodResult = ReflectionUtils.findMethodUsingFilter(mCachedMessageStore.getClass(), (method) -> method.getParameterCount() == 1 && FMessageWpp.Key.TYPE.isAssignableFrom(method.getParameterTypes()[0]));
return ReflectionUtils.callMethod(methodResult, mCachedMessageStore, messageKey);
} catch (Exception e) {
XposedBridge.log(e);
return null;
}
}


public static Object createUserJid(String rawjid) {
var genInstance = XposedHelpers.newInstance(mGenJidClass);
Expand Down Expand Up @@ -289,7 +309,12 @@ public static String getCurrentRawJID() {

public static String stripJID(String str) {
try {
return (str.contains("@g.us") || str.contains("@s.whatsapp.net") || str.contains("@broadcast")) ? str.substring(0, str.indexOf("@")) : str;
if (str.contains(".") && str.contains("@") && str.indexOf(".") < str.indexOf("@")) {
return str.substring(0, str.indexOf("."));
} else if (str.contains("@g.us") || str.contains("@s.whatsapp.net") || str.contains("@broadcast")) {
return str.substring(0, str.indexOf("@"));
}
return str;
} catch (Exception e) {
XposedBridge.log(e.getMessage());
return str;
Expand Down Expand Up @@ -347,6 +372,12 @@ 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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static void init(ClassLoader classLoader) throws Exception {
var userJidClass = classLoader.loadClass("com.whatsapp.jid.UserJid");
userJidMethod = ReflectionUtils.findMethodUsingFilter(TYPE, method -> method.getParameterCount() == 0 && method.getReturnType() == userJidClass);
keyMessage = Unobfuscator.loadMessageKeyField(classLoader);
Key.TYPE = keyMessage.getType();
messageMethod = Unobfuscator.loadNewMessageMethod(classLoader);
messageWithMediaMethod = Unobfuscator.loadNewMessageWithMediaMethod(classLoader);
getFieldIdMessage = Unobfuscator.loadSetEditMessageField(classLoader);
Expand Down Expand Up @@ -120,6 +121,7 @@ public int getMediaType() {
}

public static class Key {
public static Class<?> TYPE;

public final Object thisObject;
public final String messageID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,36 @@ public String getCurrentMessageByKey(String message_key) {
return "";
}

public long getIdfromKey(String message_key) {
if (sqLiteDatabase == null) return -1;
String[] columns = new String[]{"_id"};
String selection = "key_id=?";
String[] selectionArgs = new String[]{message_key};
try (Cursor cursor = sqLiteDatabase.query("message", columns, selection, selectionArgs, null, null, null)) {
if (cursor.moveToFirst()) {
return cursor.getLong(0);
}
} catch (Exception e) {
XposedBridge.log(e);
}
return -1;
}

public String getMediaFromID(long id) {
if (sqLiteDatabase == null) return null;
String[] columns = new String[]{"file_path"};
String selection = "message_row_id=?";
String[] selectionArgs = new String[]{String.valueOf(id)};
try (Cursor cursor = sqLiteDatabase.query("message_media", columns, selection, selectionArgs, null, null, null)) {
if (cursor.moveToFirst()) {
return cursor.getString(0);
}
} catch (Exception e) {
XposedBridge.log(e);
}
return null;
}

public String getCurrentMessageByID(long row_id) {
if (sqLiteDatabase == null) return "";
String[] columns = new String[]{"text_data"};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
Expand Down Expand Up @@ -53,6 +54,7 @@

public class Unobfuscator {

private static final String TAG = "Unobfuscator";
private static DexKitBridge dexkit;

public static final HashMap<String, Object> cache = new HashMap<>();
Expand Down Expand Up @@ -535,10 +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);
if (field == null) throw new Exception("StatusDownloadFile field not found");
return field;
for (Field clazzField : clazz.getFields()) {
var clazz2 = clazzField.getType();
var field = ReflectionUtils.getFieldByType(clazz2, File.class);
if (field != null) return field;
}

throw new Exception("StatusDownloadFile field not found");
});
}

Expand Down Expand Up @@ -603,6 +608,12 @@ public synchronized static Method loadViewOnceStoreMethod(ClassLoader loader) th
return method;
}

public synchronized static Method loadViewOnceChangeMethod(ClassLoader loader) throws Exception {
var method = findFirstMethodUsingStrings(loader, StringMatchType.Contains, "com.whatsapp.messaging.ViewOnceViewerActivity");
if (method == null) throw new Exception("ViewOnce class not found");
return method;
}


/**
* @noinspection SimplifyOptionalCallChains
Expand Down Expand Up @@ -869,7 +880,8 @@ public synchronized static Method loadOnChangeStatus(ClassLoader loader) throws
// for 19.xx, the current implementation returns wrong method
if (method.getParameterCount() < 6) {
ClassData declaringClassData = dexkit.getClassData(method.getDeclaringClass());
if (declaringClassData == null) throw new Exception("OnChangeStatus method not found");
if (declaringClassData == null)
throw new Exception("OnChangeStatus method not found");

Class<?> arg1Class = findFirstClassUsingStrings(loader, StringMatchType.Contains, "problematic contact:");
MethodDataList methodData = declaringClassData.findMethod(
Expand Down Expand Up @@ -1070,9 +1082,15 @@ 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) {
// 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);
}
}
throw new RuntimeException("GetEditMessage method not found");
});
Expand Down Expand Up @@ -1703,34 +1721,61 @@ public synchronized static Method loadBubbleDrawableMethod(ClassLoader classLoad
});
}

public static Method[] loadRootDetector(ClassLoader classLoader) {
public static synchronized Method[] loadRootDetector(ClassLoader classLoader) {
var methods = findAllMethodUsingStrings(classLoader, StringMatchType.Contains, "/system/bin/su");
if (methods.length == 0) throw new RuntimeException("RootDetector method not found");
return methods;
}

public static Method loadCheckEmulator(ClassLoader classLoader) throws Exception {
public static synchronized Method loadCheckEmulator(ClassLoader classLoader) throws Exception {
var method = findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, "Android SDK built for x86");
if (method == null) throw new RuntimeException("CheckEmulator method not found");
return method;
}

public static Method loadCheckCustomRom(ClassLoader classLoader) throws Exception {
public static synchronized Method loadCheckCustomRom(ClassLoader classLoader) throws Exception {
var method = findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, "cyanogen");
if (method == null) throw new RuntimeException("CheckCustomRom method not found");
return method;
}

public static Class loadGetContactInfoClass(ClassLoader classLoader) throws Exception {
public static synchronized Class loadGetContactInfoClass(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(classLoader, () -> findFirstClassUsingStrings(classLoader, StringMatchType.Contains, "unknown@unknown"));

}

public static Method loadTranscribeMethod(ClassLoader classLoader) throws Exception {
public static synchronized Method loadTranscribeMethod(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, "transcribe: starting transcription"));
}

public static Method loadCheckSupportLanguage(ClassLoader classLoader) throws Exception {
public static synchronized Method loadCheckSupportLanguage(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> findFirstMethodUsingStrings(classLoader, StringMatchType.Equals, "Unsupported language"));
}

public static synchronized Class loadUnkTranscript(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(classLoader, () -> {
var loadTranscribe = loadTranscribeMethod(classLoader);
var callbackClass = loadTranscribe.getParameterTypes()[1];
var onComplete = ReflectionUtils.findMethodUsingFilter(callbackClass, method -> method.getParameterCount() == 4);
var resultTypeClass = onComplete.getParameterTypes()[0].getName();
Log.i(TAG, resultTypeClass);
var classDataList = dexkit.findClass(FindClass.create().matcher(ClassMatcher.create().addUsingString("Unknown").superClass(resultTypeClass)));
if (classDataList.isEmpty())
throw new RuntimeException("UnkTranscript class not found");
return classDataList.get(0).getInstance(classLoader);
});
}

public static synchronized Method loadStateChangeMethod(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, "presencestatemanager/startTransitionToUnavailable/new-state"));
}

public static synchronized Class loadCachedMessageStore(ClassLoader loader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(loader, () -> {
var cacheMsClass = findFirstClassUsingStrings(loader, StringMatchType.Contains, "CachedMessageStore/getMessage/key");
if (cacheMsClass == null)
throw new RuntimeException("CachedMessageStore class not found");
return cacheMsClass;
});
}
}
Loading

0 comments on commit 4e5afec

Please sign in to comment.