From 638bf72392e4b997ab13281b741a4021ba24ed04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E6=B1=A0?= Date: Sun, 10 Mar 2024 07:44:02 +0800 Subject: [PATCH] =?UTF-8?q?`Shamrock`:=20=E4=BF=AE=E5=A4=8D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E4=B8=8B=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 白池 --- .../src/main/java/kritor/service/Grpc.kt | 7 +++ kritor | 2 +- xposed/src/main/assets/config.properties | 43 ++++++++++++++++ .../main/java/kritor/server/KritorServer.kt | 14 +++++- .../java/kritor/service/Authentication.kt | 49 +++++++++++++++++++ .../fuqiuluo/shamrock/config/ActiveTicket.kt | 7 +++ .../shamrock/config/ShamrockConfig.kt | 42 ++++++++++++++-- .../xposed/actions/InitRemoteService.kt | 11 +++-- .../shamrock/xposed/loader/NativeLoader.kt | 2 - .../java/qq/service/internals/MSFHandler.kt | 13 +++-- 10 files changed, 175 insertions(+), 15 deletions(-) create mode 100644 annotations/src/main/java/kritor/service/Grpc.kt create mode 100644 xposed/src/main/assets/config.properties create mode 100644 xposed/src/main/java/kritor/service/Authentication.kt create mode 100644 xposed/src/main/java/moe/fuqiuluo/shamrock/config/ActiveTicket.kt diff --git a/annotations/src/main/java/kritor/service/Grpc.kt b/annotations/src/main/java/kritor/service/Grpc.kt new file mode 100644 index 0000000..0a66477 --- /dev/null +++ b/annotations/src/main/java/kritor/service/Grpc.kt @@ -0,0 +1,7 @@ +package kritor.service + +@Target(AnnotationTarget.FUNCTION) +annotation class Grpc( + val serviceName: String, + val funcName: String +) \ No newline at end of file diff --git a/kritor b/kritor index 0dd59dd..f4fa157 160000 --- a/kritor +++ b/kritor @@ -1 +1 @@ -Subproject commit 0dd59dd2d43324ba13f14e2b8ebc5df07ed9821d +Subproject commit f4fa15754e266182b5f2c08c54c88c21c61eb065 diff --git a/xposed/src/main/assets/config.properties b/xposed/src/main/assets/config.properties new file mode 100644 index 0000000..6505ef1 --- /dev/null +++ b/xposed/src/main/assets/config.properties @@ -0,0 +1,43 @@ +# Shamrock Config + +# 资源上传群组 +resource_group=883536416 + +# 强制使用平板模式 +force_tablet=false + +# 被动(反向)RPC开关 +passive_rpc=false +# 被动(反向)RPC地址 +rpc_address= +# 第一个被动RPC鉴权token +rpc_address.ticket= +# 如果有多个请使用 +# 我是第二个地址 +#rpc_address.1= +# 第二个被动RPC鉴权token +#rpc_address.1.ticket= + +# 主动(正向)RPC开关 +active_rpc=false +# 主动(正向)RPC端口 +rpc_port=5700 +# 主动RPC鉴权token +active_ticket= +# 多鉴权token支持 +# 第二个主动RPC鉴权token +#active_ticket.1= + +# 自回复开关 +#alive_reply=false +# 自回复消息 +enable_self_message=false + +# 旧BDH兼容开关 +enable_old_bdh=false + +# 反JVM调用栈跟踪 +anti_jvm_trace=true + +# 调试模式 +#debug=false \ No newline at end of file diff --git a/xposed/src/main/java/kritor/server/KritorServer.kt b/xposed/src/main/java/kritor/server/KritorServer.kt index 80c0706..7aab8e0 100644 --- a/xposed/src/main/java/kritor/server/KritorServer.kt +++ b/xposed/src/main/java/kritor/server/KritorServer.kt @@ -1,20 +1,32 @@ +@file:OptIn(ExperimentalCoroutinesApi::class) package kritor.server import io.grpc.ServerBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kritor.service.* import moe.fuqiuluo.shamrock.helper.LogCenter +import kotlin.coroutines.CoroutineContext class KritorServer( private val port: Int -) { +): CoroutineScope { private val server = ServerBuilder .forPort(port) + .addService(Authentication) .build()!! fun start(block: Boolean = false) { LogCenter.log("KritorServer started at port $port.") server.start() + if (block) { server.awaitTermination() } } + + override val coroutineContext: CoroutineContext = + Dispatchers.IO.limitedParallelism(12) } \ No newline at end of file diff --git a/xposed/src/main/java/kritor/service/Authentication.kt b/xposed/src/main/java/kritor/service/Authentication.kt new file mode 100644 index 0000000..a6c7814 --- /dev/null +++ b/xposed/src/main/java/kritor/service/Authentication.kt @@ -0,0 +1,49 @@ +package kritor.service + +import io.kritor.AuthCode +import io.kritor.AuthReq +import io.kritor.AuthRsp +import io.kritor.AuthenticationGrpcKt +import io.kritor.authRsp +import moe.fuqiuluo.shamrock.config.ActiveTicket +import moe.fuqiuluo.shamrock.config.ShamrockConfig +import qq.service.QQInterfaces + +object Authentication: AuthenticationGrpcKt.AuthenticationCoroutineImplBase() { + @Grpc("Authentication", "Auth") + override suspend fun auth(request: AuthReq): AuthRsp { + if (QQInterfaces.app.account != request.account) { + return authRsp { + code = AuthCode.NO_ACCOUNT + msg = "No such account" + } + } + + val activeTicketName = ActiveTicket.name() + var index = 0 + while (true) { + val ticket = ShamrockConfig.getProperty(activeTicketName + if (index == 0) "" else ".$index", null) + if (ticket.isNullOrEmpty()) { + if (index == 0) { + return authRsp { + code = AuthCode.OK + msg = "OK" + } + } else { + break + } + } else if (ticket == request.ticket) { + return authRsp { + code = AuthCode.OK + msg = "OK" + } + } + index++ + } + + return authRsp { + code = AuthCode.NO_TICKET + msg = "Invalid ticket" + } + } +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ActiveTicket.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ActiveTicket.kt new file mode 100644 index 0000000..4354770 --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ActiveTicket.kt @@ -0,0 +1,7 @@ +package moe.fuqiuluo.shamrock.config + +object ActiveTicket: ConfigKey() { + override fun name(): String = "active_ticket" + + override fun default(): String = "" +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ShamrockConfig.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ShamrockConfig.kt index 9ca6dac..730a00d 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ShamrockConfig.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/config/ShamrockConfig.kt @@ -1,6 +1,8 @@ package moe.fuqiuluo.shamrock.config import android.content.Intent +import moe.fuqiuluo.shamrock.helper.LogCenter +import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader.moduleLoader import mqq.app.MobileQQ import java.util.Properties @@ -17,11 +19,22 @@ private val configKeys = setOf( ResourceGroup, RPCAddress, RPCPort, - ) internal object ShamrockConfig: Properties() { init { + if (!configFile.exists()) { + moduleLoader.getResourceAsStream("assets/config.properties")?.use { + configDir.resolve("default.prop").outputStream().use { output -> + it.copyTo(output) + } + } + moduleLoader.getResourceAsStream("assets/config.properties")?.use { + configFile.outputStream().use { output -> + it.copyTo(output) + } + } + } if (configFile.exists()) configFile.inputStream().use { load(it) } @@ -40,13 +53,34 @@ internal object ShamrockConfig: Properties() { fun updateConfig(intent: Intent? = null) { intent?.let { for (key in configKeys) { - val value = intent.getStringExtra(key.name()) - if (value != null) setProperty(key.name(), value) + when (key.default()) { + is String -> { + val value = intent.getStringExtra(key.name()) + if (value != null) setProperty(key.name(), value) + } + is Boolean -> { + val value = intent.getBooleanExtra(key.name(), key.default() as Boolean) + setProperty(key.name(), value.toString()) + } + is Int -> { + val value = intent.getIntExtra(key.name(), key.default() as Int) + setProperty(key.name(), value.toString()) + } + is Long -> { + val value = intent.getLongExtra(key.name(), key.default() as Long) + setProperty(key.name(), value.toString()) + } + } } + + if (getProperty(ActiveTicket.name()).isNullOrEmpty()) { + setProperty(ActiveTicket.name(), "") // 初始化ticket + } + setProperty(IsInit.name(), "true") } configFile.outputStream().use { - store(it, "Shamrock Config ${System.currentTimeMillis()}") + store(it, "Shamrock Config") } } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt index 7677640..6d7773d 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt @@ -4,6 +4,8 @@ package moe.fuqiuluo.shamrock.xposed.actions import android.content.Context import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import kritor.server.KritorServer import moe.fuqiuluo.shamrock.config.ActiveRPC import moe.fuqiuluo.shamrock.config.RPCPort @@ -17,10 +19,11 @@ private lateinit var server: KritorServer @XposedHook(Process.MAIN, priority = 10) internal class InitRemoteService : IAction { override fun invoke(ctx: Context) { - if (ActiveRPC.get() && !::server.isInitialized) { - server = KritorServer(RPCPort.get()) - server.start() + GlobalScope.launch { + if (ActiveRPC.get() && !::server.isInitialized) { + server = KritorServer(RPCPort.get()) + server.start() + } } - } } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt index 35eaf94..a2a9c68 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt @@ -34,8 +34,6 @@ internal object NativeLoader { XposedBridge.log("[Shamrock] 反射检测到 Android x86") true } else false - }.onFailure { - XposedBridge.log("[Shamrock] ${it.stackTraceToString()}") }.getOrElse { false } private fun getLibFilePath(name: String): String { diff --git a/xposed/src/main/java/qq/service/internals/MSFHandler.kt b/xposed/src/main/java/qq/service/internals/MSFHandler.kt index 900ecf6..a00271b 100644 --- a/xposed/src/main/java/qq/service/internals/MSFHandler.kt +++ b/xposed/src/main/java/qq/service/internals/MSFHandler.kt @@ -4,6 +4,8 @@ import com.tencent.qphone.base.remote.FromServiceMsg import com.tencent.qphone.base.remote.ToServiceMsg import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import moe.fuqiuluo.shamrock.helper.Level +import moe.fuqiuluo.shamrock.helper.LogCenter typealias MsfPush = (FromServiceMsg) -> Unit typealias MsfResp = (ToServiceMsg, FromServiceMsg) -> Unit @@ -45,8 +47,13 @@ internal object MSFHandler { } fun onResp(toServiceMsg: ToServiceMsg, fromServiceMsg: FromServiceMsg) { - val cmd = toServiceMsg.getAttribute("respkey") as Int - val resp = mRespHandler[cmd] - resp?.invoke(toServiceMsg, fromServiceMsg) + runCatching { + val cmd = toServiceMsg.getAttribute("__respkey") as? Int? + ?: return@runCatching + val resp = mRespHandler[cmd] + resp?.invoke(toServiceMsg, fromServiceMsg) + }.onFailure { + LogCenter.log("MSF.onResp failed: ${it.message}", Level.ERROR) + } } } \ No newline at end of file