Merge branch 'main' of https://github.com/cinit/QAuxiliary
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
|
||||
package cc.hicore.hook;
|
||||
|
||||
import static io.github.qauxv.util.HostInfo.requireMinQQVersion;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
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.hook.CommonSwitchFunctionHook;
|
||||
import io.github.qauxv.util.Initiator;
|
||||
import io.github.qauxv.util.QQVersion;
|
||||
|
||||
@FunctionHookEntry
|
||||
@UiItemAgentEntry
|
||||
@@ -55,6 +58,20 @@ public class ShowAccurateGaggedTime extends CommonSwitchFunctionHook {
|
||||
|
||||
@Override
|
||||
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,
|
||||
Reflex.findMethod(Initiator.loadClass("com.tencent.mobileqq.troop.troopgag.api.impl.TroopGagServiceImpl"), String.class,
|
||||
"gagTimeToStringCountDown", Context.class, long.class), param -> {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
package cc.ioctl.hook.chat
|
||||
|
||||
import cc.hicore.QApp.QAppUtils
|
||||
import cc.ioctl.util.hookAfterIfEnabled
|
||||
import cc.ioctl.util.hookBeforeIfEnabled
|
||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||
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.util.Initiator
|
||||
import io.github.qauxv.util.Log
|
||||
import io.github.qauxv.util.QQVersion
|
||||
import io.github.qauxv.util.SyncUtils
|
||||
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.requireMinQQVersion
|
||||
import xyz.nextalone.util.get
|
||||
|
||||
@FunctionHookEntry
|
||||
@@ -49,6 +55,8 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
||||
targets = arrayOf(
|
||||
CMessageRecordFactory,
|
||||
NContactUtils_getDiscussionMemberShowName,
|
||||
NContactUtils_getBuddyName,
|
||||
Hd_GagInfoDisclosure_Method,
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -57,6 +65,10 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
||||
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.CHAT_CATEGORY
|
||||
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 {
|
||||
val (min, hour, day) = Triple("分", "时", "天")
|
||||
val d = sec / 86400
|
||||
@@ -70,61 +82,81 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
override fun initOnce(): Boolean {
|
||||
val clzGagMgr = Initiator._TroopGagMgr()
|
||||
val method = clzGagMgr.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
|
||||
private fun addGagTipMsg(selfUin: String, troopUin: String, opUin: String, victimUin: String, victimTime: Long) {
|
||||
val opName = ContactUtils.getTroopMemberNick(troopUin, opUin)
|
||||
val victimName = ContactUtils.getTroopMemberNick(troopUin, victimUin)
|
||||
val builder = NtGrayTipHelper.NtGrayTipJsonBuilder()
|
||||
when (victimUin) {
|
||||
"0" -> {
|
||||
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, opName)
|
||||
builder.appendText(if (victimTime == 0L) "关闭了全员禁言" else "开启了全员禁言")
|
||||
}
|
||||
|
||||
selfUin -> {
|
||||
builder.appendUserItem(selfUin, "你")
|
||||
builder.appendText("被")
|
||||
builder.appendUserItem(opUin, opName)
|
||||
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
||||
}
|
||||
|
||||
else -> {
|
||||
builder.appendUserItem(victimUin, victimName)
|
||||
builder.appendText("被")
|
||||
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, opName)
|
||||
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
||||
}
|
||||
}
|
||||
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()
|
||||
when (victimUin) {
|
||||
"0" -> {
|
||||
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, "$opName")
|
||||
builder.appendText(if (victimTime == 0L) "关闭了全员禁言" else "开启了全员禁言")
|
||||
}
|
||||
NtGrayTipHelper.addLocalJsonGrayTipMsg(
|
||||
AppRuntimeHelper.getAppRuntime()!!,
|
||||
ContactCompat(ChatTypeConstants.GROUP, troopUin, ""),
|
||||
NtGrayTipHelper.createLocalJsonElement(NtGrayTipHelper.AIO_AV_GROUP_NOTICE.toLong(), builder.build().toString(), ""),
|
||||
true,
|
||||
true
|
||||
) { result, uin ->
|
||||
if (result != 0) {
|
||||
Log.e("GagInfoDisclosure error: addLocalJsonGrayTipMsg failed, result=$result, uin=$uin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selfUin -> {
|
||||
builder.appendUserItem(selfUin, "你")
|
||||
builder.appendText("被")
|
||||
builder.appendUserItem(opUin, "$opName")
|
||||
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
||||
}
|
||||
|
||||
else -> {
|
||||
builder.appendUserItem(victimUin, "$victimName")
|
||||
builder.appendText("被")
|
||||
if (opUin == selfUin) builder.appendUserItem(selfUin, "你") else builder.appendUserItem(opUin, "$opName")
|
||||
builder.appendText(if (victimTime == 0L) "解除禁言" else "禁言${getSecStr(victimTime)}")
|
||||
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)
|
||||
}
|
||||
}
|
||||
NtGrayTipHelper.addLocalJsonGrayTipMsg(
|
||||
AppRuntimeHelper.getAppRuntime()!!,
|
||||
ContactCompat(ChatTypeConstants.GROUP, troopUin, ""),
|
||||
NtGrayTipHelper.createLocalJsonElement(NtGrayTipHelper.AIO_AV_GROUP_NOTICE.toLong(), builder.build().toString(), ""),
|
||||
true,
|
||||
true
|
||||
) { result, uin ->
|
||||
if (result != 0) {
|
||||
Log.e("GagInfoDisclosure error: addLocalJsonGrayTipMsg failed, result=$result, uin=$uin")
|
||||
}
|
||||
} 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
|
||||
|
||||
@@ -32,6 +32,7 @@ import cc.ioctl.util.HookUtils
|
||||
import com.github.kyuubiran.ezxhelper.utils.isAbstract
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import io.github.duzhaokun123.hook.MessageCopyHook
|
||||
import io.github.duzhaokun123.hook.MessageTTSHook
|
||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||
import io.github.qauxv.hook.BasePersistBackgroundHook
|
||||
import io.github.qauxv.util.Initiator
|
||||
@@ -52,7 +53,8 @@ object MenuBuilderHook : BasePersistBackgroundHook() {
|
||||
MessageCopyHook,
|
||||
PicCopyToClipboard,
|
||||
MiniAppDirectJump,
|
||||
CopyMarkdown
|
||||
CopyMarkdown,
|
||||
MessageTTSHook,
|
||||
)
|
||||
|
||||
override fun initOnce(): Boolean {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
package com.xiaoniu.hook
|
||||
|
||||
import com.github.kyuubiran.ezxhelper.utils.hookBefore
|
||||
import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
|
||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||
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.util.QQVersion
|
||||
import io.github.qauxv.util.requireMinQQVersion
|
||||
import xyz.nextalone.util.clazz
|
||||
import xyz.nextalone.util.method
|
||||
import xyz.nextalone.util.set
|
||||
import xyz.nextalone.util.throwOrTrue
|
||||
|
||||
@FunctionHookEntry
|
||||
@@ -38,9 +41,18 @@ object DisableTroopFlame : CommonSwitchFunctionHook() {
|
||||
override val name = "屏蔽群火苗"
|
||||
|
||||
override fun initOnce() = throwOrTrue {
|
||||
"Lcom/tencent/mobileqq/troop/flame/api/impl/TroopFlameApiImpl;->getGroupExtFlameData(Lcom/tencent/mobileqq/data/troop/TroopInfoExt;)Ltencent/trpcprotocol/IqunFlameManageSvrPB\$GroupExtFlameData;"
|
||||
.method
|
||||
.hookReturnConstant(null)
|
||||
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;"
|
||||
.method
|
||||
.hookReturnConstant(null)
|
||||
}
|
||||
|
||||
override val uiItemLocation = FunctionEntryRouter.Locations.Simplify.CHAT_GROUP_OTHER
|
||||
|
||||
@@ -26,25 +26,37 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.view.View
|
||||
import cc.hicore.QApp.QAppUtils
|
||||
import cc.ioctl.util.HostInfo
|
||||
import cc.ioctl.util.Reflex
|
||||
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.XposedHelpers
|
||||
import io.github.duzhaokun123.hook.MessageCopyHook.TAG
|
||||
import io.github.duzhaokun123.util.TTS
|
||||
import io.github.qauxv.R
|
||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||
import io.github.qauxv.base.annotation.UiItemAgentEntry
|
||||
import io.github.qauxv.dsl.FunctionEntryRouter
|
||||
import io.github.qauxv.hook.CommonSwitchFunctionHook
|
||||
import io.github.qauxv.step.Step
|
||||
import io.github.qauxv.ui.CommonContextWrapper
|
||||
import io.github.qauxv.util.CustomMenu
|
||||
import io.github.qauxv.util.Initiator
|
||||
import io.github.qauxv.util.QQVersion
|
||||
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
|
||||
@UiItemAgentEntry
|
||||
object MessageTTSHook : CommonSwitchFunctionHook() {
|
||||
object MessageTTSHook : CommonSwitchFunctionHook(), OnMenuBuilder, DexKitFinder {
|
||||
override val name: String
|
||||
get() = "文字消息转语音 (使用系统 TTS)"
|
||||
|
||||
@@ -52,6 +64,8 @@ object MessageTTSHook : CommonSwitchFunctionHook() {
|
||||
get() = "提示失败多半是没设置系统 TTS 引擎"
|
||||
|
||||
override fun initOnce(): Boolean {
|
||||
if (QAppUtils.isQQnt()) return true
|
||||
|
||||
val cl_ArkAppItemBuilder = Initiator._TextItemBuilder()
|
||||
XposedHelpers.findAndHookMethod(
|
||||
cl_ArkAppItemBuilder, "a", Int::class.javaPrimitiveType, Context::class.java,
|
||||
@@ -106,11 +120,93 @@ object MessageTTSHook : CommonSwitchFunctionHook() {
|
||||
R.id.item_tts -> {
|
||||
TTS.speak(wc, Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: "")
|
||||
}
|
||||
|
||||
R.id.item_tts2 -> {
|
||||
val msg = Reflex.getInstanceObjectOrNull(chatMessage, "msg")?.toString() ?: ""
|
||||
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 = "") {
|
||||
if (!checkInit(wc)) return
|
||||
val binding = Tts2DialogBinding.inflate(LayoutInflater.from(wc))
|
||||
binding.etMsg.setText(text)
|
||||
binding.tvVoice.text = instance.voice?.toString() ?: "null"
|
||||
|
||||
@@ -29,8 +29,10 @@ import com.tencent.common.app.AppInterface;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import io.github.qauxv.base.annotation.DexDeobfs;
|
||||
import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi;
|
||||
import io.github.qauxv.util.HostInfo;
|
||||
import io.github.qauxv.util.Initiator;
|
||||
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.NContactUtils_getBuddyName;
|
||||
import io.github.qauxv.util.dexkit.NContactUtils_getDiscussionMemberShowName;
|
||||
@@ -59,23 +61,25 @@ public class ContactUtils {
|
||||
Objects.requireNonNull(memberUin);
|
||||
AppRuntime app = AppRuntimeHelper.getQQAppInterface();
|
||||
assert app != null;
|
||||
try {
|
||||
Object mTroopManager = ManagerHelper.getTroopManager();
|
||||
Object troopMemberInfo = Reflex.invokeVirtualDeclaredOrdinal(mTroopManager, 0, 3, false,
|
||||
troopUin, memberUin,
|
||||
String.class, String.class,
|
||||
Initiator._TroopMemberInfo());
|
||||
if (troopMemberInfo != null) {
|
||||
String troopnick = (String) XposedHelpers.getObjectField(troopMemberInfo, "troopnick");
|
||||
if (troopnick != null) {
|
||||
String ret = troopnick.replace(UNICODE_RLO, "");
|
||||
if (ret.trim().length() > 0) {
|
||||
return ret;
|
||||
if (!HostInfo.requireMinQQVersion(QQVersion.QQ_9_0_25)) {
|
||||
try {
|
||||
Object mTroopManager = ManagerHelper.getTroopManager();
|
||||
Object troopMemberInfo = Reflex.invokeVirtualDeclaredOrdinal(mTroopManager, 0, 3, false,
|
||||
troopUin, memberUin,
|
||||
String.class, String.class,
|
||||
Initiator._TroopMemberInfo());
|
||||
if (troopMemberInfo != null) {
|
||||
String troopnick = (String) XposedHelpers.getObjectField(troopMemberInfo, "troopnick");
|
||||
if (troopnick != null) {
|
||||
String ret = troopnick.replace(UNICODE_RLO, "");
|
||||
if (ret.trim().length() > 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception | LinkageError e) {
|
||||
Log.e(e);
|
||||
}
|
||||
} catch (Exception | LinkageError e) {
|
||||
Log.e(e);
|
||||
}
|
||||
try {
|
||||
String ret = getDiscussionMemberShowName(app, troopUin, memberUin);
|
||||
|
||||
@@ -125,4 +125,6 @@ public class QQVersion {
|
||||
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_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
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
hookBeforeIfEnabled(msgServiceClass.method("sendMsg")!!) { param ->
|
||||
val size = sizeMap.values.toList()[sizeIndex]
|
||||
if (size == 0) return@hookBeforeIfEnabled
|
||||
val elements = param.args[2] as ArrayList<*>
|
||||
for (element in elements) {
|
||||
val msgElement = (element as MsgElement)
|
||||
|
||||
@@ -45,6 +45,7 @@ import cc.ioctl.util.HostInfo
|
||||
import cc.ioctl.util.Reflex
|
||||
import cc.ioctl.util.hookAfterIfEnabled
|
||||
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.UiItemAgentEntry
|
||||
import io.github.qauxv.dsl.FunctionEntryRouter
|
||||
@@ -100,11 +101,11 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
||||
lateinit var buildNotification: Method
|
||||
lateinit var recentInfoBuilder: Method
|
||||
cNotificationFacade.declaredMethods.forEach {
|
||||
if (it.parameterTypes.size != 3) return@forEach
|
||||
if (it.parameterTypes[0] != cAppRuntime) return@forEach
|
||||
if (it.parameterTypes[2] == cCommonInfo) {
|
||||
if (it.paramCount < 3 || it.parameterTypes[0] != cAppRuntime) return@forEach
|
||||
if (it.paramCount == 3 && it.parameterTypes[2] == cCommonInfo) {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -131,7 +132,8 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
||||
val info = QQRecentContactInfo(pair.first)
|
||||
notificationInfoMap.remove(oldNotification.contentIntent)
|
||||
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 senderUin = info.senderUin ?: return@hookBeforeIfEnabled
|
||||
val senderIcon: IconCompat
|
||||
@@ -146,17 +148,23 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
||||
// 好友消息
|
||||
when (info.chatType) {
|
||||
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)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
groupName = info.peerName ?: return@hookBeforeIfEnabled
|
||||
groupUin = info.peerUin ?: return@hookBeforeIfEnabled
|
||||
|
||||
senderIcon = avatarHelper.getAvatar(senderUin.toString()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
||||
groupIcon = IconCompat.createFromIcon(hostInfo.application, oldNotification.getLargeIcon()) ?: IconCompat.createWithBitmap(ResUtils.loadDrawableFromAsset("face.png", context).toBitmap())
|
||||
senderIcon = avatarHelper.getAvatar(senderUin.toString()) ?: IconCompat.createWithBitmap(
|
||||
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)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Impossible
|
||||
throw Error("what the hell?")
|
||||
@@ -238,11 +246,13 @@ object MessagingStyleNotification : CommonSwitchFunctionHook(SyncUtils.PROC_ANY)
|
||||
var messageStyle = historyMessage["$channelId+$mainUin"]
|
||||
|
||||
if (messageStyle == null) {
|
||||
messageStyle = MessagingStyle(Person.Builder()
|
||||
.setName(mainName)
|
||||
.setIcon(mainIcon)
|
||||
.setKey(mainUin.toString())
|
||||
.build())
|
||||
messageStyle = MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName(mainName)
|
||||
.setIcon(mainIcon)
|
||||
.setKey(mainUin.toString())
|
||||
.build()
|
||||
)
|
||||
messageStyle.conversationTitle = mainName
|
||||
messageStyle.isGroupConversation = groupUin != null
|
||||
historyMessage["$channelId+$mainUin"] = messageStyle
|
||||
|
||||
@@ -64,7 +64,7 @@ object ChatInputHint : CommonConfigFunctionHook("na_chat_input_hint", arrayOf(NB
|
||||
|
||||
override fun initOnce(): Boolean = throwOrTrue {
|
||||
if (requireMinQQVersion(QQVersion.QQ_8_9_63)) {
|
||||
// 私聊 && QQ_9_0_50版本后的群聊
|
||||
// 私聊 && QQ9.0.35版本后的群聊
|
||||
DexKit.requireMethodFromCache(AIO_InputRootInit_QQNT).hookAfter(this) {
|
||||
it.thisObject.javaClass.declaredFields.single { it.type == EditText::class.java }.apply {
|
||||
isAccessible = true
|
||||
@@ -72,8 +72,8 @@ object ChatInputHint : CommonConfigFunctionHook("na_chat_input_hint", arrayOf(NB
|
||||
et.hint = getValue()
|
||||
}
|
||||
}
|
||||
// QQ_9_0_50版本前的群聊
|
||||
if (!requireMinQQVersion(QQVersion.QQ_9_0_50)) {
|
||||
// QQ9.0.35版本前的群聊
|
||||
if (!requireMinQQVersion(QQVersion.QQ_9_0_35)) {
|
||||
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_20) -> "Lcom/tencent/mobileqq/aio/input/b/c;->l()V"
|
||||
|
||||
Reference in New Issue
Block a user