From 4b5932b3193d462b2367691dbb4088a6e3f8b06c Mon Sep 17 00:00:00 2001 From: whitechi73 Date: Tue, 23 Jan 2024 00:26:11 +0800 Subject: [PATCH] `Shamrock`: fix #190 --- .../kernel/nativeinterface/DeviceType.java | 36 +++++-- .../nativeinterface/InitSessionConfig.java | 100 ++++++++++++++++++ .../InitSessionDesktopPathConfig.java | 5 + .../InitSessionMobilePathConfig.java | 17 +++ .../kernel/nativeinterface/PlatformType.java | 35 ++++++ .../nativeinterface/RDeliveryConfig.java | 19 ++++ .../remote/service/WebSocketClientService.kt | 1 - .../service/api/WebSocketClientServlet.kt | 8 +- .../service/listener/PrimitiveListener.kt | 67 ++++++------ .../shamrock/xposed/actions/ForceTablet.kt | 41 +++++-- 10 files changed, 280 insertions(+), 49 deletions(-) create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionConfig.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionDesktopPathConfig.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionMobilePathConfig.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PlatformType.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/RDeliveryConfig.java diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/DeviceType.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/DeviceType.java index c66b119..58b0faf 100644 --- a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/DeviceType.java +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/DeviceType.java @@ -1,10 +1,32 @@ package com.tencent.qqnt.kernel.nativeinterface; -/* compiled from: P */ -/* loaded from: classes4.dex */ -public enum DeviceType { - KUNKNOWN, - KPHONE, - KPAD, - KCOMPUTER +public final class DeviceType { + private static final DeviceType[] $VALUES; + public static final DeviceType KCOMPUTER; + public static final DeviceType KPAD; + public static final DeviceType KPHONE; + public static final DeviceType KUNKNOWN; + + static { + DeviceType deviceType = new DeviceType("KUNKNOWN", 0); + KUNKNOWN = deviceType; + DeviceType deviceType2 = new DeviceType("KPHONE", 1); + KPHONE = deviceType2; + DeviceType deviceType3 = new DeviceType("KPAD", 2); + KPAD = deviceType3; + DeviceType deviceType4 = new DeviceType("KCOMPUTER", 3); + KCOMPUTER = deviceType4; + $VALUES = new DeviceType[]{deviceType, deviceType2, deviceType3, deviceType4}; + } + + DeviceType(String str, int i2) { + } + + public static DeviceType valueOf(String str) { + return null; + } + + public static DeviceType[] values() { + return (DeviceType[]) $VALUES.clone(); + } } diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionConfig.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionConfig.java new file mode 100644 index 0000000..f92617b --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionConfig.java @@ -0,0 +1,100 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +public class InitSessionConfig { + + String a2; + String appid; + String clientVer; + String d2; + String d2Key; + String defaultFileDownloadPath; + InitSessionDesktopPathConfig desktopPathConfig; + DeviceType deviceType; + String extDataPath; + String gproDBName; + String machineId; + InitSessionMobilePathConfig mobilePathConfig; + String platVer; + PlatformType platform; + RDeliveryConfig rdeliveryConfig; + String selfUid; + long selfUin; + String sysPath; + String userPath; + + public String getA2() { + return null; + } + + public String getAppid() { + return null; + } + + public String getClientVer() { + return null; + } + + public String getD2() { + return null; + } + + public String getD2Key() { + return null; + } + + public String getDefaultFileDownloadPath() { + return null; + } + + public InitSessionDesktopPathConfig getDesktopPathConfig() { + return null; + } + + public DeviceType getDeviceType() { + return null; + } + + public String getExtDataPath() { + return null; + } + + public String getGproDBName() { + return null; + } + + public String getMachineId() { + return null; + } + + public InitSessionMobilePathConfig getMobilePathConfig() { + return null; + } + + public String getPlatVer() { + return null; + } + + public PlatformType getPlatform() { + return null; + } + + public RDeliveryConfig getRdeliveryConfig() { + return null; + } + + public String getSelfUid() { + return null; + } + + public long getSelfUin() { + return 0; + } + + public String getSysPath() { + return null; + } + + public String getUserPath() { + return null; + } +} diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionDesktopPathConfig.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionDesktopPathConfig.java new file mode 100644 index 0000000..e8bdee0 --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionDesktopPathConfig.java @@ -0,0 +1,5 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +public class InitSessionDesktopPathConfig { + String accountPath; +} diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionMobilePathConfig.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionMobilePathConfig.java new file mode 100644 index 0000000..89d928c --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/InitSessionMobilePathConfig.java @@ -0,0 +1,17 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +public final class InitSessionMobilePathConfig { + String mobileQqFilePath; + String mobileQqMarketPath; + String mobileQqPicPath; + String mobileQqPttPath; + String mobileQqVideoPath; + + public InitSessionMobilePathConfig() { + this.mobileQqPicPath = ""; + this.mobileQqVideoPath = ""; + this.mobileQqPttPath = ""; + this.mobileQqFilePath = ""; + this.mobileQqMarketPath = ""; + } +} diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PlatformType.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PlatformType.java new file mode 100644 index 0000000..aa6e00e --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PlatformType.java @@ -0,0 +1,35 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +public final class PlatformType { + private static final /* synthetic */ PlatformType[] $VALUES; + public static final PlatformType KANDROID; + public static final PlatformType KIOS; + public static final PlatformType KMAC; + public static final PlatformType KUNKNOWN; + public static final PlatformType KWINDOWS; + + static { + PlatformType platformType = new PlatformType("KUNKNOWN", 0); + KUNKNOWN = platformType; + PlatformType platformType2 = new PlatformType("KANDROID", 1); + KANDROID = platformType2; + PlatformType platformType3 = new PlatformType("KIOS", 2); + KIOS = platformType3; + PlatformType platformType4 = new PlatformType("KWINDOWS", 3); + KWINDOWS = platformType4; + PlatformType platformType5 = new PlatformType("KMAC", 4); + KMAC = platformType5; + $VALUES = new PlatformType[]{platformType, platformType2, platformType3, platformType4, platformType5}; + } + + PlatformType(String str, int i2) { + } + + public static PlatformType valueOf(String str) { + return null; + } + + public static PlatformType[] values() { + return (PlatformType[]) $VALUES.clone(); + } +} diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/RDeliveryConfig.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/RDeliveryConfig.java new file mode 100644 index 0000000..02c7f0f --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/RDeliveryConfig.java @@ -0,0 +1,19 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +import java.util.ArrayList; + +public final class RDeliveryConfig implements IKernelModel { + String appId; + String appKey; + String appVersion; + String bundleId; + ArrayList fixedAfterHitKeys; + String language; + String logicEnvironment; + String osVersion; + int platform; + String sdkVersion; + String serverUrl; + int systemId; + String userId; +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt index a128ea9..52d970f 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt @@ -20,7 +20,6 @@ internal class WebSocketClientService( init { startHeartbeatTimer() - initTransmitter() } override fun submitFlowJob(job: Job) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt index 916d47c..1f82cea 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt @@ -45,6 +45,7 @@ internal abstract class WebSocketClientServlet( } } + private var firstOpen = true private val sendLock = Mutex() override fun allowTransmit(): Boolean { @@ -89,7 +90,12 @@ internal abstract class WebSocketClientServlet( //startHeartbeatTimer() pushMetaLifecycle() - //initTransmitter() + if (firstOpen) { + firstOpen = false + } else { + cancelFlowJobs() + } + initTransmitter() } override fun onClose(code: Int, reason: String?, remote: Boolean) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt index 33e1972..631a18a 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt @@ -498,43 +498,42 @@ internal object PrimitiveListener { } private suspend fun onGroupRecall(time: Long, pb: ProtoMap) { - var detail = pb[1, 3, 2] - if (detail !is ProtoMap) { - try { - val readPacket = ByteReadPacket(detail.asByteArray) - readPacket.discardExact(4) - readPacket.discardExact(1) - detail = ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt())) - readPacket.release() - } catch (e: Exception) { - LogCenter.log("onGroupRecall error: ${e.stackTraceToString()}", Level.WARN) - } - } - var groupCode:Long + var detail = pb[1, 3, 2] + if (detail !is ProtoMap) { try { - groupCode = detail[4].asULong - }catch (e: ClassCastException){ - groupCode = detail[4].asList.value[0].asULong + val readPacket = ByteReadPacket(detail.asByteArray) + readPacket.discardExact(4) + readPacket.discardExact(1) + detail = ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt())) + readPacket.release() + } catch (e: Exception) { + LogCenter.log("onGroupRecall error: ${e.stackTraceToString()}", Level.WARN) } - val operatorUid = detail[11, 1].asUtf8String - val targetUid = detail[11, 3, 6].asUtf8String - val msgSeq = detail[11, 3, 1].asLong - val tipText = if (detail.has(11, 9)) detail[11, 9, 2].asUtf8String else "" - val mapping = MessageHelper.getMsgMappingBySeq(MsgConstant.KCHATTYPEGROUP, msgSeq.toInt()) - if (mapping == null) { - LogCenter.log("由于缺失消息映射关系(seq = $msgSeq),消息撤回事件无法推送!", Level.WARN) - return - } - val msgHash = mapping.msgHashId - val operator = ContactHelper.getUinByUidAsync(operatorUid).toLong() - val target = ContactHelper.getUinByUidAsync(targetUid).toLong() - LogCenter.log("群消息撤回($groupCode): $operator -> $target, seq = $msgSeq, hash = $msgHash, tip = $tipText") + } + val groupCode:Long = try { + detail[4].asULong + }catch (e: ClassCastException){ + detail[4].asList.value[0].asULong + } + val operatorUid = detail[11, 1].asUtf8String + val targetUid = detail[11, 3, 6].asUtf8String + val msgSeq = detail[11, 3, 1].asLong + val tipText = if (detail.has(11, 9)) detail[11, 9, 2].asUtf8String else "" + val mapping = MessageHelper.getMsgMappingBySeq(MsgConstant.KCHATTYPEGROUP, msgSeq.toInt()) + if (mapping == null) { + LogCenter.log("由于缺失消息映射关系(seq = $msgSeq),消息撤回事件无法推送!", Level.WARN) + return + } + val msgHash = mapping.msgHashId + val operator = ContactHelper.getUinByUidAsync(operatorUid).toLong() + val target = ContactHelper.getUinByUidAsync(targetUid).toLong() + LogCenter.log("群消息撤回($groupCode): $operator -> $target, seq = $msgSeq, hash = $msgHash, tip = $tipText") - if (!GlobalEventTransmitter.GroupNoticeTransmitter - .transGroupMsgRecall(time, operator, target, groupCode, msgHash, tipText) - ) { - LogCenter.log("群消息撤回推送失败!", Level.WARN) - } + if (!GlobalEventTransmitter.GroupNoticeTransmitter + .transGroupMsgRecall(time, operator, target, groupCode, msgHash, tipText) + ) { + LogCenter.log("群消息撤回推送失败!", Level.WARN) + } } private suspend fun onGroupApply(time: Long, pb: ProtoMap) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/ForceTablet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/ForceTablet.kt index 99bd4d7..c1716bc 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/ForceTablet.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/ForceTablet.kt @@ -1,22 +1,32 @@ +@file:Suppress("UNUSED_VARIABLE", "LocalVariableName") package moe.fuqiuluo.shamrock.xposed.actions import android.content.Context import com.tencent.common.config.pad.DeviceType +import com.tencent.qqnt.kernel.nativeinterface.InitSessionConfig +import com.tencent.qqnt.kernel.nativeinterface.PlatformType import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedBridge import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig import moe.fuqiuluo.shamrock.tools.FuzzySearchClass import moe.fuqiuluo.shamrock.utils.PlatformUtils import moe.fuqiuluo.shamrock.helper.LogCenter +import moe.fuqiuluo.shamrock.tools.afterHook +import moe.fuqiuluo.shamrock.tools.hookMethod import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader internal class ForceTablet: IAction { override fun invoke(ctx: Context) { - if (!PlatformUtils.isMqqPackage()) return + //if (!PlatformUtils.isMqqPackage()) return if (ShamrockConfig.forceTablet()) { if (PlatformUtils.isMainProcess()) { LogCenter.log("强制协议类型 (PAD)", toast = true) } + + val returnTablet = afterHook { + it.result = DeviceType.TABLET + } + FuzzySearchClass.findAllClassByMethod( LuoClassloader.hostClassLoader, "com.tencent.common.config.pad" ) { _, method -> @@ -24,13 +34,32 @@ internal class ForceTablet: IAction { }.forEach { clazz -> //log("Inject to tablet mode in ${clazz.name}") val method = clazz.declaredMethods.first { it.returnType == DeviceType::class.java } - XposedBridge.hookMethod(method, object: XC_MethodHook() { - override fun afterHookedMethod(param: MethodHookParam) { - //log("Original deviceMode = ${param.result}, but change to TABLET.") - param.result = DeviceType.TABLET - } + XposedBridge.hookMethod(method, returnTablet) + } + + val PadUtil = LuoClassloader.load("com.tencent.common.config.pad.PadUtil") + PadUtil?.declaredMethods?.filter { + it.returnType == DeviceType::class.java + }?.forEach { + XposedBridge.hookMethod(it, returnTablet) + } + + val deviceTypeField = InitSessionConfig::class.java.declaredFields.firstOrNull { + it.type == com.tencent.qqnt.kernel.nativeinterface.DeviceType::class.java + } + if (deviceTypeField != null) { + XposedBridge.hookAllConstructors(InitSessionConfig::class.java, afterHook { + if (!deviceTypeField.isAccessible) deviceTypeField.isAccessible = true + deviceTypeField.set(it.thisObject, com.tencent.qqnt.kernel.nativeinterface.DeviceType.KPAD) }) } + InitSessionConfig::class.java.hookMethod("getDeviceType").after { + it.result = com.tencent.qqnt.kernel.nativeinterface.DeviceType.KPAD + } + + //InitSessionConfig::class.java.hookMethod("getPlatform").after { + // it.result = PlatformType.KMAC + //} } } } \ No newline at end of file