Merge branch 'main' of https://github.com/cinit/QAuxiliary
This commit is contained in:
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
package cc.hicore.hook;
|
package cc.hicore.hook;
|
||||||
|
|
||||||
|
import static io.github.qauxv.util.HostInfo.requireMinQQVersion;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
@@ -31,6 +33,7 @@ import io.github.qauxv.bridge.AppRuntimeHelper;
|
|||||||
import io.github.qauxv.dsl.FunctionEntryRouter;
|
import io.github.qauxv.dsl.FunctionEntryRouter;
|
||||||
import io.github.qauxv.hook.CommonSwitchFunctionHook;
|
import io.github.qauxv.hook.CommonSwitchFunctionHook;
|
||||||
import io.github.qauxv.util.Initiator;
|
import io.github.qauxv.util.Initiator;
|
||||||
|
import io.github.qauxv.util.QQVersion;
|
||||||
|
|
||||||
@FunctionHookEntry
|
@FunctionHookEntry
|
||||||
@UiItemAgentEntry
|
@UiItemAgentEntry
|
||||||
@@ -55,6 +58,20 @@ public class ShowAccurateGaggedTime extends CommonSwitchFunctionHook {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean initOnce() throws Exception {
|
protected boolean initOnce() throws Exception {
|
||||||
|
if (requireMinQQVersion(QQVersion.QQ_9_0_75)) {
|
||||||
|
HookUtils.hookBeforeIfEnabled(this,
|
||||||
|
Reflex.findMethod(Initiator.loadClass("com.tencent.qqnt.troop.impl.TroopGagUtils"), String.class,
|
||||||
|
"remainingTimeToStringCountDown", long.class), param -> {
|
||||||
|
long time = (long) param.args[0];
|
||||||
|
if (time <= 0) {
|
||||||
|
param.setResult("[0秒]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
param.setResult(secondToTime(time));
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
HookUtils.hookBeforeIfEnabled(this,
|
HookUtils.hookBeforeIfEnabled(this,
|
||||||
Reflex.findMethod(Initiator.loadClass("com.tencent.mobileqq.troop.troopgag.api.impl.TroopGagServiceImpl"), String.class,
|
Reflex.findMethod(Initiator.loadClass("com.tencent.mobileqq.troop.troopgag.api.impl.TroopGagServiceImpl"), String.class,
|
||||||
"gagTimeToStringCountDown", Context.class, long.class), param -> {
|
"gagTimeToStringCountDown", Context.class, long.class), param -> {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
package cc.ioctl.hook.chat
|
package cc.ioctl.hook.chat
|
||||||
|
|
||||||
import cc.hicore.QApp.QAppUtils
|
import cc.hicore.QApp.QAppUtils
|
||||||
|
import cc.ioctl.util.hookAfterIfEnabled
|
||||||
import cc.ioctl.util.hookBeforeIfEnabled
|
import cc.ioctl.util.hookBeforeIfEnabled
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
||||||
@@ -36,9 +37,14 @@ import io.github.qauxv.dsl.FunctionEntryRouter
|
|||||||
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
||||||
import io.github.qauxv.util.Initiator
|
import io.github.qauxv.util.Initiator
|
||||||
import io.github.qauxv.util.Log
|
import io.github.qauxv.util.Log
|
||||||
|
import io.github.qauxv.util.QQVersion
|
||||||
import io.github.qauxv.util.SyncUtils
|
import io.github.qauxv.util.SyncUtils
|
||||||
import io.github.qauxv.util.dexkit.CMessageRecordFactory
|
import io.github.qauxv.util.dexkit.CMessageRecordFactory
|
||||||
|
import io.github.qauxv.util.dexkit.DexKit
|
||||||
|
import io.github.qauxv.util.dexkit.Hd_GagInfoDisclosure_Method
|
||||||
|
import io.github.qauxv.util.dexkit.NContactUtils_getBuddyName
|
||||||
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName
|
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName
|
||||||
|
import io.github.qauxv.util.requireMinQQVersion
|
||||||
import xyz.nextalone.util.get
|
import xyz.nextalone.util.get
|
||||||
|
|
||||||
@FunctionHookEntry
|
@FunctionHookEntry
|
||||||
@@ -49,6 +55,8 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
|||||||
targets = arrayOf(
|
targets = arrayOf(
|
||||||
CMessageRecordFactory,
|
CMessageRecordFactory,
|
||||||
NContactUtils_getDiscussionMemberShowName,
|
NContactUtils_getDiscussionMemberShowName,
|
||||||
|
NContactUtils_getBuddyName,
|
||||||
|
Hd_GagInfoDisclosure_Method,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -57,6 +65,10 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
|||||||
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.CHAT_CATEGORY
|
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.CHAT_CATEGORY
|
||||||
override val isAvailable = QAppUtils.isQQnt()
|
override val isAvailable = QAppUtils.isQQnt()
|
||||||
|
|
||||||
|
private fun getLongData(bArr: ByteArray, i: Int): Long {
|
||||||
|
return (((bArr[i].toInt() and 255) shl 24) + ((bArr[i + 1].toInt() and 255) shl 16) + ((bArr[i + 2].toInt() and 255) shl 8) + ((bArr[i + 3].toInt() and 255) shl 0)).toLong()
|
||||||
|
}
|
||||||
|
|
||||||
private fun getSecStr(sec: Long): String {
|
private fun getSecStr(sec: Long): String {
|
||||||
val (min, hour, day) = Triple("分", "时", "天")
|
val (min, hour, day) = Triple("分", "时", "天")
|
||||||
val d = sec / 86400
|
val d = sec / 86400
|
||||||
@@ -70,48 +82,31 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun NtGrayTipHelper.NtGrayTipJsonBuilder.appendUserItem(uin: String, name: String) {
|
private fun NtGrayTipHelper.NtGrayTipJsonBuilder.appendUserItem(uin: String, name: String) {
|
||||||
val uid = RelationNTUinAndUidApi.getUidFromUin(uin).takeIf { it.isNullOrEmpty() } ?: "u_0000000000000000000000"
|
val uid = RelationNTUinAndUidApi.getUidFromUin(uin).takeIf { it.isNullOrEmpty().not() } ?: "u_0000000000000000000000"
|
||||||
this.append(NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(uin, uid, name))
|
this.append(NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(uin, uid, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initOnce(): Boolean {
|
private fun addGagTipMsg(selfUin: String, troopUin: String, opUin: String, victimUin: String, victimTime: Long) {
|
||||||
val clzGagMgr = Initiator._TroopGagMgr()
|
val opName = ContactUtils.getTroopMemberNick(troopUin, opUin)
|
||||||
val method = clzGagMgr.declaredMethods.single { method ->
|
val victimName = ContactUtils.getTroopMemberNick(troopUin, victimUin)
|
||||||
val params = method.parameterTypes; params.size == 5
|
|
||||||
&& params[0] == Int::class.java
|
|
||||||
&& params[1] == Long::class.java
|
|
||||||
&& params[2] == Long::class.java
|
|
||||||
&& params[3] == Long::class.java
|
|
||||||
&& params[4] == ArrayList::class.java
|
|
||||||
&& method.returnType == Void.TYPE
|
|
||||||
}
|
|
||||||
hookBeforeIfEnabled(method) { param ->
|
|
||||||
val selfUin = AppRuntimeHelper.getAccount()
|
|
||||||
val troopUin = param.args[1].toString()
|
|
||||||
val opUin = param.args[2].toString()
|
|
||||||
val opName = ContactUtils.getDiscussionMemberShowName(AppRuntimeHelper.getAppRuntime()!!, troopUin, opUin)
|
|
||||||
val pushParams = param.args[4] as ArrayList<*>
|
|
||||||
val victimUin = pushParams[0].get("uin") as String
|
|
||||||
val victimName = ContactUtils.getDiscussionMemberShowName(AppRuntimeHelper.getAppRuntime()!!, troopUin, victimUin)
|
|
||||||
val victimTime = pushParams[0].get("gagLength") as Long
|
|
||||||
val builder = NtGrayTipHelper.NtGrayTipJsonBuilder()
|
val builder = NtGrayTipHelper.NtGrayTipJsonBuilder()
|
||||||
when (victimUin) {
|
when (victimUin) {
|
||||||
"0" -> {
|
"0" -> {
|
||||||
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, "$opName")
|
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, opName)
|
||||||
builder.appendText(if (victimTime == 0L) "关闭了全员禁言" else "开启了全员禁言")
|
builder.appendText(if (victimTime == 0L) "关闭了全员禁言" else "开启了全员禁言")
|
||||||
}
|
}
|
||||||
|
|
||||||
selfUin -> {
|
selfUin -> {
|
||||||
builder.appendUserItem(selfUin, "你")
|
builder.appendUserItem(selfUin, "你")
|
||||||
builder.appendText("被")
|
builder.appendText("被")
|
||||||
builder.appendUserItem(opUin, "$opName")
|
builder.appendUserItem(opUin, opName)
|
||||||
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
builder.appendUserItem(victimUin, "$victimName")
|
builder.appendUserItem(victimUin, victimName)
|
||||||
builder.appendText("被")
|
builder.appendText("被")
|
||||||
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, "$opName")
|
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, opName)
|
||||||
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,6 +122,43 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun initOnce(): Boolean {
|
||||||
|
if (requireMinQQVersion(QQVersion.QQ_9_0_73)) {
|
||||||
|
hookAfterIfEnabled(DexKit.requireMethodFromCache(Hd_GagInfoDisclosure_Method)) { param ->
|
||||||
|
val msgInfo = param.args[1]
|
||||||
|
val vMsg = msgInfo.get("vMsg") as ByteArray? ?: return@hookAfterIfEnabled
|
||||||
|
if (vMsg[4].toInt() == 12) {
|
||||||
|
val selfUin = AppRuntimeHelper.getAccount()
|
||||||
|
val troopUin = getLongData(vMsg, 0).toString()
|
||||||
|
val opUin = getLongData(vMsg, 6).toString()
|
||||||
|
val victimUinTmp = getLongData(vMsg, 16)
|
||||||
|
val victimUin = (victimUinTmp.takeIf { it > 0 } ?: (victimUinTmp and 0xFFFFFFFFL)).toString()
|
||||||
|
val victimTime = getLongData(vMsg, 20)
|
||||||
|
addGagTipMsg(selfUin, troopUin, opUin, victimUin, victimTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val troopGagClass = Initiator.loadClass("com.tencent.mobileqq.troop.utils.TroopGagMgr")
|
||||||
|
val method = troopGagClass.declaredMethods.single { method ->
|
||||||
|
val params = method.parameterTypes; params.size == 5
|
||||||
|
&& params[0] == Int::class.java
|
||||||
|
&& params[1] == Long::class.java
|
||||||
|
&& params[2] == Long::class.java
|
||||||
|
&& params[3] == Long::class.java
|
||||||
|
&& params[4] == ArrayList::class.java
|
||||||
|
&& method.returnType == Void.TYPE
|
||||||
|
}
|
||||||
|
hookBeforeIfEnabled(method) { param ->
|
||||||
|
val selfUin = AppRuntimeHelper.getAccount()
|
||||||
|
val troopUin = param.args[1].toString()
|
||||||
|
val opUin = param.args[2].toString()
|
||||||
|
val pushParams = param.args[4] as ArrayList<*>
|
||||||
|
val victimUin = pushParams[0].get("uin") as String
|
||||||
|
val victimTime = pushParams[0].get("gagLength") as Long
|
||||||
|
addGagTipMsg(selfUin, troopUin, opUin, victimUin, victimTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,7 @@ import cc.ioctl.util.HookUtils
|
|||||||
import com.github.kyuubiran.ezxhelper.utils.isAbstract
|
import com.github.kyuubiran.ezxhelper.utils.isAbstract
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import de.robv.android.xposed.XC_MethodHook
|
||||||
import io.github.duzhaokun123.hook.MessageCopyHook
|
import io.github.duzhaokun123.hook.MessageCopyHook
|
||||||
|
import io.github.duzhaokun123.hook.MessageTTSHook
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
import io.github.qauxv.hook.BasePersistBackgroundHook
|
import io.github.qauxv.hook.BasePersistBackgroundHook
|
||||||
import io.github.qauxv.util.Initiator
|
import io.github.qauxv.util.Initiator
|
||||||
@@ -52,7 +53,8 @@ object MenuBuilderHook : BasePersistBackgroundHook() {
|
|||||||
MessageCopyHook,
|
MessageCopyHook,
|
||||||
PicCopyToClipboard,
|
PicCopyToClipboard,
|
||||||
MiniAppDirectJump,
|
MiniAppDirectJump,
|
||||||
CopyMarkdown
|
CopyMarkdown,
|
||||||
|
MessageTTSHook,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun initOnce(): Boolean {
|
override fun initOnce(): Boolean {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
package com.xiaoniu.hook
|
package com.xiaoniu.hook
|
||||||
|
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.hookBefore
|
||||||
import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
|
import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
||||||
@@ -29,7 +30,9 @@ import io.github.qauxv.dsl.FunctionEntryRouter
|
|||||||
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
||||||
import io.github.qauxv.util.QQVersion
|
import io.github.qauxv.util.QQVersion
|
||||||
import io.github.qauxv.util.requireMinQQVersion
|
import io.github.qauxv.util.requireMinQQVersion
|
||||||
|
import xyz.nextalone.util.clazz
|
||||||
import xyz.nextalone.util.method
|
import xyz.nextalone.util.method
|
||||||
|
import xyz.nextalone.util.set
|
||||||
import xyz.nextalone.util.throwOrTrue
|
import xyz.nextalone.util.throwOrTrue
|
||||||
|
|
||||||
@FunctionHookEntry
|
@FunctionHookEntry
|
||||||
@@ -38,6 +41,15 @@ object DisableTroopFlame : CommonSwitchFunctionHook() {
|
|||||||
override val name = "屏蔽群火苗"
|
override val name = "屏蔽群火苗"
|
||||||
|
|
||||||
override fun initOnce() = throwOrTrue {
|
override fun initOnce() = throwOrTrue {
|
||||||
|
if (requireMinQQVersion(QQVersion.QQ_9_0_75)) {
|
||||||
|
// Waiting for a better solution...
|
||||||
|
"com.tencent.mobileqq.troop.flame.api.impl.TroopFlameApiImpl".clazz!!
|
||||||
|
.method("getFlameViewDataFromPB")!!
|
||||||
|
.hookBefore {
|
||||||
|
it.args[0].set("switchState", 0)
|
||||||
|
it.args[0].set("state", 0)
|
||||||
|
}
|
||||||
|
} else
|
||||||
"Lcom/tencent/mobileqq/troop/flame/api/impl/TroopFlameApiImpl;->getGroupExtFlameData(Lcom/tencent/mobileqq/data/troop/TroopInfoExt;)Ltencent/trpcprotocol/IqunFlameManageSvrPB\$GroupExtFlameData;"
|
"Lcom/tencent/mobileqq/troop/flame/api/impl/TroopFlameApiImpl;->getGroupExtFlameData(Lcom/tencent/mobileqq/data/troop/TroopInfoExt;)Ltencent/trpcprotocol/IqunFlameManageSvrPB\$GroupExtFlameData;"
|
||||||
.method
|
.method
|
||||||
.hookReturnConstant(null)
|
.hookReturnConstant(null)
|
||||||
|
|||||||
@@ -26,25 +26,37 @@ import android.app.Activity
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.speech.tts.TextToSpeech
|
import android.speech.tts.TextToSpeech
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import cc.hicore.QApp.QAppUtils
|
||||||
import cc.ioctl.util.HostInfo
|
import cc.ioctl.util.HostInfo
|
||||||
import cc.ioctl.util.Reflex
|
import cc.ioctl.util.Reflex
|
||||||
import cc.ioctl.util.afterHookIfEnabled
|
import cc.ioctl.util.afterHookIfEnabled
|
||||||
|
import com.xiaoniu.dispatcher.OnMenuBuilder
|
||||||
|
import com.xiaoniu.util.ContextUtils
|
||||||
|
import de.robv.android.xposed.XC_MethodHook
|
||||||
import de.robv.android.xposed.XposedBridge
|
import de.robv.android.xposed.XposedBridge
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import de.robv.android.xposed.XposedHelpers
|
||||||
|
import io.github.duzhaokun123.hook.MessageCopyHook.TAG
|
||||||
import io.github.duzhaokun123.util.TTS
|
import io.github.duzhaokun123.util.TTS
|
||||||
import io.github.qauxv.R
|
import io.github.qauxv.R
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
||||||
import io.github.qauxv.dsl.FunctionEntryRouter
|
import io.github.qauxv.dsl.FunctionEntryRouter
|
||||||
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
||||||
|
import io.github.qauxv.step.Step
|
||||||
import io.github.qauxv.ui.CommonContextWrapper
|
import io.github.qauxv.ui.CommonContextWrapper
|
||||||
import io.github.qauxv.util.CustomMenu
|
import io.github.qauxv.util.CustomMenu
|
||||||
import io.github.qauxv.util.Initiator
|
import io.github.qauxv.util.Initiator
|
||||||
|
import io.github.qauxv.util.QQVersion
|
||||||
import io.github.qauxv.util.Toasts
|
import io.github.qauxv.util.Toasts
|
||||||
|
import io.github.qauxv.util.dexkit.DexDeobfsProvider
|
||||||
|
import io.github.qauxv.util.dexkit.DexKit
|
||||||
|
import io.github.qauxv.util.dexkit.DexKitFinder
|
||||||
|
import io.github.qauxv.util.dexkit.TextMsgItem_getText
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
|
||||||
@FunctionHookEntry
|
@FunctionHookEntry
|
||||||
@UiItemAgentEntry
|
@UiItemAgentEntry
|
||||||
object MessageTTSHook : CommonSwitchFunctionHook() {
|
object MessageTTSHook : CommonSwitchFunctionHook(), OnMenuBuilder, DexKitFinder {
|
||||||
override val name: String
|
override val name: String
|
||||||
get() = "文字消息转语音 (使用系统 TTS)"
|
get() = "文字消息转语音 (使用系统 TTS)"
|
||||||
|
|
||||||
@@ -52,6 +64,8 @@ object MessageTTSHook : CommonSwitchFunctionHook() {
|
|||||||
get() = "提示失败多半是没设置系统 TTS 引擎"
|
get() = "提示失败多半是没设置系统 TTS 引擎"
|
||||||
|
|
||||||
override fun initOnce(): Boolean {
|
override fun initOnce(): Boolean {
|
||||||
|
if (QAppUtils.isQQnt()) return true
|
||||||
|
|
||||||
val cl_ArkAppItemBuilder = Initiator._TextItemBuilder()
|
val cl_ArkAppItemBuilder = Initiator._TextItemBuilder()
|
||||||
XposedHelpers.findAndHookMethod(
|
XposedHelpers.findAndHookMethod(
|
||||||
cl_ArkAppItemBuilder, "a", Int::class.javaPrimitiveType, Context::class.java,
|
cl_ArkAppItemBuilder, "a", Int::class.javaPrimitiveType, Context::class.java,
|
||||||
@@ -106,11 +120,93 @@ object MessageTTSHook : CommonSwitchFunctionHook() {
|
|||||||
R.id.item_tts -> {
|
R.id.item_tts -> {
|
||||||
TTS.speak(wc, Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: "")
|
TTS.speak(wc, Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.item_tts2 -> {
|
R.id.item_tts2 -> {
|
||||||
val msg = Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: ""
|
val msg = Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: ""
|
||||||
TTS.showConfigDialog(wc, msg)
|
TTS.showConfigDialog(wc, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override val targetComponentTypes: Array<String>
|
||||||
|
get() = arrayOf("com.tencent.mobileqq.aio.msglist.holder.component.text.AIOTextContentComponent")
|
||||||
|
|
||||||
|
override fun onGetMenuNt(msg: Any, componentType: String, param: XC_MethodHook.MethodHookParam) {
|
||||||
|
if (!isEnabled) return
|
||||||
|
val item = CustomMenu.createItemIconNt(msg, "TTS", 0, R.id.item_tts) {
|
||||||
|
val ctx = ContextUtils.getCurrentActivity()
|
||||||
|
val wc = CommonContextWrapper.createAppCompatContext(ctx)
|
||||||
|
val text = try {
|
||||||
|
DexKit.requireMethodFromCache(TextMsgItem_getText).also {
|
||||||
|
it.isAccessible = true
|
||||||
|
}.invoke(msg) as CharSequence
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"${e.javaClass.name}: ${e.message}\n" + (e.stackTrace.joinToString("\n"))
|
||||||
|
}
|
||||||
|
TTS.speak(wc, text.toString())
|
||||||
|
}
|
||||||
|
val item2 = CustomMenu.createItemIconNt(msg, "TTS+", 0, R.id.item_tts2) {
|
||||||
|
val ctx = ContextUtils.getCurrentActivity()
|
||||||
|
val wc = CommonContextWrapper.createAppCompatContext(ctx)
|
||||||
|
val text = try {
|
||||||
|
DexKit.requireMethodFromCache(TextMsgItem_getText).also {
|
||||||
|
it.isAccessible = true
|
||||||
|
}.invoke(msg) as CharSequence
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"${e.javaClass.name}: ${e.message}\n" + (e.stackTrace.joinToString("\n"))
|
||||||
|
}
|
||||||
|
TTS.showConfigDialog(wc, text.toString())
|
||||||
|
}
|
||||||
|
param.result = (param.result as List<*>) + item + item2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see MessageCopyHook
|
||||||
|
*/
|
||||||
|
override fun makePreparationSteps(): Array<Step> {
|
||||||
|
return arrayOf(object : Step {
|
||||||
|
override fun step(): Boolean {
|
||||||
|
return doFind()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDone(): Boolean {
|
||||||
|
return !isNeedFind
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPriority(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDescription(): String {
|
||||||
|
return "文本消息相关方法查找中"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isNeedFind: Boolean
|
||||||
|
get() = HostInfo.requireMinQQVersion(QQVersion.QQ_8_9_63) && TextMsgItem_getText.descCache == null
|
||||||
|
|
||||||
|
override fun doFind(): Boolean {
|
||||||
|
DexDeobfsProvider.getCurrentBackend().use { backend ->
|
||||||
|
val dexKit = backend.getDexKitBridge()
|
||||||
|
android.util.Log.d(TAG, "doFind: doFind")
|
||||||
|
val getText = dexKit.findMethod {
|
||||||
|
searchPackages("com.tencent.mobileqq.aio.msg")
|
||||||
|
matcher {
|
||||||
|
modifiers = Modifier.PRIVATE
|
||||||
|
returnType = "java.lang.CharSequence"
|
||||||
|
paramCount = 0
|
||||||
|
usingNumbers(24)
|
||||||
|
usingStrings("biz_src_jc_aio")
|
||||||
|
// addCall {
|
||||||
|
// name = "getQQText"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}.firstOrNull() ?: return false
|
||||||
|
android.util.Log.d(TAG, "doFind: $getText")
|
||||||
|
TextMsgItem_getText.descCache = getText.descriptor
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ object TTS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun showConfigDialog(wc: Context, text: String = "") {
|
fun showConfigDialog(wc: Context, text: String = "") {
|
||||||
|
if (!checkInit(wc)) return
|
||||||
val binding = Tts2DialogBinding.inflate(LayoutInflater.from(wc))
|
val binding = Tts2DialogBinding.inflate(LayoutInflater.from(wc))
|
||||||
binding.etMsg.setText(text)
|
binding.etMsg.setText(text)
|
||||||
binding.tvVoice.text = instance.voice?.toString() ?: "null"
|
binding.tvVoice.text = instance.voice?.toString() ?: "null"
|
||||||
|
|||||||
@@ -29,8 +29,10 @@ import com.tencent.common.app.AppInterface;
|
|||||||
import de.robv.android.xposed.XposedHelpers;
|
import de.robv.android.xposed.XposedHelpers;
|
||||||
import io.github.qauxv.base.annotation.DexDeobfs;
|
import io.github.qauxv.base.annotation.DexDeobfs;
|
||||||
import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi;
|
import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi;
|
||||||
|
import io.github.qauxv.util.HostInfo;
|
||||||
import io.github.qauxv.util.Initiator;
|
import io.github.qauxv.util.Initiator;
|
||||||
import io.github.qauxv.util.Log;
|
import io.github.qauxv.util.Log;
|
||||||
|
import io.github.qauxv.util.QQVersion;
|
||||||
import io.github.qauxv.util.dexkit.DexKit;
|
import io.github.qauxv.util.dexkit.DexKit;
|
||||||
import io.github.qauxv.util.dexkit.NContactUtils_getBuddyName;
|
import io.github.qauxv.util.dexkit.NContactUtils_getBuddyName;
|
||||||
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName;
|
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName;
|
||||||
@@ -59,6 +61,7 @@ public class ContactUtils {
|
|||||||
Objects.requireNonNull(memberUin);
|
Objects.requireNonNull(memberUin);
|
||||||
AppRuntime app = AppRuntimeHelper.getQQAppInterface();
|
AppRuntime app = AppRuntimeHelper.getQQAppInterface();
|
||||||
assert app != null;
|
assert app != null;
|
||||||
|
if (!HostInfo.requireMinQQVersion(QQVersion.QQ_9_0_25)) {
|
||||||
try {
|
try {
|
||||||
Object mTroopManager = ManagerHelper.getTroopManager();
|
Object mTroopManager = ManagerHelper.getTroopManager();
|
||||||
Object troopMemberInfo = Reflex.invokeVirtualDeclaredOrdinal(mTroopManager, 0, 3, false,
|
Object troopMemberInfo = Reflex.invokeVirtualDeclaredOrdinal(mTroopManager, 0, 3, false,
|
||||||
@@ -77,6 +80,7 @@ public class ContactUtils {
|
|||||||
} catch (Exception | LinkageError e) {
|
} catch (Exception | LinkageError e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
String ret = getDiscussionMemberShowName(app, troopUin, memberUin);
|
String ret = getDiscussionMemberShowName(app, troopUin, memberUin);
|
||||||
if (ret != null) {
|
if (ret != null) {
|
||||||
|
|||||||
@@ -125,4 +125,6 @@ public class QQVersion {
|
|||||||
public static final long QQ_9_0_68 = 6612;
|
public static final long QQ_9_0_68 = 6612;
|
||||||
public static final long QQ_9_0_70 = 6676;
|
public static final long QQ_9_0_70 = 6676;
|
||||||
public static final long QQ_9_0_71 = 6702;
|
public static final long QQ_9_0_71 = 6702;
|
||||||
|
public static final long QQ_9_0_73 = 6722;
|
||||||
|
public static final long QQ_9_0_75 = 6786;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -995,3 +995,10 @@ data object Hd_DisableGrowHalfLayer_Method : DexKitTarget.UsingStringVector() {
|
|||||||
m.returnType == Void.TYPE && m.paramCount == 3
|
m.returnType == Void.TYPE && m.paramCount == 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data object Hd_GagInfoDisclosure_Method : DexKitTarget.UsingStr() {
|
||||||
|
override val findMethod = true
|
||||||
|
override val traitString = arrayOf("<---0x2dc push groupCode:")
|
||||||
|
override val declaringClass = "com.tencent.imcore.message"
|
||||||
|
override val filter = DexKitFilter.strInClsName("com/tencent/imcore/message/")
|
||||||
|
}
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ object FakePicSize : BaseFunctionHook(
|
|||||||
val msgServiceClass = Initiator.loadClass("com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService\$CppProxy")
|
val msgServiceClass = Initiator.loadClass("com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService\$CppProxy")
|
||||||
hookBeforeIfEnabled(msgServiceClass.method("sendMsg")!!) { param ->
|
hookBeforeIfEnabled(msgServiceClass.method("sendMsg")!!) { param ->
|
||||||
val size = sizeMap.values.toList()[sizeIndex]
|
val size = sizeMap.values.toList()[sizeIndex]
|
||||||
|
if (size == 0) return@hookBeforeIfEnabled
|
||||||
val elements = param.args[2] as ArrayList<*>
|
val elements = param.args[2] as ArrayList<*>
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
val msgElement = (element as MsgElement)
|
val msgElement = (element as MsgElement)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import cc.ioctl.util.HostInfo
|
|||||||
import cc.ioctl.util.Reflex
|
import cc.ioctl.util.Reflex
|
||||||
import cc.ioctl.util.hookAfterIfEnabled
|
import cc.ioctl.util.hookAfterIfEnabled
|
||||||
import cc.ioctl.util.hookBeforeIfEnabled
|
import cc.ioctl.util.hookBeforeIfEnabled
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.paramCount
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
||||||
import io.github.qauxv.dsl.FunctionEntryRouter
|
import io.github.qauxv.dsl.FunctionEntryRouter
|
||||||
@@ -100,11 +101,11 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
|||||||
lateinit var buildNotification: Method
|
lateinit var buildNotification: Method
|
||||||
lateinit var recentInfoBuilder: Method
|
lateinit var recentInfoBuilder: Method
|
||||||
cNotificationFacade.declaredMethods.forEach {
|
cNotificationFacade.declaredMethods.forEach {
|
||||||
if (it.parameterTypes.size != 3) return@forEach
|
if (it.paramCount < 3 || it.parameterTypes[0] != cAppRuntime) return@forEach
|
||||||
if (it.parameterTypes[0] != cAppRuntime) return@forEach
|
if (it.paramCount == 3 && it.parameterTypes[2] == cCommonInfo) {
|
||||||
if (it.parameterTypes[2] == cCommonInfo) {
|
|
||||||
buildNotification = it
|
buildNotification = it
|
||||||
} else if (it.parameterTypes[1] == cRecentInfo) {
|
} else if (it.paramCount >= 3 && it.parameterTypes[1] == cRecentInfo && it.parameterTypes[2] == Boolean::class.java) {
|
||||||
|
// paramCount=4 since 9.0.75
|
||||||
recentInfoBuilder = it
|
recentInfoBuilder = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +132,8 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
|||||||
val info = QQRecentContactInfo(pair.first)
|
val info = QQRecentContactInfo(pair.first)
|
||||||
notificationInfoMap.remove(oldNotification.contentIntent)
|
notificationInfoMap.remove(oldNotification.contentIntent)
|
||||||
if (info.chatType == 1 || info.chatType == 2) {
|
if (info.chatType == 1 || info.chatType == 2) {
|
||||||
val content = info.abstractContent?.joinToString(separator = "") { it.get("content", String::class.java) ?: "[未解析消息]" } ?: return@hookBeforeIfEnabled
|
val content =
|
||||||
|
info.abstractContent?.joinToString(separator = "") { it.get("content", String::class.java) ?: "[未解析消息]" } ?: return@hookBeforeIfEnabled
|
||||||
val senderName = info.getUserName() ?: return@hookBeforeIfEnabled
|
val senderName = info.getUserName() ?: return@hookBeforeIfEnabled
|
||||||
val senderUin = info.senderUin ?: return@hookBeforeIfEnabled
|
val senderUin = info.senderUin ?: return@hookBeforeIfEnabled
|
||||||
val senderIcon: IconCompat
|
val senderIcon: IconCompat
|
||||||
@@ -146,17 +148,23 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
|||||||
// 好友消息
|
// 好友消息
|
||||||
when (info.chatType) {
|
when (info.chatType) {
|
||||||
1 -> {
|
1 -> {
|
||||||
senderIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
senderIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon())
|
||||||
|
?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
||||||
shortcut = getShortcut("private_$senderUin", senderName, senderIcon, pair.second)
|
shortcut = getShortcut("private_$senderUin", senderName, senderIcon, pair.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
2 -> {
|
2 -> {
|
||||||
groupName = info.peerName ?: return@hookBeforeIfEnabled
|
groupName = info.peerName ?: return@hookBeforeIfEnabled
|
||||||
groupUin = info.peerUin ?: return@hookBeforeIfEnabled
|
groupUin = info.peerUin ?: return@hookBeforeIfEnabled
|
||||||
|
|
||||||
senderIcon = avatarHelper.getAvatar(senderUin.toString()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
senderIcon = avatarHelper.getAvatar(senderUin.toString()) ?: IconCompat.createWithBitmap(
|
||||||
groupIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
ResUtils.loadDrawableFromAsset("face.png", context).toBitmap()
|
||||||
|
)
|
||||||
|
groupIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon())
|
||||||
|
?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
||||||
shortcut = getShortcut("group_$groupUin", groupName, groupIcon, pair.second)
|
shortcut = getShortcut("group_$groupUin", groupName, groupIcon, pair.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
// Impossible
|
// Impossible
|
||||||
throw Error("what the hell?")
|
throw Error("what the hell?")
|
||||||
@@ -238,11 +246,13 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
|||||||
var messageStyle = historyMessage["$channelId+$mainUin"]
|
var messageStyle = historyMessage["$channelId+$mainUin"]
|
||||||
|
|
||||||
if (messageStyle == null) {
|
if (messageStyle == null) {
|
||||||
messageStyle = MessagingStyle(Person.Builder()
|
messageStyle = MessagingStyle(
|
||||||
|
Person.Builder()
|
||||||
.setName(mainName)
|
.setName(mainName)
|
||||||
.setIcon(mainIcon)
|
.setIcon(mainIcon)
|
||||||
.setKey(mainUin.toString())
|
.setKey(mainUin.toString())
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
messageStyle.conversationTitle = mainName
|
messageStyle.conversationTitle = mainName
|
||||||
messageStyle.isGroupConversation = groupUin != null
|
messageStyle.isGroupConversation = groupUin != null
|
||||||
historyMessage["$channelId+$mainUin"] = messageStyle
|
historyMessage["$channelId+$mainUin"] = messageStyle
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ object ChatInputHint : CommonConfigFunctionHook("na_chat_input_hint", arrayOf(NB
|
|||||||
|
|
||||||
override fun initOnce(): Boolean = throwOrTrue {
|
override fun initOnce(): Boolean = throwOrTrue {
|
||||||
if (requireMinQQVersion(QQVersion.QQ_8_9_63)) {
|
if (requireMinQQVersion(QQVersion.QQ_8_9_63)) {
|
||||||
// 私聊 && QQ_9_0_50版本后的群聊
|
// 私聊 && QQ9.0.35版本后的群聊
|
||||||
DexKit.requireMethodFromCache(AIO_InputRootInit_QQNT).hookAfter(this) {
|
DexKit.requireMethodFromCache(AIO_InputRootInit_QQNT).hookAfter(this) {
|
||||||
it.thisObject.javaClass.declaredFields.single { it.type == EditText::class.java }.apply {
|
it.thisObject.javaClass.declaredFields.single { it.type == EditText::class.java }.apply {
|
||||||
isAccessible = true
|
isAccessible = true
|
||||||
@@ -72,8 +72,8 @@ object ChatInputHint : CommonConfigFunctionHook("na_chat_input_hint", arrayOf(NB
|
|||||||
et.hint = getValue()
|
et.hint = getValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// QQ_9_0_50版本前的群聊
|
// QQ9.0.35版本前的群聊
|
||||||
if (!requireMinQQVersion(QQVersion.QQ_9_0_50)) {
|
if (!requireMinQQVersion(QQVersion.QQ_9_0_35)) {
|
||||||
when { // Lcom/tencent/mobileqq/aio/input/anonymous/AnonymousModeInputVBDelegate;->setNotAnonymousHint()V
|
when { // Lcom/tencent/mobileqq/aio/input/anonymous/AnonymousModeInputVBDelegate;->setNotAnonymousHint()V
|
||||||
requireMinQQVersion(QQVersion.QQ_9_0_30) -> "Lcom/tencent/mobileqq/aio/input/c/c;->l()V"
|
requireMinQQVersion(QQVersion.QQ_9_0_30) -> "Lcom/tencent/mobileqq/aio/input/c/c;->l()V"
|
||||||
requireMinQQVersion(QQVersion.QQ_9_0_20) -> "Lcom/tencent/mobileqq/aio/input/b/c;->l()V"
|
requireMinQQVersion(QQVersion.QQ_9_0_20) -> "Lcom/tencent/mobileqq/aio/input/b/c;->l()V"
|
||||||
|
|||||||
Reference in New Issue
Block a user