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 {
|
setContent {
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
while (true) {
|
while (true) {
|
||||||
delay(15_000) // Delay in milliseconds
|
delay(5_000) // Delay in milliseconds
|
||||||
broadcastToModule {
|
broadcastToModule {
|
||||||
putExtra("__cmd", "switch_status")
|
putExtra("__cmd", "switch_status")
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ abstract class ModuleHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
putExtra("__cmd", cmd)
|
||||||
putExtra("__hash", callbackId)
|
putExtra("__hash", callbackId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,8 @@ val DEPENDENCY_ANDROIDX = arrayOf(
|
|||||||
"androidx.activity:activity-compose:1.7.2",
|
"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_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}"
|
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.mobileqq.app.MessageHandler;
|
||||||
import com.tencent.qphone.base.remote.ToServiceMsg;
|
import com.tencent.qphone.base.remote.ToServiceMsg;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import mqq.app.AppRuntime;
|
import mqq.app.AppRuntime;
|
||||||
|
|
||||||
public abstract class AppInterface extends AppRuntime {
|
public abstract class AppInterface extends AppRuntime {
|
||||||
|
private final ConcurrentHashMap<String, BusinessHandler> allHandler = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public String getCurrentNickname() {
|
public String getCurrentNickname() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,10 @@ public abstract class BaseBusinessHandler extends OidbWrapper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addBusinessObserver(ToServiceMsg toServiceMsg, BusinessObserver businessObserver, boolean z) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public final <T> T decodePacket(byte[] data, String name, T obj) {
|
public final <T> T decodePacket(byte[] data, String name, T obj) {
|
||||||
UniPacket uniPacket = new UniPacket(true);
|
UniPacket uniPacket = new UniPacket(true);
|
||||||
try {
|
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> getCommandList();
|
||||||
|
|
||||||
protected abstract Set<String> getPushCommandList();
|
protected abstract Set<String> getPushCommandList();
|
||||||
|
@ -8,6 +8,8 @@ public abstract class BusinessHandler extends BaseBusinessHandler {
|
|||||||
public BusinessHandler(AppInterface appInterface) {
|
public BusinessHandler(AppInterface appInterface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract Class<? extends BusinessObserver> observerClass();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getCommandList() {
|
public Set<String> getCommandList() {
|
||||||
return null;
|
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) {
|
public <T extends IRuntimeService> T getRuntimeService(Class<T> cls, String namespace) {
|
||||||
throw new UnsupportedOperationException();
|
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 {
|
.parentFile!!.resolve("Tencent/Shamrock").also {
|
||||||
if (!it.exists()) it.mkdirs()
|
if (!it.exists()) it.mkdirs()
|
||||||
}
|
}
|
||||||
private val configFile = configDir.resolve("config.properties")
|
private val configFile = configDir.resolve("config.prop")
|
||||||
|
|
||||||
private val configKeys = setOf(
|
private val configKeys = setOf(
|
||||||
ActiveRPC,
|
ActiveRPC,
|
||||||
@ -42,6 +42,7 @@ internal object ShamrockConfig: Properties() {
|
|||||||
val value = intent.getStringExtra(key.name())
|
val value = intent.getStringExtra(key.name())
|
||||||
if (value != null) setProperty(key.name(), value)
|
if (value != null) setProperty(key.name(), value)
|
||||||
}
|
}
|
||||||
|
setProperty(IsInit.name(), "true")
|
||||||
}
|
}
|
||||||
configFile.outputStream().use {
|
configFile.outputStream().use {
|
||||||
store(it, "Shamrock Config ${System.currentTimeMillis()}")
|
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.helper.LogCenter
|
||||||
import moe.fuqiuluo.shamrock.tools.MethodHooker
|
import moe.fuqiuluo.shamrock.tools.MethodHooker
|
||||||
import moe.fuqiuluo.shamrock.tools.hookMethod
|
import moe.fuqiuluo.shamrock.tools.hookMethod
|
||||||
|
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||||
import moe.fuqiuluo.shamrock.xposed.XposedEntry
|
import moe.fuqiuluo.shamrock.xposed.XposedEntry
|
||||||
import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader
|
||||||
import moe.fuqiuluo.shamrock.xposed.loader.NativeLoader
|
import moe.fuqiuluo.shamrock.xposed.loader.NativeLoader
|
||||||
@ -85,7 +86,12 @@ class AntiDetection: IAction {
|
|||||||
LogCenter.log("[Shamrock] Shamrock反检测启动失败(env=$env, injected=$injected)", Level.ERROR)
|
LogCenter.log("[Shamrock] Shamrock反检测启动失败(env=$env, injected=$injected)", Level.ERROR)
|
||||||
} else {
|
} else {
|
||||||
XposedEntry.secStaticNativehookInited = true
|
XposedEntry.secStaticNativehookInited = true
|
||||||
LogCenter.log("[Shamrock] Shamrock反检测启动成功: ${antiNativeDetections()}", Level.INFO)
|
if (PlatformUtils.isMainProcess()) {
|
||||||
|
LogCenter.log(
|
||||||
|
"[Shamrock] Shamrock反检测启动成功: ${antiNativeDetections()}",
|
||||||
|
Level.INFO
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
LogCenter.log("[Shamrock] Shamrock反检测启动失败,请检查LSPosed版本使用大于100: ${e.message}", Level.ERROR)
|
LogCenter.log("[Shamrock] Shamrock反检测启动失败,请检查LSPosed版本使用大于100: ${e.message}", Level.ERROR)
|
||||||
|
@ -7,6 +7,8 @@ import android.content.Intent
|
|||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import de.robv.android.xposed.XposedBridge
|
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.SwitchStatus
|
||||||
import moe.fuqiuluo.shamrock.xposed.actions.interacts.Init
|
import moe.fuqiuluo.shamrock.xposed.actions.interacts.Init
|
||||||
import moe.fuqiuluo.symbols.Process
|
import moe.fuqiuluo.symbols.Process
|
||||||
@ -38,7 +40,12 @@ class DynamicBroadcast: IAction {
|
|||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val cmd = intent.getStringExtra("__cmd") ?: ""
|
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
|
package moe.fuqiuluo.shamrock.xposed.actions
|
||||||
|
|
||||||
import android.content.Context
|
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.utils.PlatformUtils
|
||||||
|
import moe.fuqiuluo.shamrock.xposed.helper.AppTalker
|
||||||
import moe.fuqiuluo.symbols.Process
|
import moe.fuqiuluo.symbols.Process
|
||||||
import moe.fuqiuluo.symbols.XposedHook
|
import moe.fuqiuluo.symbols.XposedHook
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@XposedHook(Process.MAIN, priority = 1)
|
@XposedHook(Process.MAIN, priority = 1)
|
||||||
class PullConfig: IAction {
|
class PullConfig: IAction {
|
||||||
override fun invoke(ctx: Context) {
|
override fun invoke(ctx: Context) {
|
||||||
if (!PlatformUtils.isMainProcess()) return
|
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)
|
bodyBuilder.invoke(values)
|
||||||
talk(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