Shamrock: fix #190

This commit is contained in:
whitechi73 2024-01-23 00:26:11 +08:00
parent 48b720bdd7
commit 4b5932b319
10 changed files with 280 additions and 49 deletions

View File

@ -1,10 +1,32 @@
package com.tencent.qqnt.kernel.nativeinterface; package com.tencent.qqnt.kernel.nativeinterface;
/* compiled from: P */ public final class DeviceType {
/* loaded from: classes4.dex */ private static final DeviceType[] $VALUES;
public enum DeviceType { public static final DeviceType KCOMPUTER;
KUNKNOWN, public static final DeviceType KPAD;
KPHONE, public static final DeviceType KPHONE;
KPAD, public static final DeviceType KUNKNOWN;
KCOMPUTER
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();
}
} }

View File

@ -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;
}
}

View File

@ -0,0 +1,5 @@
package com.tencent.qqnt.kernel.nativeinterface;
public class InitSessionDesktopPathConfig {
String accountPath;
}

View File

@ -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 = "";
}
}

View File

@ -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();
}
}

View File

@ -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<String> fixedAfterHitKeys;
String language;
String logicEnvironment;
String osVersion;
int platform;
String sdkVersion;
String serverUrl;
int systemId;
String userId;
}

View File

@ -20,7 +20,6 @@ internal class WebSocketClientService(
init { init {
startHeartbeatTimer() startHeartbeatTimer()
initTransmitter()
} }
override fun submitFlowJob(job: Job) { override fun submitFlowJob(job: Job) {

View File

@ -45,6 +45,7 @@ internal abstract class WebSocketClientServlet(
} }
} }
private var firstOpen = true
private val sendLock = Mutex() private val sendLock = Mutex()
override fun allowTransmit(): Boolean { override fun allowTransmit(): Boolean {
@ -89,7 +90,12 @@ internal abstract class WebSocketClientServlet(
//startHeartbeatTimer() //startHeartbeatTimer()
pushMetaLifecycle() pushMetaLifecycle()
//initTransmitter() if (firstOpen) {
firstOpen = false
} else {
cancelFlowJobs()
}
initTransmitter()
} }
override fun onClose(code: Int, reason: String?, remote: Boolean) { override fun onClose(code: Int, reason: String?, remote: Boolean) {

View File

@ -498,43 +498,42 @@ internal object PrimitiveListener {
} }
private suspend fun onGroupRecall(time: Long, pb: ProtoMap) { private suspend fun onGroupRecall(time: Long, pb: ProtoMap) {
var detail = pb[1, 3, 2] var detail = pb[1, 3, 2]
if (detail !is ProtoMap) { 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
try { try {
groupCode = detail[4].asULong val readPacket = ByteReadPacket(detail.asByteArray)
}catch (e: ClassCastException){ readPacket.discardExact(4)
groupCode = detail[4].asList.value[0].asULong 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 groupCode:Long = try {
val msgSeq = detail[11, 3, 1].asLong detail[4].asULong
val tipText = if (detail.has(11, 9)) detail[11, 9, 2].asUtf8String else "" }catch (e: ClassCastException){
val mapping = MessageHelper.getMsgMappingBySeq(MsgConstant.KCHATTYPEGROUP, msgSeq.toInt()) detail[4].asList.value[0].asULong
if (mapping == null) { }
LogCenter.log("由于缺失消息映射关系(seq = $msgSeq),消息撤回事件无法推送!", Level.WARN) val operatorUid = detail[11, 1].asUtf8String
return val targetUid = detail[11, 3, 6].asUtf8String
} val msgSeq = detail[11, 3, 1].asLong
val msgHash = mapping.msgHashId val tipText = if (detail.has(11, 9)) detail[11, 9, 2].asUtf8String else ""
val operator = ContactHelper.getUinByUidAsync(operatorUid).toLong() val mapping = MessageHelper.getMsgMappingBySeq(MsgConstant.KCHATTYPEGROUP, msgSeq.toInt())
val target = ContactHelper.getUinByUidAsync(targetUid).toLong() if (mapping == null) {
LogCenter.log("群消息撤回($groupCode): $operator -> $target, seq = $msgSeq, hash = $msgHash, tip = $tipText") 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 if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMsgRecall(time, operator, target, groupCode, msgHash, tipText) .transGroupMsgRecall(time, operator, target, groupCode, msgHash, tipText)
) { ) {
LogCenter.log("群消息撤回推送失败!", Level.WARN) LogCenter.log("群消息撤回推送失败!", Level.WARN)
} }
} }
private suspend fun onGroupApply(time: Long, pb: ProtoMap) { private suspend fun onGroupApply(time: Long, pb: ProtoMap) {

View File

@ -1,22 +1,32 @@
@file:Suppress("UNUSED_VARIABLE", "LocalVariableName")
package moe.fuqiuluo.shamrock.xposed.actions package moe.fuqiuluo.shamrock.xposed.actions
import android.content.Context import android.content.Context
import com.tencent.common.config.pad.DeviceType 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.XC_MethodHook
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.tools.FuzzySearchClass import moe.fuqiuluo.shamrock.tools.FuzzySearchClass
import moe.fuqiuluo.shamrock.utils.PlatformUtils import moe.fuqiuluo.shamrock.utils.PlatformUtils
import moe.fuqiuluo.shamrock.helper.LogCenter 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 import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
internal class ForceTablet: IAction { internal class ForceTablet: IAction {
override fun invoke(ctx: Context) { override fun invoke(ctx: Context) {
if (!PlatformUtils.isMqqPackage()) return //if (!PlatformUtils.isMqqPackage()) return
if (ShamrockConfig.forceTablet()) { if (ShamrockConfig.forceTablet()) {
if (PlatformUtils.isMainProcess()) { if (PlatformUtils.isMainProcess()) {
LogCenter.log("强制协议类型 (PAD)", toast = true) LogCenter.log("强制协议类型 (PAD)", toast = true)
} }
val returnTablet = afterHook {
it.result = DeviceType.TABLET
}
FuzzySearchClass.findAllClassByMethod( FuzzySearchClass.findAllClassByMethod(
LuoClassloader.hostClassLoader, "com.tencent.common.config.pad" LuoClassloader.hostClassLoader, "com.tencent.common.config.pad"
) { _, method -> ) { _, method ->
@ -24,13 +34,32 @@ internal class ForceTablet: IAction {
}.forEach { clazz -> }.forEach { clazz ->
//log("Inject to tablet mode in ${clazz.name}") //log("Inject to tablet mode in ${clazz.name}")
val method = clazz.declaredMethods.first { it.returnType == DeviceType::class.java } val method = clazz.declaredMethods.first { it.returnType == DeviceType::class.java }
XposedBridge.hookMethod(method, object: XC_MethodHook() { XposedBridge.hookMethod(method, returnTablet)
override fun afterHookedMethod(param: MethodHookParam) { }
//log("Original deviceMode = ${param.result}, but change to TABLET.")
param.result = DeviceType.TABLET 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
//}
} }
} }
} }