mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: 重构收包起,减少拷贝
Signed-off-by: 白池 <whitechi73@outlook.com>
This commit is contained in:
parent
69cdbad643
commit
5637db43be
@ -91,7 +91,7 @@ class MainActivity : ComponentActivity() {
|
||||
setContent {
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
delay(15_000) // Delay in milliseconds
|
||||
delay(5_000) // Delay in milliseconds
|
||||
broadcastToModule {
|
||||
putExtra("__cmd", "switch_status")
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ abstract class ModuleHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
putExtra("__cmd", cmd)
|
||||
putExtra("__hash", callbackId)
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,8 @@ val DEPENDENCY_ANDROIDX = arrayOf(
|
||||
"androidx.activity:activity-compose:1.7.2",
|
||||
)
|
||||
|
||||
const val DEPENDENCY_JSON5K = "io.github.xn32:json5k:0.3.0"
|
||||
|
||||
const val DEPENDENCY_PROTOBUF = "com.google.protobuf:protobuf-java:3.24.0"
|
||||
const val DEPENDENCY_JAVA_WEBSOCKET = "org.java-websocket:Java-WebSocket:1.5.4"
|
||||
|
||||
fun room(name: String) = "androidx.room:room-$name:${Versions.roomVersion}"
|
||||
|
||||
|
@ -6,9 +6,13 @@ import com.tencent.mobileqq.app.BusinessObserver;
|
||||
import com.tencent.mobileqq.app.MessageHandler;
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import mqq.app.AppRuntime;
|
||||
|
||||
public abstract class AppInterface extends AppRuntime {
|
||||
private final ConcurrentHashMap<String, BusinessHandler> allHandler = new ConcurrentHashMap<>();
|
||||
|
||||
public String getCurrentNickname() {
|
||||
return "";
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ public abstract class BaseBusinessHandler extends OidbWrapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addBusinessObserver(ToServiceMsg toServiceMsg, BusinessObserver businessObserver, boolean z) {
|
||||
|
||||
}
|
||||
|
||||
public final <T> T decodePacket(byte[] data, String name, T obj) {
|
||||
UniPacket uniPacket = new UniPacket(true);
|
||||
try {
|
||||
@ -24,6 +28,10 @@ public abstract class BaseBusinessHandler extends OidbWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean msgCmdFilter(String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract Set<String> getCommandList();
|
||||
|
||||
protected abstract Set<String> getPushCommandList();
|
||||
|
@ -8,6 +8,8 @@ public abstract class BusinessHandler extends BaseBusinessHandler {
|
||||
public BusinessHandler(AppInterface appInterface) {
|
||||
}
|
||||
|
||||
protected abstract Class<? extends BusinessObserver> observerClass();
|
||||
|
||||
@Override
|
||||
public Set<String> getCommandList() {
|
||||
return null;
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.tencent.mobileqq.msf.sdk;
|
||||
|
||||
import com.tencent.qphone.base.remote.FromServiceMsg;
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg;
|
||||
|
||||
public class MsfMessagePair {
|
||||
public FromServiceMsg fromServiceMsg;
|
||||
public String sendProcess;
|
||||
public ToServiceMsg toServiceMsg;
|
||||
|
||||
public MsfMessagePair(String str, ToServiceMsg toServiceMsg, FromServiceMsg fromServiceMsg) {
|
||||
|
||||
}
|
||||
|
||||
public MsfMessagePair(ToServiceMsg toServiceMsg, FromServiceMsg fromServiceMsg) {
|
||||
|
||||
}
|
||||
}
|
@ -66,6 +66,13 @@ public abstract class AppRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
public MobileQQ getApplication() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void startServlet(NewIntent newIntent) {
|
||||
}
|
||||
|
||||
public <T extends IRuntimeService> T getRuntimeService(Class<T> cls, String namespace) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
29
qqinterface/src/main/java/mqq/app/NewIntent.java
Normal file
29
qqinterface/src/main/java/mqq/app/NewIntent.java
Normal file
@ -0,0 +1,29 @@
|
||||
package mqq.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.tencent.mobileqq.app.BusinessObserver;
|
||||
|
||||
public class NewIntent extends Intent {
|
||||
public boolean runNow;
|
||||
|
||||
public NewIntent(Context context, Class<? extends Servlet> cls) {
|
||||
super(context, cls);
|
||||
}
|
||||
|
||||
public BusinessObserver getObserver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isWithouLogin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setObserver(BusinessObserver businessObserver) {
|
||||
|
||||
}
|
||||
|
||||
public void setWithouLogin(boolean z) {
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package moe.fuqiuluo.shamrock.config
|
||||
|
||||
object IsInit: ConfigKey<Boolean>() {
|
||||
override fun name(): String = "is_init"
|
||||
|
||||
override fun default(): Boolean = false
|
||||
}
|
@ -8,7 +8,7 @@ private val configDir = MobileQQ.getContext().getExternalFilesDir(null)!!
|
||||
.parentFile!!.resolve("Tencent/Shamrock").also {
|
||||
if (!it.exists()) it.mkdirs()
|
||||
}
|
||||
private val configFile = configDir.resolve("config.properties")
|
||||
private val configFile = configDir.resolve("config.prop")
|
||||
|
||||
private val configKeys = setOf(
|
||||
ActiveRPC,
|
||||
@ -42,6 +42,7 @@ internal object ShamrockConfig: Properties() {
|
||||
val value = intent.getStringExtra(key.name())
|
||||
if (value != null) setProperty(key.name(), value)
|
||||
}
|
||||
setProperty(IsInit.name(), "true")
|
||||
}
|
||||
configFile.outputStream().use {
|
||||
store(it, "Shamrock Config ${System.currentTimeMillis()}")
|
||||
|
@ -16,6 +16,7 @@ import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.MethodHooker
|
||||
import moe.fuqiuluo.shamrock.tools.hookMethod
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.XposedEntry
|
||||
import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
||||
import moe.fuqiuluo.shamrock.xposed.loader.NativeLoader
|
||||
@ -85,7 +86,12 @@ class AntiDetection: IAction {
|
||||
LogCenter.log("[Shamrock] Shamrock反检测启动失败(env=$env, injected=$injected)", Level.ERROR)
|
||||
} else {
|
||||
XposedEntry.secStaticNativehookInited = true
|
||||
LogCenter.log("[Shamrock] Shamrock反检测启动成功: ${antiNativeDetections()}", Level.INFO)
|
||||
if (PlatformUtils.isMainProcess()) {
|
||||
LogCenter.log(
|
||||
"[Shamrock] Shamrock反检测启动成功: ${antiNativeDetections()}",
|
||||
Level.INFO
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
LogCenter.log("[Shamrock] Shamrock反检测启动失败,请检查LSPosed版本使用大于100: ${e.message}", Level.ERROR)
|
||||
|
@ -7,6 +7,8 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.xposed.actions.interacts.SwitchStatus
|
||||
import moe.fuqiuluo.shamrock.xposed.actions.interacts.Init
|
||||
import moe.fuqiuluo.symbols.Process
|
||||
@ -38,7 +40,12 @@ class DynamicBroadcast: IAction {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val cmd = intent.getStringExtra("__cmd") ?: ""
|
||||
handlers[cmd]?.invoke(intent)
|
||||
val handler = handlers[cmd]
|
||||
if (handler == null) {
|
||||
LogCenter.log("DynamicReceiver.onReceive: unknown cmd=$cmd", Level.ERROR)
|
||||
} else {
|
||||
handler(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
@file:Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE", "LocalVariableName")
|
||||
package moe.fuqiuluo.shamrock.xposed.actions
|
||||
|
||||
import android.content.Context
|
||||
import com.tencent.common.app.AppInterface
|
||||
import com.tencent.mobileqq.msf.sdk.MsfMessagePair
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.hookMethod
|
||||
import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
||||
import moe.fuqiuluo.symbols.XposedHook
|
||||
import qq.service.QQInterfaces
|
||||
import qq.service.internals.MSFHandler.onPush
|
||||
import qq.service.internals.MSFHandler.onResp
|
||||
|
||||
|
||||
@XposedHook(priority = 10)
|
||||
class PatchMsfCore: IAction {
|
||||
override fun invoke(ctx: Context) {
|
||||
val app = QQInterfaces.app
|
||||
require(app is AppInterface) { "QQInterface.app must be AppInterface" }
|
||||
|
||||
runCatching {
|
||||
val MSFRespHandleTask = LuoClassloader.load("mqq.app.msghandle.MSFRespHandleTask")
|
||||
if (MSFRespHandleTask == null) {
|
||||
LogCenter.log("无法注入MSFRespHandleTask!", Level.ERROR)
|
||||
} else {
|
||||
val msfPair = MSFRespHandleTask.declaredFields.first {
|
||||
it.type == MsfMessagePair::class.java
|
||||
}
|
||||
msfPair.isAccessible = true
|
||||
MSFRespHandleTask.hookMethod("run").before {
|
||||
val pair = msfPair.get(it.thisObject) as MsfMessagePair
|
||||
if (pair.toServiceMsg == null) {
|
||||
onPush(pair.fromServiceMsg)
|
||||
} else {
|
||||
onResp(pair.toServiceMsg, pair.fromServiceMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
LogCenter.log(it.stackTraceToString(), Level.ERROR)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,38 @@
|
||||
@file:OptIn(DelicateCoroutinesApi::class)
|
||||
package moe.fuqiuluo.shamrock.xposed.actions
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import moe.fuqiuluo.shamrock.config.IsInit
|
||||
import moe.fuqiuluo.shamrock.config.ShamrockConfig
|
||||
import moe.fuqiuluo.shamrock.tools.toast
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppTalker
|
||||
import moe.fuqiuluo.symbols.Process
|
||||
import moe.fuqiuluo.symbols.XposedHook
|
||||
import kotlin.system.exitProcess
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@XposedHook(Process.MAIN, priority = 1)
|
||||
class PullConfig: IAction {
|
||||
override fun invoke(ctx: Context) {
|
||||
if (!PlatformUtils.isMainProcess()) return
|
||||
|
||||
val isInit = ShamrockConfig[IsInit]
|
||||
AppTalker.talk("init", onFailure = {
|
||||
if (isInit) {
|
||||
ctx.toast("Shamrock主进程未启动,将不会同步配置!")
|
||||
} else {
|
||||
ctx.toast("Shamrock主进程未启动,初始化失败!")
|
||||
GlobalScope.launch {
|
||||
delay(3.seconds)
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
})
|
||||
ctx.toast("同步配置中...")
|
||||
}
|
||||
}
|
@ -24,4 +24,12 @@ internal object AppTalker {
|
||||
bodyBuilder.invoke(values)
|
||||
talk(values)
|
||||
}
|
||||
|
||||
fun talk(action: String, onFailure: ((Throwable) -> Unit)? = null, bodyBuilder: ContentValues.() -> Unit = {}) {
|
||||
val values = ContentValues()
|
||||
values.put("__cmd", action)
|
||||
values.put("__hash", 0)
|
||||
bodyBuilder.invoke(values)
|
||||
talk(values, onFailure)
|
||||
}
|
||||
}
|
52
xposed/src/main/java/qq/service/internals/MSFHandler.kt
Normal file
52
xposed/src/main/java/qq/service/internals/MSFHandler.kt
Normal file
@ -0,0 +1,52 @@
|
||||
package qq.service.internals
|
||||
|
||||
import com.tencent.qphone.base.remote.FromServiceMsg
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
typealias MsfPush = (FromServiceMsg) -> Unit
|
||||
typealias MsfResp = (ToServiceMsg, FromServiceMsg) -> Unit
|
||||
|
||||
internal object MSFHandler {
|
||||
private val mPushHandlers = hashMapOf<String, MsfPush>()
|
||||
private val mRespHandler = hashMapOf<Int, MsfResp>()
|
||||
private val mPushLock = Mutex()
|
||||
private val mRespLock = Mutex()
|
||||
|
||||
suspend fun registerPush(cmd: String, push: MsfPush) {
|
||||
mPushLock.withLock {
|
||||
mPushHandlers[cmd] = push
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun unregisterPush(cmd: String) {
|
||||
mPushLock.withLock {
|
||||
mPushHandlers.remove(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun registerResp(cmd: Int, resp: MsfResp) {
|
||||
mRespLock.withLock {
|
||||
mRespHandler[cmd] = resp
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun unregisterResp(cmd: Int) {
|
||||
mRespLock.withLock {
|
||||
mRespHandler.remove(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
fun onPush(fromServiceMsg: FromServiceMsg) {
|
||||
val cmd = fromServiceMsg.serviceCmd
|
||||
val push = mPushHandlers[cmd]
|
||||
push?.invoke(fromServiceMsg)
|
||||
}
|
||||
|
||||
fun onResp(toServiceMsg: ToServiceMsg, fromServiceMsg: FromServiceMsg) {
|
||||
val cmd = toServiceMsg.getAttribute("respkey") as Int
|
||||
val resp = mRespHandler[cmd]
|
||||
resp?.invoke(toServiceMsg, fromServiceMsg)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user