Skip to content

Commit

Permalink
fix: get friend list handle on TIM 4.0.95.4001
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Oct 31, 2024
1 parent 484bf39 commit 678be6f
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 39 deletions.
53 changes: 53 additions & 0 deletions app/src/main/java/cc/ioctl/hook/misc/ShadowInitDependencyStub.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* QAuxiliary - An Xposed module for QQ/TIM
* Copyright (C) 2019-2024 QAuxiliary developers
* https://github.com/cinit/QAuxiliary
*
* This software is an opensource software: you can redistribute it
* and/or modify it under the terms of the General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version as published
* by QAuxiliary contributors.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the General Public License for more details.
*
* You should have received a copy of the General Public License
* along with this software.
* If not, see
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
*/

package cc.ioctl.hook.misc

import io.github.qauxv.base.annotation.FunctionHookEntry
import io.github.qauxv.hook.BasePersistBackgroundHook
import io.github.qauxv.step.DexDeobfStep
import io.github.qauxv.step.Step
import io.github.qauxv.util.dexkit.DexKit
import io.github.qauxv.util.dexkit.DexKitTarget
import io.github.qauxv.util.dexkit.NContactUtils_getBuddyName

@FunctionHookEntry
object ShadowInitDependencyStub : BasePersistBackgroundHook() {

private val mDexDeobfIndexes: Array<DexKitTarget> = arrayOf(
NContactUtils_getBuddyName
)

override fun initOnce(): Boolean {
return true
}

override val isPreparationRequired: Boolean
get() {
return mDexDeobfIndexes.any {
DexKit.isRunDexDeobfuscationRequired(it)
}
}

override fun makePreparationSteps(): Array<Step> = mDexDeobfIndexes.map { DexDeobfStep(it) }.toTypedArray()

}
2 changes: 1 addition & 1 deletion app/src/main/java/io/github/qauxv/bridge/ContactUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public static String getBuddyName(@NonNull AppRuntime app, @NonNull String uin)
Objects.requireNonNull(uin, "uin is null");
Method getBuddyName = DexKit.loadMethodFromCache(NContactUtils_getBuddyName.INSTANCE);
if (getBuddyName == null) {
Log.e("getBuddyName but N_ContactUtils_getBuddyName not found");
Log.w("getBuddyName but N_ContactUtils_getBuddyName not found");
return null;
}
try {
Expand Down
75 changes: 37 additions & 38 deletions app/src/main/java/io/github/qauxv/bridge/ManagerHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
package io.github.qauxv.bridge;

import static io.github.qauxv.util.Initiator.load;
import static io.github.qauxv.util.Initiator.loadClass;

import cc.ioctl.util.HostInfo;
import cc.ioctl.util.Reflex;
import io.github.qauxv.util.Initiator;
import io.github.qauxv.util.IoUtils;
import io.github.qauxv.util.Log;
import io.github.qauxv.util.QQVersion;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import mqq.app.AppRuntime;

public class ManagerHelper {
Expand Down Expand Up @@ -70,47 +72,44 @@ public static Object getManager(int index) throws ReflectiveOperationException {
}

public static Object getFriendListHandler() {
if (HostInfo.requireMinQQVersion(QQVersion.QQ_8_5_0)) {
try {
Class cl_bh = load("com/tencent/mobileqq/app/BusinessHandler");
Class cl_flh = load("com/tencent/mobileqq/app/FriendListHandler");
if (cl_bh == null) {
assert cl_flh != null;
cl_bh = cl_flh.getSuperclass();
}
Object appInterface = AppRuntimeHelper.getQQAppInterface();
return Reflex.invokeVirtual(appInterface, "getBusinessHandler", cl_flh.getName(),
String.class, cl_bh);
} catch (Exception e) {
Log.e(e);
return null;
try {
Object appInterface = AppRuntimeHelper.getQQAppInterface();
// BusinessHandler is likely to be obfuscated
Class<?> kBusinessHandler = load("com/tencent/mobileqq/app/BusinessHandler");
if (kBusinessHandler == null) {
// QQ lite 3.5.0, has obfuscated FriendListHandler, other versions look good
kBusinessHandler = loadClass("com/tencent/mobileqq/app/FriendListHandler").getSuperclass();
}
} else {
try {
Class cl_bh = load("com/tencent/mobileqq/app/BusinessHandler");
if (cl_bh == null) {
Class cl_flh = load("com/tencent/mobileqq/app/FriendListHandler");
assert cl_flh != null;
cl_bh = cl_flh.getSuperclass();
Method getBusinessHandler = null;
for (Method m : Initiator._QQAppInterface().getMethods()) {
// public, non-static
if (!Modifier.isPublic(m.getModifiers()) || Modifier.isStatic(m.getModifiers())) {
continue;
}
// For 8.5.0+, getBusinessHandler use string as parameter
if (m.getName().equals("getBusinessHandler")) {
getBusinessHandler = m;
break;
}
Object appInterface = AppRuntimeHelper.getQQAppInterface();
try {
return Reflex.invokeVirtual(appInterface, "a", 1, int.class, cl_bh);
} catch (NoSuchMethodException e) {
try {
Method m = appInterface.getClass()
.getMethod("getBusinessHandler", int.class);
m.setAccessible(true);
return m.invoke(appInterface, 1);
} catch (Exception e2) {
e.addSuppressed(e2);
if (m.getReturnType() == kBusinessHandler && "a".equals(m.getName())) {
Class<?>[] params = m.getParameterTypes();
if (params.length == 1 && (params[0] == int.class || params[0] == String.class)) {
getBusinessHandler = m;
break;
}
throw e;
}
} catch (Exception e) {
Log.e(e);
return null;
}
if (getBusinessHandler == null) {
throw new NoSuchMethodException("QQAppInterface.getBusinessHandler");
}
Class<?> type = getBusinessHandler.getParameterTypes()[0];
if (type == String.class) {
return getBusinessHandler.invoke(appInterface, loadClass("com/tencent/mobileqq/app/FriendListHandler").getName());
} else {
return getBusinessHandler.invoke(appInterface, 1);
}
} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
throw IoUtils.unsafeThrowForIteCause(e);
}
}

Expand Down

0 comments on commit 678be6f

Please sign in to comment.