3 Commits

Author SHA1 Message Date
b9cfe73eae Shamrock: fix #150 2024-01-17 04:53:07 +08:00
8d6d984849 Shamrock: 尝试修复重复Client连接 #187 2024-01-17 04:15:24 +08:00
25fe9fab37 Shamrock: fix 9.0.8 2024-01-17 03:52:49 +08:00
10 changed files with 178 additions and 67 deletions

View File

@ -16,10 +16,11 @@
## 简介 ## 简介
☘ 基于 Xposed 实现 OneBot 标准的 QQ 机器人框架,原作者[**fuqiuluo**](https://github.com/fuqiuluo)已脱离开发接下来由白池接手哦本项目为OpenShamrock不会有任何收费行为欢迎大家的加入 ☘ 基于 Lsposed(**Non**-Riru) 实现 OneBot 标准的 QQ 机器人框架,原作者[**fuqiuluo**](https://github.com/fuqiuluo)已脱离开发接下来由白池接手哦本项目为OpenShamrock不会有任何收费行为欢迎大家的加入
> 本项目仅提供学习与交流用途请在24小时内删除。 > 本项目仅提供学习与交流用途请在24小时内删除。
> 本项目目的是研究 Xposed 和 LSPosed 框架的使用。 Epic 框架开发相关知识。 > 本项目目的是研究 Xposed 和 LSPosed 框架的使用。 Epic 框架开发相关知识。
> Riru可能导致封禁请减少使用。
> 如有违反法律,请联系删除。 > 如有违反法律,请联系删除。
> 请勿在任何平台宣传,宣扬,转发本项目,请勿恶意修改企业安装包造成相关企业产生损失,如有违背,必将追责到底。 > 请勿在任何平台宣传,宣扬,转发本项目,请勿恶意修改企业安装包造成相关企业产生损失,如有违背,必将追责到底。
> 官方论坛,[点我直达](https://forum.libfekit.so/) > 官方论坛,[点我直达](https://forum.libfekit.so/)

View File

@ -15,6 +15,8 @@ static std::vector<std::string> qemu_detect_props = {
static int (*backup_system_property_get)(const char *name, char *value); static int (*backup_system_property_get)(const char *name, char *value);
static FILE* (*backup_fopen)(const char *filename, const char *mode); static FILE* (*backup_fopen)(const char *filename, const char *mode);
static int (*backup_memcmp)(const void* __lhs, const void* __rhs, size_t __n);
//static const char* (*backup_strstr)(const char* h, const char* n);
//int fake_system_property_get(const char *name, char *value); //int fake_system_property_get(const char *name, char *value);
//FILE* fake_fopen(const char *filename, const char *mode); //FILE* fake_fopen(const char *filename, const char *mode);

View File

@ -85,8 +85,6 @@ int fake_system_property_get(const char *name, char *value) {
return backup_system_property_get(name, value); return backup_system_property_get(name, value);
} }
FILE* fake_fopen(const char *filename, const char *mode) { FILE* fake_fopen(const char *filename, const char *mode) {
if (strstr(filename, "qemu_pipe")) { if (strstr(filename, "qemu_pipe")) {
LOGI("[Shamrock] bypass qemu detection"); LOGI("[Shamrock] bypass qemu detection");
@ -117,6 +115,54 @@ FILE* fake_fopen(const char *filename, const char *mode) {
return backup_fopen(filename, mode); return backup_fopen(filename, mode);
} }
char * __cdecl my_strstr(const char *lhs, const char *rhs) {
char *cur = (char *)lhs;
char *l;
char *r;
if (!*rhs) {
return ((char *)lhs);
}
while (*cur) {
l = cur;
r = (char *)rhs;
while (*r && !(*l - *r)) {
l++;
r++;
}
if (!*r) {
return cur;
}
cur++;
}
return nullptr;
}
int fake_memcmp(const void* __lhs, const void* __rhs, size_t __n) {
//if (my_strstr((const char*) __rhs, "lsposed")) {
//return -1;
//}
//if (my_strstr((const char*) __rhs, "xposed")) {
// return -1;
//}
if (my_strstr((const char*) __rhs, "shamrock")) {
if (backup_memcmp(__lhs, __rhs, __n) == 0) {
// 底层广播判断
return 0;
}
return -1;
}
if (my_strstr((const char*) __rhs, "riru")) {
return -1;
}
//if (my_strstr((const char*) __rhs, "zygisk")) {
// return -1;
//}
//if (my_strstr((const char*) __rhs, "magisk")) {
// return -1;
//}
return backup_memcmp(__lhs, __rhs, __n);
}
void on_library_loaded(const char *name, void *handle) { void on_library_loaded(const char *name, void *handle) {
} }
@ -136,5 +182,8 @@ Java_moe_fuqiuluo_shamrock_xposed_actions_AntiDetection_antiNativeDetections(JNI
if (hook_function == nullptr) return false; if (hook_function == nullptr) return false;
hook_function((void*) __system_property_get, (void *)fake_system_property_get, (void **) &backup_system_property_get); hook_function((void*) __system_property_get, (void *)fake_system_property_get, (void **) &backup_system_property_get);
hook_function((void*) fopen, (void*) fake_fopen, (void**) &backup_fopen); hook_function((void*) fopen, (void*) fake_fopen, (void**) &backup_fopen);
//hook_function((void*) strstr, (void*) fake_strstr, (void**) &backup_strstr);
hook_function((void*) memcmp, (void*) fake_memcmp, (void**) &backup_memcmp);
return true; return true;
} }

View File

@ -18,6 +18,11 @@ internal class WebSocketClientService(
) : WebSocketClientServlet(address, heartbeatInterval, wsHeaders) { ) : WebSocketClientServlet(address, heartbeatInterval, wsHeaders) {
private val eventJobList = mutableSetOf<Job>() private val eventJobList = mutableSetOf<Job>()
init {
startHeartbeatTimer()
initTransmitter()
}
override fun submitFlowJob(job: Job) { override fun submitFlowJob(job: Job) {
eventJobList.add(job) eventJobList.add(job)
} }

View File

@ -264,8 +264,10 @@ internal object GlobalEventTransmitter: BaseSvc() {
suspend fun transGroupMemberNumChanged( suspend fun transGroupMemberNumChanged(
time: Long, time: Long,
target: Long, target: Long,
targetUid: String,
groupCode: Long, groupCode: Long,
operation: Long, operator: Long,
operatorUid: String,
noticeType: NoticeType, noticeType: NoticeType,
noticeSubType: NoticeSubType noticeSubType: NoticeSubType
): Boolean { ): Boolean {
@ -275,11 +277,14 @@ internal object GlobalEventTransmitter: BaseSvc() {
postType = PostType.Notice, postType = PostType.Notice,
type = noticeType, type = noticeType,
subType = noticeSubType, subType = noticeSubType,
operatorId = operation, operatorId = operator,
userId = target, userId = target,
senderId = operation, senderId = operator,
target = target, target = target,
groupId = groupCode groupId = groupCode,
targetUid = targetUid,
operatorUid = operatorUid,
userUid = targetUid
)) ))
return true return true
} }
@ -287,6 +292,7 @@ internal object GlobalEventTransmitter: BaseSvc() {
suspend fun transGroupAdminChanged( suspend fun transGroupAdminChanged(
msgTime: Long, msgTime: Long,
target: Long, target: Long,
targetUid: String,
groupCode: Long, groupCode: Long,
setAdmin: Boolean setAdmin: Boolean
): Boolean { ): Boolean {
@ -298,6 +304,7 @@ internal object GlobalEventTransmitter: BaseSvc() {
subType = if (setAdmin) NoticeSubType.Set else NoticeSubType.UnSet, subType = if (setAdmin) NoticeSubType.Set else NoticeSubType.UnSet,
operatorId = 0, operatorId = 0,
target = target, target = target,
targetUid = targetUid,
groupId = groupCode groupId = groupCode
)) ))
return true return true
@ -306,8 +313,10 @@ internal object GlobalEventTransmitter: BaseSvc() {
suspend fun transGroupBan( suspend fun transGroupBan(
msgTime: Long, msgTime: Long,
subType: NoticeSubType, subType: NoticeSubType,
operation: Long, operator: Long,
operatorUid: String,
target: Long, target: Long,
targetUid: String,
groupCode: Long, groupCode: Long,
duration: Int duration: Int
): Boolean { ): Boolean {
@ -317,12 +326,14 @@ internal object GlobalEventTransmitter: BaseSvc() {
postType = PostType.Notice, postType = PostType.Notice,
type = NoticeType.GroupBan, type = NoticeType.GroupBan,
subType = subType, subType = subType,
operatorId = operation, operatorId = operator,
userId = target, userId = target,
senderId = operation, senderId = operator,
target = target, target = target,
groupId = groupCode, groupId = groupCode,
duration = duration duration = duration,
operatorUid = operatorUid,
targetUid = targetUid
)) ))
return true return true
} }

View File

@ -35,24 +35,22 @@ import java.net.URI
import kotlin.concurrent.timer import kotlin.concurrent.timer
internal abstract class WebSocketClientServlet( internal abstract class WebSocketClientServlet(
url: String, private val url: String,
private val heartbeatInterval: Long, private val heartbeatInterval: Long,
private val wsHeaders: Map<String, String> private val wsHeaders: Map<String, String>
) : BaseTransmitServlet, WebSocketClient(URI(url), wsHeaders) { ) : BaseTransmitServlet, WebSocketClient(URI(url), wsHeaders) {
init {
if (connectedClients.containsKey(url)) {
throw RuntimeException("WebSocketClient已存在: $url")
}
}
private val sendLock = Mutex() private val sendLock = Mutex()
override fun allowTransmit(): Boolean { override fun allowTransmit(): Boolean {
return ShamrockConfig.openWebSocketClient() return ShamrockConfig.openWebSocketClient()
} }
override fun onOpen(handshakedata: ServerHandshake?) {
LogCenter.log("WebSocketClient onOpen: ${handshakedata?.httpStatus}, ${handshakedata?.httpStatusMessage}")
startHeartbeatTimer()
pushMetaLifecycle()
initTransmitter()
}
override fun onMessage(message: String) { override fun onMessage(message: String) {
GlobalScope.launch { GlobalScope.launch {
handleMessage(message) handleMessage(message)
@ -84,6 +82,16 @@ internal abstract class WebSocketClientServlet(
respond?.let { send(it) } respond?.let { send(it) }
} }
override fun onOpen(handshakedata: ServerHandshake?) {
LogCenter.log("WebSocketClient onOpen: ${handshakedata?.httpStatus}, ${handshakedata?.httpStatusMessage}")
connectedClients[url] = this
//startHeartbeatTimer()
pushMetaLifecycle()
//initTransmitter()
}
override fun onClose(code: Int, reason: String?, remote: Boolean) { override fun onClose(code: Int, reason: String?, remote: Boolean) {
if (code == 403) { if (code == 403) {
if (wsHeaders.containsKey("authorization")) { if (wsHeaders.containsKey("authorization")) {
@ -95,11 +103,13 @@ internal abstract class WebSocketClientServlet(
} }
LogCenter.log("WebSocketClient onClose: $code, $reason, $remote") LogCenter.log("WebSocketClient onClose: $code, $reason, $remote")
cancelFlowJobs() cancelFlowJobs()
connectedClients.remove(url)
} }
override fun onError(ex: Exception?) { override fun onError(ex: Exception?) {
LogCenter.log("WebSocketClient onError: ${ex?.message}") LogCenter.log("WebSocketClient onError: ${ex?.message}")
cancelFlowJobs() cancelFlowJobs()
connectedClients.remove(url)
} }
protected suspend inline fun <reified T> pushTo(body: T) { protected suspend inline fun <reified T> pushTo(body: T) {
@ -113,14 +123,14 @@ internal abstract class WebSocketClientServlet(
} }
} }
private fun startHeartbeatTimer() { fun startHeartbeatTimer() {
if (heartbeatInterval <= 0) { if (heartbeatInterval <= 0) {
LogCenter.log("被动WebSocket心跳间隔为0不启动心跳", Level.WARN) LogCenter.log("被动WebSocket心跳间隔为0不启动心跳", Level.WARN)
return return
} }
timer( timer(
name = "heartbeat", name = "heartbeat",
initialDelay = 0, initialDelay = heartbeatInterval,
period = heartbeatInterval, period = heartbeatInterval,
) { ) {
if (isClosed || isClosing || !isOpen) { if (isClosed || isClosing || !isOpen) {
@ -143,7 +153,7 @@ internal abstract class WebSocketClientServlet(
status = "正常", status = "正常",
good = true good = true
), ),
interval = 1000L * 15 interval = heartbeatInterval
) )
) )
) )
@ -169,4 +179,8 @@ internal abstract class WebSocketClientServlet(
) )
} }
} }
companion object {
private val connectedClients = mutableMapOf<String, WebSocketClientServlet>()
}
} }

View File

@ -67,14 +67,20 @@ internal data class NoticeEvent(
@SerialName("post_type") val postType: PostType, @SerialName("post_type") val postType: PostType,
@SerialName("notice_type") val type: NoticeType, @SerialName("notice_type") val type: NoticeType,
@SerialName("sub_type") val subType: NoticeSubType = NoticeSubType.None, @SerialName("sub_type") val subType: NoticeSubType = NoticeSubType.None,
@SerialName("group_id") val groupId: Long = -1, @SerialName("group_id") val groupId: Long = Long.MIN_VALUE,
@SerialName("operator_id") val operatorId: Long = -1, @SerialName("operator_id") val operatorId: Long = Long.MIN_VALUE,
@SerialName("user_id") val userId: Long = -1, @SerialName("operator_uid") val operatorUid: String = "",
@SerialName("sender_id") val senderId: Long = -1, @SerialName("user_id") val userId: Long = Long.MIN_VALUE,
@SerialName("duration") val duration: Int = -1, @SerialName("user_uid") val userUid: String = "",
@SerialName("message_id") val msgId: Int = -1, @SerialName("sender_id") val senderId: Long = Long.MIN_VALUE,
@SerialName("duration") val duration: Int = Int.MIN_VALUE,
@SerialName("message_id") val msgId: Int = Int.MIN_VALUE,
@SerialName("tip_text") val tip: String = "", @SerialName("tip_text") val tip: String = "",
@SerialName("target_id") val target: Long = -1,
@SerialName("target_id") val target: Long = Long.MIN_VALUE,
@SerialName("target_uid") val targetUid: String = "",
@SerialName("file") val file: GroupFileMsg? = null, @SerialName("file") val file: GroupFileMsg? = null,
@SerialName("private_file") val privateFile: PrivateFileMsg? = null, @SerialName("private_file") val privateFile: PrivateFileMsg? = null,
@SerialName("flag") val flag: String? = null, @SerialName("flag") val flag: String? = null,
@ -92,7 +98,7 @@ internal data class NoticeEvent(
// 群打卡 // 群打卡
@SerialName("sign_detail") val signDetail: SignDetail? = null, @SerialName("sign_detail") val signDetail: SignDetail? = null,
) )
/** /**
* 不要使用继承的方式实现通用字段,那样会很难维护! * 不要使用继承的方式实现通用字段,那样会很难维护!

View File

@ -14,6 +14,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.proto.* import moe.fuqiuluo.proto.*
import moe.fuqiuluo.qqinterface.servlet.FriendSvc.requestFriendSystemMsgNew import moe.fuqiuluo.qqinterface.servlet.FriendSvc.requestFriendSystemMsgNew
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc.requestGroupSystemMsgNew import moe.fuqiuluo.qqinterface.servlet.GroupSvc.requestGroupSystemMsgNew
import moe.fuqiuluo.qqinterface.servlet.TicketSvc.getLongUin import moe.fuqiuluo.qqinterface.servlet.TicketSvc.getLongUin
import moe.fuqiuluo.shamrock.helper.MessageHelper import moe.fuqiuluo.shamrock.helper.MessageHelper
@ -302,11 +303,10 @@ internal object PrimitiveListener {
LogCenter.log("onGroupPokeAndGroupSign error: ${e.stackTraceToString()}", Level.WARN) LogCenter.log("onGroupPokeAndGroupSign error: ${e.stackTraceToString()}", Level.WARN)
} }
} }
var groupId:Long val groupId = try {
try { detail[4].asULong
groupId = detail[4].asULong
}catch (e: ClassCastException){ }catch (e: ClassCastException){
groupId = detail[4].asList.value[0].asULong detail[4].asList.value[0].asULong
} }
detail = if (detail[26] is ProtoList) { detail = if (detail[26] is ProtoList) {
@ -392,13 +392,21 @@ internal object PrimitiveListener {
val groupCode = pb[1, 3, 2, 1].asULong val groupCode = pb[1, 3, 2, 1].asULong
val targetUid = pb[1, 3, 2, 3].asUtf8String val targetUid = pb[1, 3, 2, 3].asUtf8String
val type = pb[1, 3, 2, 4].asInt val type = pb[1, 3, 2, 4].asInt
val operation = ContactHelper.getUinByUidAsync(pb[1, 3, 2, 5].asUtf8String).toLong()
GroupSvc.getGroupMemberList(groupCode.toString(), true).onFailure {
LogCenter.log("新成员加入刷新群成员列表失败: $groupCode", Level.WARN)
}.onSuccess {
LogCenter.log("新成员加入刷新群成员列表成功,群成员数量: ${it.size}", Level.INFO)
}
val operatorUid = pb[1, 3, 2, 5].asUtf8String
val operator = ContactHelper.getUinByUidAsync(operatorUid).toLong()
val target = ContactHelper.getUinByUidAsync(targetUid).toLong() val target = ContactHelper.getUinByUidAsync(targetUid).toLong()
LogCenter.log("群成员增加($groupCode): $target, type = $type") LogCenter.log("群成员增加($groupCode): $target, type = $type")
if (!GlobalEventTransmitter.GroupNoticeTransmitter if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMemberNumChanged( .transGroupMemberNumChanged(
time, target, groupCode, operation, NoticeType.GroupMemIncrease, when (type) { time, target, targetUid, groupCode, operator, operatorUid, NoticeType.GroupMemIncrease, when (type) {
130 -> NoticeSubType.Approve 130 -> NoticeSubType.Approve
131 -> NoticeSubType.Invite 131 -> NoticeSubType.Invite
else -> NoticeSubType.Approve else -> NoticeSubType.Approve
@ -413,11 +421,19 @@ internal object PrimitiveListener {
val groupCode = pb[1, 3, 2, 1].asULong val groupCode = pb[1, 3, 2, 1].asULong
val targetUid = pb[1, 3, 2, 3].asUtf8String val targetUid = pb[1, 3, 2, 3].asUtf8String
val type = pb[1, 3, 2, 4].asInt val type = pb[1, 3, 2, 4].asInt
val operation = try { val operatorUid = try {
ContactHelper.getUinByUidAsync(pb[1, 3, 2, 5, 1, 1].asUtf8String).toLong() pb[1, 3, 2, 5, 1, 1].asUtf8String
} catch (e: Throwable) { } catch (e: Throwable) {
ContactHelper.getUinByUidAsync(pb[1, 3, 2, 5].asUtf8String).toLong() pb[1, 3, 2, 5].asUtf8String
} }
GroupSvc.getGroupMemberList(groupCode.toString(), true).onFailure {
LogCenter.log("新成员加入刷新群成员列表失败: $groupCode", Level.WARN)
}.onSuccess {
LogCenter.log("新成员加入刷新群成员列表成功,群成员数量: ${it.size}", Level.INFO)
}
val operator = ContactHelper.getUinByUidAsync(operatorUid).toLong()
val target = ContactHelper.getUinByUidAsync(targetUid).toLong() val target = ContactHelper.getUinByUidAsync(targetUid).toLong()
val subtype = when (type) { val subtype = when (type) {
130 -> NoticeSubType.Leave 130 -> NoticeSubType.Leave
@ -431,7 +447,7 @@ internal object PrimitiveListener {
LogCenter.log("群成员减少($groupCode): $target, type = $subtype ($type)") LogCenter.log("群成员减少($groupCode): $target, type = $subtype ($type)")
if (!GlobalEventTransmitter.GroupNoticeTransmitter if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMemberNumChanged(time, target, groupCode, operation, NoticeType.GroupMemDecrease, subtype) .transGroupMemberNumChanged(time, target, targetUid, groupCode, operator, operatorUid, NoticeType.GroupMemDecrease, subtype)
) { ) {
LogCenter.log("群成员减少推送失败!", Level.WARN) LogCenter.log("群成员减少推送失败!", Level.WARN)
} }
@ -452,7 +468,7 @@ internal object PrimitiveListener {
LogCenter.log("群管理员变动($groupCode): $target, isSetAdmin = $isSetAdmin") LogCenter.log("群管理员变动($groupCode): $target, isSetAdmin = $isSetAdmin")
if (!GlobalEventTransmitter.GroupNoticeTransmitter if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupAdminChanged(msgTime, target, groupCode, isSetAdmin) .transGroupAdminChanged(msgTime, target, targetUid, groupCode, isSetAdmin)
) { ) {
LogCenter.log("群管理员变动推送失败!", Level.WARN) LogCenter.log("群管理员变动推送失败!", Level.WARN)
} }
@ -465,18 +481,18 @@ internal object PrimitiveListener {
val targetUid = if (wholeBan) "" else pb[1, 3, 2, 5, 3, 1].asUtf8String val targetUid = if (wholeBan) "" else pb[1, 3, 2, 5, 3, 1].asUtf8String
val rawDuration = pb[1, 3, 2, 5, 3, 2].asInt val rawDuration = pb[1, 3, 2, 5, 3, 2].asInt
val operation = ContactHelper.getUinByUidAsync(operatorUid).toLong() val operator = ContactHelper.getUinByUidAsync(operatorUid).toLong()
val duration = if (wholeBan) -1 else rawDuration val duration = if (wholeBan) -1 else rawDuration
val target = if (wholeBan) 0 else ContactHelper.getUinByUidAsync(targetUid).toLong() val target = if (wholeBan) 0 else ContactHelper.getUinByUidAsync(targetUid).toLong()
val subType = if (rawDuration == 0) NoticeSubType.LiftBan else NoticeSubType.Ban val subType = if (rawDuration == 0) NoticeSubType.LiftBan else NoticeSubType.Ban
if (wholeBan) { if (wholeBan) {
LogCenter.log("群全员禁言($groupCode): $operation -> ${if (subType == NoticeSubType.Ban) "开启" else "关闭"}") LogCenter.log("群全员禁言($groupCode): $operator -> ${if (subType == NoticeSubType.Ban) "开启" else "关闭"}")
} else { } else {
LogCenter.log("群禁言($groupCode): $operation -> $target, 时长 = ${duration}s") LogCenter.log("群禁言($groupCode): $operator -> $target, 时长 = ${duration}s")
} }
if (!GlobalEventTransmitter.GroupNoticeTransmitter if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupBan(msgTime, subType, operation, target, groupCode, duration) .transGroupBan(msgTime, subType, operator, operatorUid, target, targetUid, groupCode, duration)
) { ) {
LogCenter.log("群禁言推送失败!", Level.WARN) LogCenter.log("群禁言推送失败!", Level.WARN)
} }

View File

@ -5,12 +5,14 @@ import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.VersionedPackage import android.content.pm.VersionedPackage
import android.os.Build import android.os.Build
import android.os.Looper
import de.robv.android.xposed.XC_MethodReplacement import de.robv.android.xposed.XC_MethodReplacement
import de.robv.android.xposed.XSharedPreferences import de.robv.android.xposed.XSharedPreferences
import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.XposedHelpers
import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.tools.MethodHooker
import moe.fuqiuluo.shamrock.tools.hookMethod import moe.fuqiuluo.shamrock.tools.hookMethod
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
@ -181,6 +183,22 @@ class AntiDetection: IAction {
return className.isModuleStack() return className.isModuleStack()
} }
val stackTraceHooker: MethodHooker = {
val result = it.result as Array<StackTraceElement>
var zygote = false
val newResult = result.filter {
if (it.className == ZYGOTE_NAME) {
zygote = true
}
!it.isModuleStack()
}.toTypedArray()
if (!zygote && Thread.currentThread() == Looper.getMainLooper().thread) {
it.result = arrayListOf(StackTraceElement(ZYGOTE_NAME, "main", ZYGOTE_NAME, 0), *newResult)
} else {
it.result = newResult
}
}
Thread::class.java.hookMethod("getName").after { Thread::class.java.hookMethod("getName").after {
val result = it.result as String val result = it.result as String
if (result.contains("fuqiuluo") || result.contains("shamrock") || result.contains("whitechi")) { if (result.contains("fuqiuluo") || result.contains("shamrock") || result.contains("whitechi")) {
@ -188,30 +206,15 @@ class AntiDetection: IAction {
} }
} }
Thread::class.java.hookMethod("getStackTrace").after { Thread::class.java.hookMethod("getStackTrace").after(stackTraceHooker)
val result = it.result as Array<StackTraceElement> Throwable::class.java.hookMethod("getStackTrace").after(stackTraceHooker)
it.result = result.filter { Throwable::class.java.hookMethod("getOurStackTrace").after(stackTraceHooker)
!it.isModuleStack()
}.toTypedArray()
}
Throwable::class.java.hookMethod("getStackTrace").after {
val result = it.result as Array<StackTraceElement>
it.result = result.filter {
!it.isModuleStack()
}.toTypedArray()
}
Throwable::class.java.hookMethod("getOurStackTrace").after {
val result = it.result as Array<StackTraceElement>
it.result = result.filter {
!it.isModuleStack()
}.toTypedArray()
}
} }
companion object { companion object {
@JvmStatic @JvmStatic
var isAntiFindPackage = false var isAntiFindPackage = false
const val ZYGOTE_NAME = "com.android.internal.os.ZygoteInit"
} }
} }

View File

@ -115,7 +115,11 @@ internal class InitRemoteService : IAction {
LogCenter.log("被动WebSocket地址不合法: $url", Level.ERROR) LogCenter.log("被动WebSocket地址不合法: $url", Level.ERROR)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
LogCenter.log(e.stackTraceToString(), Level.ERROR) if (e is RuntimeException) {
LogCenter.log(e.message ?: e.stackTraceToString(), Level.ERROR)
} else {
LogCenter.log(e.stackTraceToString(), Level.ERROR)
}
} }
} }
} }