diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt index 8679bea..0811816 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeoutOrNull import moe.fuqiuluo.proto.protobufOf import moe.fuqiuluo.shamrock.utils.PlatformUtils import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher @@ -35,45 +36,35 @@ internal abstract class BaseSvc { return ToServiceMsg("mobileqq.service", app.currentAccountUin, cmd) } - suspend fun sendOidbAW(cmd: String, cmdId: Int, serviceId: Int, data: ByteArray, trpc: Boolean = false): ByteArray? { - return suspendCoroutine { continuation -> - val seq = MsfCore.getNextSeq() - val timer = timer(initialDelay = 5000L, period = 5000L) { + suspend fun sendOidbAW(cmd: String, cmdId: Int, serviceId: Int, data: ByteArray, trpc: Boolean = false, timeout: Long = 5000L): ByteArray? { + return withTimeoutOrNull(timeout) { + suspendCoroutine { continuation -> + val seq = MsfCore.getNextSeq() GlobalScope.launch(Dispatchers.Default) { - PacketHandler.unregisterLessHandler(seq) - continuation.resume(null) + DynamicReceiver.register(IPCRequest(cmd, seq) { + val buffer = it.getByteArrayExtra("buffer")!! + continuation.resume(buffer) + }) } + if (trpc) sendTrpcOidb(cmd, cmdId, serviceId, data, seq) + else sendOidb(cmd, cmdId, serviceId, data, seq) } - GlobalScope.launch(Dispatchers.Default) { - DynamicReceiver.register(IPCRequest(cmd, seq) { - val buffer = it.getByteArrayExtra("buffer")!! - timer.cancel() - continuation.resume(buffer) - }) - } - if (trpc) sendTrpcOidb(cmd, cmdId, serviceId, data, seq) - else sendOidb(cmd, cmdId, serviceId, data, seq) - } + }?.copyOf() } - suspend fun sendBufferAW(cmd: String, isPb: Boolean, data: ByteArray): ByteArray? { - return suspendCoroutine { continuation -> - val seq = MsfCore.getNextSeq() - val timer = timer(initialDelay = 5000L, period = 5000L) { + suspend fun sendBufferAW(cmd: String, isPb: Boolean, data: ByteArray, timeout: Long = 5000L): ByteArray? { + return withTimeoutOrNull(timeout) { + suspendCoroutine { continuation -> + val seq = MsfCore.getNextSeq() GlobalScope.launch(Dispatchers.Default) { - PacketHandler.unregisterLessHandler(seq) - continuation.resume(null) + DynamicReceiver.register(IPCRequest(cmd, seq) { + val buffer = it.getByteArrayExtra("buffer")!! + continuation.resume(buffer) + }) + sendBuffer(cmd, isPb, data, seq) } } - GlobalScope.launch(Dispatchers.Default) { - DynamicReceiver.register(IPCRequest(cmd, seq) { - val buffer = it.getByteArrayExtra("buffer")!! - timer.cancel() - continuation.resume(buffer) - }) - sendBuffer(cmd, isPb, data, seq) - } - } + }?.copyOf() } fun sendOidb(cmd: String, cmdId: Int, serviceId: Int, buffer: ByteArray, seq: Int = -1, trpc: Boolean = false) { diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/FileSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/FileSvc.kt index b2bb214..d44be64 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/FileSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/FileSvc.kt @@ -1,12 +1,17 @@ package moe.fuqiuluo.qqinterface.servlet import com.tencent.mobileqq.pb.ByteStringMicro +import io.ktor.util.Deflate import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import moe.fuqiuluo.proto.protobufOf import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc +import moe.fuqiuluo.shamrock.helper.Level +import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY import moe.fuqiuluo.shamrock.tools.slice +import moe.fuqiuluo.shamrock.tools.toHexString +import moe.fuqiuluo.shamrock.utils.DeflateTools import tencent.im.oidb.cmd0x6d8.oidb_0x6d8 import tencent.im.oidb.oidb_sso @@ -92,7 +97,7 @@ internal object FileSvc: BaseSvc() { ) } - suspend fun getGroupRootFiles(groupId: Long): GroupFileList { + suspend fun getGroupRootFiles(groupId: Long): Result { return getGroupFiles(groupId, "/") } @@ -100,7 +105,7 @@ internal object FileSvc: BaseSvc() { return FileUrl(RichProtoSvc.getGroupFileDownUrl(groupId, fileId, busid)) } - suspend fun getGroupFiles(groupId: Long, folderId: String): GroupFileList { + suspend fun getGroupFiles(groupId: Long, folderId: String): Result { val fileSystemInfo = getGroupFileSystemInfo(groupId) val rspGetFileListBuffer = sendOidbAW("OidbSvc.0x6d8_1", 1752, 1, oidb_0x6d8.ReqBody().also { it.file_list_info_req.set(oidb_0x6d8.GetFileListReqBody().apply { @@ -122,17 +127,20 @@ internal object FileSvc: BaseSvc() { uint32_show_onlinedoc_folder.set(0) }) - }.toByteArray()) + }.toByteArray(), timeout = 15_000L) - val files = arrayListOf() - val dirs = arrayListOf() - if (rspGetFileListBuffer != null) { - oidb_0x6d8.RspBody().mergeFrom(oidb_sso.OIDBSSOPkg() - .mergeFrom(rspGetFileListBuffer.slice(4)) - .bytes_bodybuffer.get() - .toByteArray()).file_list_info_rsp.apply { + return kotlin.runCatching { + val files = arrayListOf() + val dirs = arrayListOf() + if (rspGetFileListBuffer != null) { + val oidb = oidb_sso.OIDBSSOPkg().mergeFrom(rspGetFileListBuffer.slice(4).let { + if (it[0] == 0x78.toByte()) DeflateTools.uncompress(it) else it + }) + + oidb_0x6d8.RspBody().mergeFrom(oidb.bytes_bodybuffer.get().toByteArray()) + .file_list_info_rsp.apply { rpt_item_list.get().forEach { file -> - if (file.uint32_type.get() == 1) { + if (file.uint32_type.get() == oidb_0x6d8.GetFileListRspBody.TYPE_FILE) { val fileInfo = file.file_info files.add(FileInfo( groupId = groupId, @@ -147,7 +155,8 @@ internal object FileSvc: BaseSvc() { uploadUin = fileInfo.uint64_uploader_uin.get(), uploadNick = fileInfo.str_uploader_name.get() )) - } else if (file.uint32_type.get() == 2) { + } + else if (file.uint32_type.get() == oidb_0x6d8.GetFileListRspBody.TYPE_FOLDER) { val folderInfo = file.folder_info dirs.add(FolderInfo( groupId = groupId, @@ -158,14 +167,19 @@ internal object FileSvc: BaseSvc() { creator = folderInfo.uint64_create_uin.get(), creatorNick = folderInfo.str_creator_name.get() )) + } else { + LogCenter.log("未知文件类型: ${file.uint32_type.get()}", Level.WARN) } } + } + } else { + throw RuntimeException("获取群文件列表失败") } - } else { - throw RuntimeException("获取群文件列表失败") - } - return GroupFileList(files, dirs) + GroupFileList(files, dirs) + }.onFailure { + LogCenter.log(it.message + ", buffer: ${rspGetFileListBuffer.toHexString()}", Level.ERROR) + } } @Serializable diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupRootFiles.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupRootFiles.kt index 909149b..aa46532 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupRootFiles.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupRootFiles.kt @@ -13,7 +13,10 @@ internal object GetGroupRootFiles: IActionHandler() { } suspend operator fun invoke(groupId: String, echo: JsonElement = EmptyJsonString): String { - return ok(FileSvc.getGroupRootFiles(groupId.toLong()), echo = echo) + FileSvc.getGroupRootFiles(groupId.toLong()).onSuccess { + return ok(it, echo = echo) + }.getOrNull() + return error(why = "获取失败,请查看日志", echo = echo) } override val requiredParams: Array = arrayOf("group_id") diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupSubFiles.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupSubFiles.kt index c2f2234..31574f3 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupSubFiles.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGroupSubFiles.kt @@ -14,7 +14,10 @@ internal object GetGroupSubFiles: IActionHandler() { } suspend operator fun invoke(groupId: String, folderId: String, echo: JsonElement = EmptyJsonString): String { - return ok(FileSvc.getGroupFiles(groupId.toLong(), folderId), echo) + FileSvc.getGroupFiles(groupId.toLong(), folderId).onSuccess { + return ok(it, echo = echo) + }.getOrNull() + return error(why = "获取失败,请查看日志", echo = echo) } override val requiredParams: Array = arrayOf("group_id", "folder_id") diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/Config.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/Config.kt index d8ebadc..28312ca 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/Config.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/Config.kt @@ -9,7 +9,8 @@ data class ServiceConfig( @SerialName("default_token") var defaultToken: String? = null, @SerialName("active_websocket") var activeWebSocket: ConnectionConfig? = null, @SerialName("passive_websocket") var passiveWebSocket: MutableList? = null, - @SerialName("allow-temp-session") var allowTempSession: Boolean = false + @SerialName("allow-temp-session") var allowTempSession: Boolean = false, + @SerialName("anti_qq_trace") var antiTrace: Boolean = true ) @Serializable diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt index ebf00fb..c557046 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt @@ -208,4 +208,8 @@ internal object ShamrockConfig { val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") mmkv.putFloat(key, value) } + + fun isAntiTrace(): Boolean { + return Config.antiTrace + } } \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/AntiDetection.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/AntiDetection.kt index 1e3d055..f0bbc8e 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/AntiDetection.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/AntiDetection.kt @@ -11,6 +11,7 @@ import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedHelpers import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LogCenter +import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig import moe.fuqiuluo.shamrock.tools.hookMethod import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader import mqq.app.MobileQQ @@ -21,7 +22,8 @@ import mqq.app.MobileQQ class AntiDetection: IAction { override fun invoke(ctx: Context) { antiFindPackage(ctx) - antiTrace() + if (ShamrockConfig.isAntiTrace()) + antiTrace() antiMemoryWalking() }