Merge remote-tracking branch 'origin/main'
# Conflicts: # app/src/main/java/me/singleneuron/hook/AppCenterHook.kt # gradle/wrapper/gradle-wrapper.properties
This commit is contained in:
2
.github/workflows/pr_ci.yml
vendored
2
.github/workflows/pr_ci.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
|||||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v3.4.1
|
uses: gradle/gradle-build-action@v3.5.0
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
.github/workflows/push_ci.yml
vendored
2
.github/workflows/push_ci.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
|||||||
restore-keys: native-cache-
|
restore-keys: native-cache-
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v3.4.1
|
uses: gradle/gradle-build-action@v3.5.0
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -37,3 +37,6 @@
|
|||||||
path = libs/LSPlant
|
path = libs/LSPlant
|
||||||
url = https://github.com/LSPosed/LSPlant
|
url = https://github.com/LSPosed/LSPlant
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "libs/libxposed/api"]
|
||||||
|
path = libs/libxposed/api
|
||||||
|
url = https://github.com/libxposed/api
|
||||||
|
|||||||
@@ -43,10 +43,17 @@ plugins {
|
|||||||
id("build-logic.android.application")
|
id("build-logic.android.application")
|
||||||
alias(libs.plugins.changelog)
|
alias(libs.plugins.changelog)
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
|
alias(libs.plugins.protobuf)
|
||||||
alias(libs.plugins.serialization)
|
alias(libs.plugins.serialization)
|
||||||
alias(libs.plugins.aboutlibraries)
|
alias(libs.plugins.aboutlibraries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------ buildscript config ------
|
||||||
|
|
||||||
|
val buildAllAbiForDebug = false
|
||||||
|
val isNewXposedApiEnabled = true
|
||||||
|
val fullNativeDebugMode = false
|
||||||
|
|
||||||
val currentBuildUuid = UUID.randomUUID().toString()
|
val currentBuildUuid = UUID.randomUUID().toString()
|
||||||
println("Current build ID is $currentBuildUuid")
|
println("Current build ID is $currentBuildUuid")
|
||||||
|
|
||||||
@@ -58,8 +65,6 @@ if (ccacheExecutablePath != null) {
|
|||||||
println("No ccache found.")
|
println("No ccache found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fullNativeDebugMode = false
|
|
||||||
|
|
||||||
fun getSignatureKeyDigest(signConfig: SigningConfig?): String? {
|
fun getSignatureKeyDigest(signConfig: SigningConfig?): String? {
|
||||||
var key1: String? = if (signConfig != null && signConfig.storeFile != null) {
|
var key1: String? = if (signConfig != null && signConfig.storeFile != null) {
|
||||||
// extract certificate digest
|
// extract certificate digest
|
||||||
@@ -173,8 +178,10 @@ android {
|
|||||||
if (fullNativeDebugMode) {
|
if (fullNativeDebugMode) {
|
||||||
isJniDebuggable = true
|
isJniDebuggable = true
|
||||||
} else {
|
} else {
|
||||||
@Suppress("ChromeOsAbiSupport")
|
if (!buildAllAbiForDebug) {
|
||||||
abiFilters += arrayOf("arm64-v8a", "armeabi-v7a")
|
@Suppress("ChromeOsAbiSupport")
|
||||||
|
abiFilters += arrayOf("arm64-v8a", "armeabi-v7a")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isCrunchPngs = false
|
isCrunchPngs = false
|
||||||
@@ -205,12 +212,17 @@ android {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
packaging {
|
packaging {
|
||||||
resources.excludes.addAll(arrayOf(
|
// libxposed API uses META-INF/xposed
|
||||||
"META-INF/**",
|
resources.excludes.addAll(
|
||||||
"kotlin/**",
|
arrayOf(
|
||||||
"**.bin",
|
"kotlin/**",
|
||||||
"kotlin-tooling-metadata.json"
|
"**.bin",
|
||||||
))
|
"kotlin-tooling-metadata.json"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (!isNewXposedApiEnabled) {
|
||||||
|
resources.excludes.add("META-INF/xposed/**")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
@@ -247,15 +259,24 @@ kotlin {
|
|||||||
sourceSets.configureEach {
|
sourceSets.configureEach {
|
||||||
kotlin.srcDir("$buildDir/generated/ksp/$name/kotlin/")
|
kotlin.srcDir("$buildDir/generated/ksp/$name/kotlin/")
|
||||||
}
|
}
|
||||||
|
sourceSets.main {
|
||||||
|
kotlin.srcDir(File(rootDir, "libs/ezxhelper/src/main/java"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// loader
|
||||||
|
compileOnly(projects.loader.hookapi)
|
||||||
|
runtimeOnly(projects.loader.sbl)
|
||||||
|
implementation(projects.loader.startup)
|
||||||
|
// ksp
|
||||||
|
ksp(projects.libs.ksp)
|
||||||
|
// host stub
|
||||||
compileOnly(projects.libs.stub)
|
compileOnly(projects.libs.stub)
|
||||||
|
// libraries
|
||||||
implementation(projects.libs.mmkv)
|
implementation(projects.libs.mmkv)
|
||||||
implementation(projects.libs.dexkit)
|
implementation(projects.libs.dexkit)
|
||||||
implementation(projects.libs.xView)
|
implementation(projects.libs.xView)
|
||||||
ksp(projects.libs.ksp)
|
|
||||||
compileOnly(libs.xposed)
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.constraintlayout)
|
implementation(libs.androidx.constraintlayout)
|
||||||
implementation(libs.androidx.browser)
|
implementation(libs.androidx.browser)
|
||||||
@@ -269,7 +290,6 @@ dependencies {
|
|||||||
implementation(libs.colorpicker)
|
implementation(libs.colorpicker)
|
||||||
implementation(libs.material.dialogs.core)
|
implementation(libs.material.dialogs.core)
|
||||||
implementation(libs.material.dialogs.input)
|
implementation(libs.material.dialogs.input)
|
||||||
implementation(libs.ezXHelper)
|
|
||||||
// festival title
|
// festival title
|
||||||
implementation(libs.confetti)
|
implementation(libs.confetti)
|
||||||
implementation(libs.weatherView)
|
implementation(libs.weatherView)
|
||||||
@@ -281,7 +301,7 @@ dependencies {
|
|||||||
implementation(libs.byte.buddy)
|
implementation(libs.byte.buddy)
|
||||||
implementation(libs.dalvik.dx)
|
implementation(libs.dalvik.dx)
|
||||||
ksp(libs.sealedEnum.ksp)
|
ksp(libs.sealedEnum.ksp)
|
||||||
implementation(libs.google.protobuf)
|
implementation(libs.google.protobuf.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
val adb: String = androidComponents.sdkComponents.adb.get().asFile.absolutePath
|
val adb: String = androidComponents.sdkComponents.adb.get().asFile.absolutePath
|
||||||
@@ -474,3 +494,21 @@ val generateEulaAndPrivacy by tasks.registering {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see https://github.com/google/protobuf-gradle-plugin/issues/518
|
||||||
|
protobuf {
|
||||||
|
protoc {
|
||||||
|
artifact = libs.google.protobuf.protoc.get().toString()
|
||||||
|
}
|
||||||
|
plugins {
|
||||||
|
generateProtoTasks {
|
||||||
|
all().forEach {
|
||||||
|
it.builtins {
|
||||||
|
create("java") {
|
||||||
|
option("lite")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
5
app/proguard-rules.pro
vendored
5
app/proguard-rules.pro
vendored
@@ -75,6 +75,11 @@
|
|||||||
-dontwarn com.sun.jna.**
|
-dontwarn com.sun.jna.**
|
||||||
-dontwarn edu.umd.cs.findbugs.annotations.**
|
-dontwarn edu.umd.cs.findbugs.annotations.**
|
||||||
-dontwarn java.lang.instrument.**
|
-dontwarn java.lang.instrument.**
|
||||||
|
|
||||||
|
# Xposed API
|
||||||
|
-dontwarn de.robv.android.xposed.**
|
||||||
|
-dontwarn io.github.libxposed.api.**
|
||||||
|
|
||||||
-keep class com.android.dx.** {
|
-keep class com.android.dx.** {
|
||||||
*;
|
*;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
package hook
|
package hook
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
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.config.ConfigManager
|
import io.github.qauxv.config.ConfigManager
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<permission
|
<permission
|
||||||
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
|
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
|
||||||
android:protectionLevel="signature"
|
android:protectionLevel="signature"
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
android:multiArch="true"
|
android:multiArch="true"
|
||||||
android:name=".util.hookstatus.ModuleAppImpl"
|
android:name=".util.hookstatus.ModuleAppImpl"
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
|
android:description="@string/xposeddescription"
|
||||||
android:theme="@style/AppTheme.Def"
|
android:theme="@style/AppTheme.Def"
|
||||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute">
|
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute">
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
io.github.qauxv.startup.HookEntry
|
io.github.qauxv.loader.sbl.xp51.Xp51HookEntry
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ add_library(qauxv SHARED
|
|||||||
qauxv_core/SilkCodec.cc
|
qauxv_core/SilkCodec.cc
|
||||||
qauxv_core/HostInfo.cc
|
qauxv_core/HostInfo.cc
|
||||||
qauxv_core/NativeCoreBridge.cc
|
qauxv_core/NativeCoreBridge.cc
|
||||||
|
qauxv_core/linker_utils.cc
|
||||||
|
|
||||||
utils/shared_memory.cpp
|
utils/shared_memory.cpp
|
||||||
utils/auto_close_fd.cc
|
utils/auto_close_fd.cc
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace teble::v2sign {
|
|||||||
const uint32_t v2Id = 0x7109871a;
|
const uint32_t v2Id = 0x7109871a;
|
||||||
|
|
||||||
std::string getModulePath(JNIEnv *env) {
|
std::string getModulePath(JNIEnv *env) {
|
||||||
jclass cMainHook = env->FindClass("io/github/qauxv/startup/HookEntry");
|
jclass cMainHook = env->FindClass("io/github/qauxv/core/MainHook");
|
||||||
jclass cClass = env->FindClass("java/lang/Class");
|
jclass cClass = env->FindClass("java/lang/Class");
|
||||||
jmethodID mGetClassLoader = env->GetMethodID(cClass, "getClassLoader",
|
jmethodID mGetClassLoader = env->GetMethodID(cClass, "getClassLoader",
|
||||||
"()Ljava/lang/ClassLoader;");
|
"()Ljava/lang/ClassLoader;");
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
//#include <chrono>
|
//#include <chrono>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -32,7 +33,9 @@
|
|||||||
#include "utils/AobScanUtils.h"
|
#include "utils/AobScanUtils.h"
|
||||||
#include "utils/MemoryUtils.h"
|
#include "utils/MemoryUtils.h"
|
||||||
#include "utils/arch_utils.h"
|
#include "utils/arch_utils.h"
|
||||||
|
#include "utils/endian.h"
|
||||||
#include "qauxv_core/natives_utils.h"
|
#include "qauxv_core/natives_utils.h"
|
||||||
|
#include "qauxv_core/linker_utils.h"
|
||||||
|
|
||||||
#ifndef STACK_GUARD
|
#ifndef STACK_GUARD
|
||||||
// for debug purpose only
|
// for debug purpose only
|
||||||
@@ -52,251 +55,10 @@ jclass klassRevokeMsgHook = nullptr;
|
|||||||
jobject gInstanceRevokeMsgHook = nullptr;
|
jobject gInstanceRevokeMsgHook = nullptr;
|
||||||
jmethodID handleRecallSysMsgFromNtKernel = nullptr;
|
jmethodID handleRecallSysMsgFromNtKernel = nullptr;
|
||||||
|
|
||||||
uintptr_t gOffsetGetDecoderSp = 0;
|
|
||||||
|
|
||||||
uintptr_t gOffsetForTmpRev5048 = 0;
|
|
||||||
|
|
||||||
NOINLINE
|
|
||||||
uint64_t ThunkGetInt64Property(const void* thiz, int property) {
|
|
||||||
// vtable
|
|
||||||
// 4160. [[this+8]+0x58]
|
|
||||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + 8);
|
|
||||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
|
||||||
void* func = *reinterpret_cast<void**>(vtable + 0x58);
|
|
||||||
return reinterpret_cast<decltype(ThunkGetInt64Property)*>(func)(thisp8, property);
|
|
||||||
}
|
|
||||||
|
|
||||||
NOINLINE
|
|
||||||
uint32_t ThunkGetInt32Property(const void* thiz, int property) {
|
|
||||||
// vtable
|
|
||||||
// 4160. [[this+8]+0x38]
|
|
||||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + 8);
|
|
||||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
|
||||||
void* func = *reinterpret_cast<void**>(vtable + 0x38);
|
|
||||||
return reinterpret_cast<decltype(ThunkGetInt32Property)*>(func)(thisp8, property);
|
|
||||||
}
|
|
||||||
|
|
||||||
NOINLINE
|
|
||||||
std::string ThunkGetStringProperty(void* thiz, int property) {
|
|
||||||
// vtable
|
|
||||||
// 4160. [[this+8]+0x70]
|
|
||||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + 8);
|
|
||||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
|
||||||
void* func = *reinterpret_cast<void**>(vtable + 0x70);
|
|
||||||
return reinterpret_cast<decltype(ThunkGetStringProperty)*>(func)(thisp8, property);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ReturnType, uintptr_t vtableOffset, uintptr_t thizOffset, typename... ArgTypes>
|
|
||||||
requires((std::is_same_v<ReturnType, void> || std::is_integral_v<ReturnType> || std::is_pointer_v<ReturnType>)
|
|
||||||
&& ((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...))
|
|
||||||
NOINLINE
|
|
||||||
ReturnType vcall(void* thiz, ArgTypes... args) {
|
|
||||||
// vtable
|
|
||||||
// [[this+thizOff]+offsetVT]
|
|
||||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + thizOffset);
|
|
||||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
|
||||||
void* func = *reinterpret_cast<void**>(vtable + vtableOffset);
|
|
||||||
if constexpr (std::is_same_v<ReturnType, void>) {
|
|
||||||
reinterpret_cast<ReturnType(*)(void*, ArgTypes...)>(func)(thisp8, args...);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
return reinterpret_cast<ReturnType(*)(void*, ArgTypes...)>(func)(thisp8, args...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... ArgTypes>
|
|
||||||
requires(((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...))
|
|
||||||
NOINLINE
|
|
||||||
void vcall_x8_v2(void* thiz, uintptr_t vtableOffset, uintptr_t thizOffset, void* x8, ArgTypes... args) {
|
|
||||||
// vtable
|
|
||||||
// [[this+thizOff]+offsetVT]
|
|
||||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + thizOffset);
|
|
||||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
|
||||||
void* func = *reinterpret_cast<void**>(vtable + vtableOffset);
|
|
||||||
static_assert(sizeof...(args) <= 3);
|
|
||||||
std::array<void*, 3> argArray = {reinterpret_cast<void*>(args)...};
|
|
||||||
call_func_with_x8(func, x8, thisp8, argArray[0], argArray[1], argArray[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper for uintptr_t as this
|
|
||||||
template<typename ReturnType, uintptr_t vtableOffset, uintptr_t thizOffset, typename... ArgTypes>
|
|
||||||
requires((std::is_same_v<ReturnType, void> || std::is_integral_v<ReturnType> || std::is_pointer_v<ReturnType>)
|
|
||||||
&& ((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...))
|
|
||||||
static inline ReturnType vcall(uintptr_t thiz, ArgTypes... args) {
|
|
||||||
if constexpr (std::is_same_v<ReturnType, void>) {
|
|
||||||
vcall<vtableOffset, thizOffset, ArgTypes...>(reinterpret_cast<void*>(thiz), args...);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
return vcall<vtableOffset, thizOffset, ArgTypes...>(reinterpret_cast<void*>(thiz), args...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... ArgTypes> requires((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...)
|
|
||||||
static inline void vcall_x8_v2(uintptr_t thiz, uintptr_t vtableOffset, uintptr_t thizOffset, void* x8, ArgTypes... args) {
|
|
||||||
vcall_x8_v2<ArgTypes...>(reinterpret_cast<void*>(thiz), vtableOffset, thizOffset, x8, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
//void ThunkCallAPI(void* x0, uintptr_t api_caller_id, int x2, int x3, int& x4, std::string& x5) {
|
|
||||||
// // 4160. 0x00cc0750
|
|
||||||
// // "CallAPI"
|
|
||||||
// // "!!! RegisterAPIHandler Error crash: api_caller_id is empty can not use You can use GlobalAPI or set other value to api_caller_id !!!"
|
|
||||||
// auto func = reinterpret_cast<decltype(ThunkCallAPI)*>((uintptr_t) gLibkernelBaseAddress + 0x00cc0750);
|
|
||||||
// func(x0, api_caller_id, x2, x3, x4, x5);
|
|
||||||
//}
|
|
||||||
|
|
||||||
class RevokeMsgInfoAccess {
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct UnknownObjectStub16 {
|
|
||||||
void* _unk0_8;
|
|
||||||
void* _unk8_8;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void NotifyRecallSysMsgEvent(int chatType, const std::string& peerUid, const std::string& recallOpUid, const std::string& msgAuthorUid,
|
|
||||||
const std::string& toUid, uint64_t random64, uint64_t timeSeconds, uint64_t msgUid, uint64_t msgSeq, uint32_t msgClientSeq) {
|
|
||||||
JavaVM* vm = HostInfo::GetJavaVM();
|
|
||||||
if (vm == nullptr) {
|
|
||||||
LOGE("NotifyRecallSysMsgEvent fatal vm == null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (klassRevokeMsgHook == nullptr) {
|
|
||||||
LOGE("NotifyRecallSysMsgEvent fatal klassRevokeMsgHook == null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// check if current thread is attached to jvm
|
|
||||||
JNIEnv* env = nullptr;
|
|
||||||
bool isAttachedManually = false;
|
|
||||||
jint err = vm->GetEnv((void**) &env, JNI_VERSION_1_6);
|
|
||||||
if (err == JNI_EDETACHED) {
|
|
||||||
if (vm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
|
|
||||||
LOGE("NotifyRecallSysMsgEvent fatal AttachCurrentThread failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isAttachedManually = true;
|
|
||||||
} else if (env == nullptr) {
|
|
||||||
LOGE("NotifyRecallSysMsgEvent fatal GetEnv failed, err = {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// call java method
|
|
||||||
env->CallStaticVoidMethod(klassRevokeMsgHook, handleRecallSysMsgFromNtKernel,
|
|
||||||
jint(chatType), env->NewStringUTF(peerUid.c_str()), env->NewStringUTF(recallOpUid.c_str()),
|
|
||||||
env->NewStringUTF(msgAuthorUid.c_str()), env->NewStringUTF(toUid.c_str()),
|
|
||||||
jlong(random64), jlong(timeSeconds), jlong(msgUid), jlong(msgSeq), jint(msgClientSeq));
|
|
||||||
// check if exception occurred
|
|
||||||
if (env->ExceptionCheck()) {
|
|
||||||
env->ExceptionDescribe();
|
|
||||||
env->ExceptionClear();
|
|
||||||
}
|
|
||||||
// detach thread if attached manually
|
|
||||||
if (isAttachedManually) {
|
|
||||||
vm->DetachCurrentThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyRecallMsgEventForC2c(const std::string& fromUid, const std::string& toUid,
|
|
||||||
uint64_t random64, uint64_t timeSeconds,
|
|
||||||
uint64_t msgUid, uint64_t msgSeq, uint32_t msgClientSeq) {
|
|
||||||
NotifyRecallSysMsgEvent(1, fromUid, fromUid, fromUid, toUid, random64, timeSeconds, msgUid, msgSeq, msgClientSeq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyRecallMsgEventForGroup(const std::string& peerUid, const std::string& recallOpUid, const std::string& msgAuthorUid,
|
|
||||||
uint64_t random64, uint64_t timeSeconds, uint64_t msgSeq) {
|
|
||||||
NotifyRecallSysMsgEvent(2, peerUid, recallOpUid, msgAuthorUid, peerUid, random64, timeSeconds, 0, msgSeq, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void (* sOriginHandleGroupRecallSysMsgCallback)(void*, void*, void*) = nullptr;
|
void (* sOriginHandleGroupRecallSysMsgCallback)(void*, void*, void*) = nullptr;
|
||||||
|
|
||||||
void HandleGroupRecallSysMsgCallback([[maybe_unused]] void* x0, void* x1, [[maybe_unused]] void* x2, [[maybe_unused]] int x3) {
|
void HandleGroupRecallSysMsgCallback([[maybe_unused]] void* x0, void* x1, [[maybe_unused]] void* x2, [[maybe_unused]] int x3) {
|
||||||
// LOGD("HandleGroupRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", x0, x1, x2);
|
// LOGD("HandleGroupRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", x0, x1, x2);
|
||||||
// we can still do it... hitherto p3 == null... we need to decode the message manually...
|
|
||||||
uintptr_t base = (uintptr_t) gLibkernelBaseAddress;
|
|
||||||
void* pVar1 = *(void**) x1;
|
|
||||||
if ((vcall<int, 0x118, 8, int>(pVar1, 3) & 1) == 0) {
|
|
||||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! hasn't msg_common::Msg::kBody");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
void* pVar2 = *(void**) x1;
|
|
||||||
STACK_GUARD;
|
|
||||||
std::array<uint8_t, 0x100> objVar1 = {}; // actual size unknown, maybe 0x90
|
|
||||||
STACK_GUARD;
|
|
||||||
vcall_x8_v2<int>(pVar2, gOffsetForTmpRev5048, 0, &objVar1, 3);
|
|
||||||
auto pVar3 = *(void**) (objVar1.data());
|
|
||||||
if (pVar3 == nullptr) {
|
|
||||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! msg_common::Msg::kBody = null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((vcall<int, 0x118, 8, int>(pVar3, 2) & 1) == 0) {
|
|
||||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! hasn't im_msg_body::MsgBody::kBytesMsgContent");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
STACK_GUARD;
|
|
||||||
std::vector<uint8_t> msgContentBytes;
|
|
||||||
STACK_GUARD;
|
|
||||||
vcall_x8_v2<int>(pVar3, 0x78, 8, &msgContentBytes, 2);
|
|
||||||
if (msgContentBytes.size() < 8) {
|
|
||||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! im_msg_body::MsgBody::kBytesMsgContent is error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::vector<uint8_t> content = {msgContentBytes.begin() + 7, msgContentBytes.end()};
|
|
||||||
STACK_GUARD;
|
|
||||||
std::array<void*, 2> objVar3 = {}; // actual size 0x10, maybe shared_ptr, but we don't have dtor
|
|
||||||
STACK_GUARD;
|
|
||||||
call_func_with_x8((void*) (base + gOffsetGetDecoderSp), &objVar3, 0, 0, 0, 0);
|
|
||||||
void* notifyMsgBody = objVar3[0];
|
|
||||||
if ((vcall<int, 0x100, 8, std::vector<uint8_t>*>(notifyMsgBody, &content) & 1) == 0) {
|
|
||||||
LOGE("on recall group sys msg! decode kBytesMsgContent fail");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint64_t groupCode = vcall<uint64_t, 0x58, 8, int>(notifyMsgBody, 4);
|
|
||||||
if (groupCode == 0) {
|
|
||||||
LOGE("on recall group sys msg! group code is 0");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint64_t opType = vcall<uint64_t, 0x58, 8, int>(notifyMsgBody, 1);
|
|
||||||
if (opType != 7) {
|
|
||||||
LOGW("HandleGroupRecallSysMsgCallback: on recall group sys msg! no Prompt_MsgRecallReminder op_type:{}", opType);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((vcall<uint64_t, 0x118, 8, int>(notifyMsgBody, 0xb) & 1) == 0) {
|
|
||||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! no NotifyMsgBody::opt_msg_recall");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
STACK_GUARD;
|
|
||||||
std::array<void*, 2> optMsgRecall = {}; // actual size 0x10, maybe shared_ptr, but we don't have dtor
|
|
||||||
STACK_GUARD;
|
|
||||||
vcall_x8_v2<int>(notifyMsgBody, gOffsetForTmpRev5048, 0, &optMsgRecall, 0xb);
|
|
||||||
if (optMsgRecall[0] == nullptr) {
|
|
||||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! NotifyMsgBody::opt_msg_recall == null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((vcall<int, 0x118, 8, int>(optMsgRecall[0], 3) & 1) == 0) {
|
|
||||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! on recall group sys msg! no msg_infos");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::array<void*, 3> vectorResultStub = {nullptr, nullptr, nullptr};
|
|
||||||
vcall_x8_v2<int>(optMsgRecall[0], 0xf0, 8, &vectorResultStub, 3);
|
|
||||||
std::string recallOpUid = ThunkGetStringProperty(optMsgRecall[0], 1);
|
|
||||||
const auto& msgInfoList = *reinterpret_cast<const std::vector<RevokeMsgInfoAccess::UnknownObjectStub16>*>(&vectorResultStub);
|
|
||||||
if (msgInfoList.empty()) {
|
|
||||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! no any msg info");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::string peerUid = fmt::format("{}", groupCode);
|
|
||||||
for (const auto& msgInfo: msgInfoList) {
|
|
||||||
uint32_t msgSeq = ThunkGetInt32Property(msgInfo._unk0_8, 1);
|
|
||||||
uint32_t random = ThunkGetInt32Property(msgInfo._unk0_8, 3);
|
|
||||||
uint64_t time = ThunkGetInt64Property(msgInfo._unk0_8, 2);
|
|
||||||
std::string msgAuthorUid = ThunkGetStringProperty(msgInfo._unk0_8, 6);
|
|
||||||
|
|
||||||
// Unfortunately, I didn't find a way to find the origMsgSenderUid.
|
|
||||||
// The only thing we can do is to get message by msgSeq, and get senderUid from it, iff we have the message.
|
|
||||||
|
|
||||||
NotifyRecallMsgEventForGroup(peerUid, recallOpUid, msgAuthorUid, random, time, msgSeq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void (* sOriginHandleC2cRecallSysMsgCallback)(void*, void*, void*) = nullptr;
|
void (* sOriginHandleC2cRecallSysMsgCallback)(void*, void*, void*) = nullptr;
|
||||||
@@ -306,55 +68,85 @@ void HandleC2cRecallSysMsgCallback([[maybe_unused]] void* p1, [[maybe_unused]] v
|
|||||||
LOGE("HandleC2cGroupSysMsgCallback BUG !!! *p3 = null, this should not happen!!!");
|
LOGE("HandleC2cGroupSysMsgCallback BUG !!! *p3 = null, this should not happen!!!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// LOGD("HandleC2cRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", p1, p2, p3);
|
||||||
std::array<void*, 3> vectorResultStub = {nullptr, nullptr, nullptr};
|
|
||||||
|
|
||||||
void* v1 = *(void**) p3;
|
|
||||||
void** v2 = (void**) ((uintptr_t) v1 + 8);
|
|
||||||
|
|
||||||
// 4160. 0xf0
|
|
||||||
auto func = reinterpret_cast<std::array<void*, 3>(*)(void*, int)>(*(void**) ((uintptr_t) *v2 + 0xf0));
|
|
||||||
// XXX: memory leak, no dtor available
|
|
||||||
vectorResultStub = func(v2, 1);
|
|
||||||
|
|
||||||
static_assert(sizeof(std::vector<int>) == sizeof(std::array<void*, 3>), "libcxx vector size not match");
|
|
||||||
const auto& objects = *reinterpret_cast<const std::vector<RevokeMsgInfoAccess::UnknownObjectStub16>*>(&vectorResultStub);
|
|
||||||
|
|
||||||
if (!objects.empty()) {
|
|
||||||
|
|
||||||
// void* x0 = nullptr;
|
|
||||||
// uintptr_t x1 = 0;
|
|
||||||
// {
|
|
||||||
// uint8_t* param_1 = static_cast<uint8_t*>(p1) + 8;
|
|
||||||
// uint8_t* pbVar1;
|
|
||||||
// uint64_t uVar2;
|
|
||||||
// uVar2 = *(uint64_t*) (param_1 + 8);
|
|
||||||
// pbVar1 = *(uint8_t**) (param_1 + 0x10);
|
|
||||||
// if ((*param_1 & 1) == 0) {
|
|
||||||
// pbVar1 = param_1 + 1;
|
|
||||||
// uVar2 = (uint64_t) (*param_1 >> 1);
|
|
||||||
// }
|
|
||||||
// x0 = pbVar1;
|
|
||||||
// x1 = uVar2;
|
|
||||||
// }
|
|
||||||
// int tmpInt = 0x138b;
|
|
||||||
// std::string tmpString;
|
|
||||||
// ThunkCallAPI(x0, x1, 0x10, 1, tmpInt, tmpString);
|
|
||||||
|
|
||||||
for (const auto& obj: objects) {
|
|
||||||
auto fromUid = ThunkGetStringProperty(obj._unk0_8, 1);
|
|
||||||
auto toUid = ThunkGetStringProperty(obj._unk0_8, 2);
|
|
||||||
auto randomId = ThunkGetInt64Property(obj._unk0_8, 6);
|
|
||||||
auto timeSeconds = ThunkGetInt64Property(obj._unk0_8, 5);
|
|
||||||
auto msgUid = ThunkGetInt64Property(obj._unk0_8, 4);
|
|
||||||
auto msgSeq = ThunkGetInt64Property(obj._unk0_8, 0x14);
|
|
||||||
auto msgClientSeq = ThunkGetInt32Property(obj._unk0_8, 3);
|
|
||||||
NotifyRecallMsgEventForC2c(fromUid, toUid, randomId, timeSeconds, msgUid, msgSeq, msgClientSeq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nobody uses PaiYiPai, right?
|
// Nobody uses PaiYiPai, right?
|
||||||
|
bool PerformNtRecallMsgHook(uint64_t baseAddress) {
|
||||||
|
if (sIsHooked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sIsHooked = true;
|
||||||
|
gLibkernelBaseAddress = reinterpret_cast<void*>(baseAddress);
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
// RecallC2cSysMsg 09 8d 40 f8 f5 03 00 aa 21 00 80 52 f3 03 02 aa 29 ?? 40 f9
|
||||||
|
auto targetRecallC2cSysMsg = AobScanTarget()
|
||||||
|
.WithName("RecallC2cSysMsg")
|
||||||
|
.WithSequence({0x09, 0x8d, 0x40, 0xf8, 0xf5, 0x03, 0x00, 0xaa, 0x21, 0x00, 0x80, 0x52, 0xf3, 0x03, 0x02, 0xaa, 0x29, 0x00, 0x40, 0xf9})
|
||||||
|
.WithMask( {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff})
|
||||||
|
.WithStep(4)
|
||||||
|
.WithExecMemOnly(true)
|
||||||
|
.WithOffsetsForResult({-0x20, -0x24, -0x28})
|
||||||
|
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
||||||
|
|
||||||
|
// RecallGroupSysMsg 28 00 40 f9 61 00 80 52 09 8d 40 f8 29 !! 40 f9
|
||||||
|
auto targetRecallGroupSysMsg = AobScanTarget()
|
||||||
|
.WithName("RecallGroupSysMsg")
|
||||||
|
.WithSequence({0x28, 0x00, 0x40, 0xf9, 0x61, 0x00, 0x80, 0x52, 0x09, 0x8d, 0x40, 0xf8, 0x29, 0x00, 0x40, 0xf9})
|
||||||
|
.WithMask( {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff})
|
||||||
|
.WithStep(4)
|
||||||
|
.WithExecMemOnly(true)
|
||||||
|
.WithOffsetsForResult({-0x18, -0x24, -0x28})
|
||||||
|
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
||||||
|
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
std::vector<std::string> errorMsgList;
|
||||||
|
// auto start = std::chrono::steady_clock::now();
|
||||||
|
if (!SearchForAllAobScanTargets({&targetRecallC2cSysMsg, &targetRecallGroupSysMsg}, gLibkernelBaseAddress, true, errorMsgList)) {
|
||||||
|
LOGE("InitInitNtKernelRecallMsgHook SearchForAllAobScanTargets failed");
|
||||||
|
// sth went wrong
|
||||||
|
for (const auto& msg: errorMsgList) {
|
||||||
|
// report error to UI somehow
|
||||||
|
TraceError(nullptr, gInstanceRevokeMsgHook, msg);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto end = std::chrono::steady_clock::now();
|
||||||
|
// LOGD("InitInitNtKernelRecallMsgHook AobScan elapsed: {}us", std::chrono::duration_cast<std::chrono::microseconds>(end - start).count());
|
||||||
|
|
||||||
|
uint64_t offsetC2c = targetRecallC2cSysMsg.GetResultOffset();
|
||||||
|
uint64_t offsetGroup = targetRecallGroupSysMsg.GetResultOffset();
|
||||||
|
|
||||||
|
LOGD("offsetC2c={:x}, offsetGroup={:x}", offsetC2c, offsetGroup);
|
||||||
|
|
||||||
|
if (offsetC2c != 0) {
|
||||||
|
void* c2c = (void*) (baseAddress + offsetC2c);
|
||||||
|
if (CreateInlineHook(c2c, (void*) &HandleC2cRecallSysMsgCallback, (void**) &sOriginHandleC2cRecallSysMsgCallback) != 0) {
|
||||||
|
TraceErrorF(nullptr, gInstanceRevokeMsgHook,
|
||||||
|
"InitInitNtKernelRecallMsgHook failed, DobbyHook c2c failed, c2c={:p}({:x}+{:x})",
|
||||||
|
c2c, baseAddress, offsetC2c);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, offsetC2c == 0");
|
||||||
|
}
|
||||||
|
if (offsetGroup != 0) {
|
||||||
|
void* group = (void*) (baseAddress + offsetGroup);
|
||||||
|
if (CreateInlineHook(group, (void*) &HandleGroupRecallSysMsgCallback, (void**) &sOriginHandleGroupRecallSysMsgCallback) != 0) {
|
||||||
|
TraceErrorF(nullptr, gInstanceRevokeMsgHook,
|
||||||
|
"InitInitNtKernelRecallMsgHook failed, DobbyHook group failed, group={:p}({:x}+{:x})",
|
||||||
|
group, baseAddress, offsetGroup);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, offsetGroup == 0");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool InitInitNtKernelRecallMsgHook() {
|
bool InitInitNtKernelRecallMsgHook() {
|
||||||
using namespace utils;
|
using namespace utils;
|
||||||
@@ -362,137 +154,7 @@ bool InitInitNtKernelRecallMsgHook() {
|
|||||||
LOGW("InitInitNtKernelRecallMsgHook failed, already hooked");
|
LOGW("InitInitNtKernelRecallMsgHook failed, already hooked");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto fnHookProc = [](uint64_t baseAddress) {
|
auto fnHookProc = &PerformNtRecallMsgHook;
|
||||||
if (sIsHooked) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sIsHooked = true;
|
|
||||||
gLibkernelBaseAddress = reinterpret_cast<void*>(baseAddress);
|
|
||||||
// RecallC2cSysMsg 09 8d 40 f8 f5 03 00 aa 21 00 80 52 f3 03 02 aa 29 8d 40 f9
|
|
||||||
auto targetRecallC2cSysMsg = AobScanTarget()
|
|
||||||
.WithName("RecallC2cSysMsg")
|
|
||||||
.WithSequence({0x09, 0x8d, 0x40, 0xf8, 0xf5, 0x03, 0x00, 0xaa, 0x21, 0x00, 0x80, 0x52, 0xf3, 0x03, 0x02, 0xaa, 0x29, 0x8d, 0x40, 0xf9})
|
|
||||||
.WithStep(4)
|
|
||||||
.WithExecMemOnly(true)
|
|
||||||
.WithOffsetsForResult({-0x20, -0x24, -0x28})
|
|
||||||
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
|
||||||
|
|
||||||
// RecallGroupSysMsg 28 00 40 f9 61 00 80 52 09 8d 40 f8 29 8d 40 f9
|
|
||||||
auto targetRecallGroupSysMsg = AobScanTarget()
|
|
||||||
.WithName("RecallGroupSysMsg")
|
|
||||||
.WithSequence({0x28, 0x00, 0x40, 0xf9, 0x61, 0x00, 0x80, 0x52, 0x09, 0x8d, 0x40, 0xf8, 0x29, 0x8d, 0x40, 0xf9})
|
|
||||||
.WithStep(4)
|
|
||||||
.WithExecMemOnly(true)
|
|
||||||
.WithOffsetsForResult({-0x18, -0x24, -0x28})
|
|
||||||
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
|
||||||
|
|
||||||
// GetDecoder 3f 8d 01 f8 f4 03 00 aa 1f 10 00 f9
|
|
||||||
auto targetGetDecoder = AobScanTarget()
|
|
||||||
.WithName("GetDecoder")
|
|
||||||
.WithSequence({0x3f, 0x8d, 0x01, 0xf8, 0xf4, 0x03, 0x00, 0xaa, 0x1f, 0x10, 0x00, 0xf9})
|
|
||||||
.WithStep(4)
|
|
||||||
.WithExecMemOnly(true)
|
|
||||||
.WithOffsetsForResult({-0x78})
|
|
||||||
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
//OffsetForTmpRev5048
|
|
||||||
//61 01 80 52 mov w1,#0xb
|
|
||||||
//e0 03 ?? aa mov x0,x?
|
|
||||||
//?? 10 00 94 bl FUN_?
|
|
||||||
//?? ?? 00 36 tbz w0,#0x0,LAB_?
|
|
||||||
//?? 02 40 f9 ldr x8,[x??]
|
|
||||||
//61 01 80 52 mov w1,#0xb
|
|
||||||
//e0 03 ?? aa mov x0,x??
|
|
||||||
//09 !! 40 f9 ldr x9,[x8, #0x!!] <-- we need to find this
|
|
||||||
//e8 ?? ?? 91 add x8,sp,#0x??
|
|
||||||
//20 01 3f d6 blr x9
|
|
||||||
auto targetInstructionOffsetForTmpRev5048 = AobScanTarget()
|
|
||||||
.WithName("InstructionOffsetForTmpRev5048")
|
|
||||||
// 0x61 0x01 0x80 0x52 0xe0 0x03 0x?? 0xaa
|
|
||||||
// 0x?? 0x10 0x00 0x94 0x?? 0x?? 0x00 0x36
|
|
||||||
// 0x?? 0x02 0x40 0xf9 0x61 0x01 0x80 0x52
|
|
||||||
// 0xe0 0x03 0x?? 0xaa 0x09 0x?? 0x40 0xf9
|
|
||||||
// 0xe8 0x?? 0x?? 0x91 0x20 0x01 0x3f 0xd6
|
|
||||||
.WithSequence({0x61, 0x01, 0x80, 0x52, 0xe0, 0x03, 0x00, 0xaa,
|
|
||||||
0x00, 0x10, 0x00, 0x94, 0x00, 0x00, 0x00, 0x36,
|
|
||||||
0x00, 0x02, 0x40, 0xf9, 0x61, 0x01, 0x80, 0x52,
|
|
||||||
0xe0, 0x03, 0x00, 0xaa, 0x09, 0x00, 0x40, 0xf9,
|
|
||||||
0xe8, 0x00, 0x00, 0x91, 0x20, 0x01, 0x3f, 0xd6})
|
|
||||||
.WithMask({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
|
|
||||||
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
|
||||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
|
|
||||||
0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff})
|
|
||||||
.WithStep(4)
|
|
||||||
.WithExecMemOnly(true)
|
|
||||||
.WithOffsetsForResult({7 * 4});
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
std::vector<std::string> errorMsgList;
|
|
||||||
// auto start = std::chrono::steady_clock::now();
|
|
||||||
if (!SearchForAllAobScanTargets({&targetRecallC2cSysMsg, &targetRecallGroupSysMsg, &targetGetDecoder,
|
|
||||||
&targetInstructionOffsetForTmpRev5048},
|
|
||||||
gLibkernelBaseAddress, true, errorMsgList)) {
|
|
||||||
LOGE("InitInitNtKernelRecallMsgHook SearchForAllAobScanTargets failed");
|
|
||||||
// sth went wrong
|
|
||||||
for (const auto& msg: errorMsgList) {
|
|
||||||
// report error to UI somehow
|
|
||||||
TraceError(nullptr, gInstanceRevokeMsgHook, msg);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// auto end = std::chrono::steady_clock::now();
|
|
||||||
// LOGD("InitInitNtKernelRecallMsgHook AobScan elapsed: {}us", std::chrono::duration_cast<std::chrono::microseconds>(end - start).count());
|
|
||||||
|
|
||||||
if (auto pkg = HostInfo::GetPackageName(); pkg != "com.tencent.mobileqq") {
|
|
||||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, unexpected package name: {}", pkg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t offsetC2c = targetRecallC2cSysMsg.GetResultOffset();
|
|
||||||
uint64_t offsetGroup = targetRecallGroupSysMsg.GetResultOffset();
|
|
||||||
uint64_t offsetGetDecoder = targetGetDecoder.GetResultOffset();
|
|
||||||
uint64_t offsetInstForTmpRev5048 = targetInstructionOffsetForTmpRev5048.GetResultOffset();
|
|
||||||
|
|
||||||
uint32_t instructionForTmpRev5048 = *reinterpret_cast<uint32_t*>(
|
|
||||||
reinterpret_cast<uintptr_t>(gLibkernelBaseAddress) + offsetInstForTmpRev5048);
|
|
||||||
{
|
|
||||||
// LOGD("instructionForTmpRev5048={:08x}", instructionForTmpRev5048);
|
|
||||||
// 09 !! 40 f9 ldr x9,[x8, #0x!!]
|
|
||||||
uint32_t imm12 = ((instructionForTmpRev5048 >> 10u) & 0xfffu) << 3u;
|
|
||||||
// LOGD("imm12={:x}", imm12);
|
|
||||||
gOffsetForTmpRev5048 = imm12;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGD("offsetC2c={:x}, offsetGroup={:x}, offsetGetDecoder={:x}, offsetInstForTmpRev5048={:x}, gOffsetForTmpRev5048={:x}",
|
|
||||||
offsetC2c, offsetGroup, offsetGetDecoder, offsetInstForTmpRev5048, gOffsetForTmpRev5048);
|
|
||||||
|
|
||||||
gOffsetGetDecoderSp = offsetGetDecoder;
|
|
||||||
if (offsetC2c != 0) {
|
|
||||||
void* c2c = (void*) (baseAddress + offsetC2c);
|
|
||||||
if (CreateInlineHook(c2c, (void*) &HandleC2cRecallSysMsgCallback, (void**) &sOriginHandleC2cRecallSysMsgCallback) != 0) {
|
|
||||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook,
|
|
||||||
"InitInitNtKernelRecallMsgHook failed, DobbyHook c2c failed, c2c={:p}({:x}+{:x})",
|
|
||||||
c2c, baseAddress, offsetC2c);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, offsetC2c == 0");
|
|
||||||
}
|
|
||||||
if (offsetGroup != 0) {
|
|
||||||
void* group = (void*) (baseAddress + offsetGroup);
|
|
||||||
if (CreateInlineHook(group, (void*) &HandleGroupRecallSysMsgCallback, (void**) &sOriginHandleGroupRecallSysMsgCallback) != 0) {
|
|
||||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook,
|
|
||||||
"InitInitNtKernelRecallMsgHook failed, DobbyHook group failed, group={:p}({:x}+{:x})",
|
|
||||||
group, baseAddress, offsetGroup);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, offsetGroup == 0");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
ProcessView self;
|
ProcessView self;
|
||||||
if (int err;(err = self.readProcess(getpid())) != 0) {
|
if (int err;(err = self.readProcess(getpid())) != 0) {
|
||||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, readProcess failed: {}", err);
|
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, readProcess failed: {}", err);
|
||||||
@@ -561,7 +223,7 @@ bool InitInitNtKernelRecallMsgHook() {
|
|||||||
} // ntqq::hook
|
} // ntqq::hook
|
||||||
|
|
||||||
extern "C" JNIEXPORT jboolean JNICALL
|
extern "C" JNIEXPORT jboolean JNICALL
|
||||||
Java_cc_ioctl_hook_msg_RevokeMsgHook_nativeInitNtKernelRecallMsgHook(JNIEnv* env, jobject thiz) {
|
Java_cc_ioctl_hook_msg_RevokeMsgHook_nativeInitNtKernelRecallMsgHookV1p2(JNIEnv* env, jobject thiz) {
|
||||||
using ntqq::hook::klassRevokeMsgHook;
|
using ntqq::hook::klassRevokeMsgHook;
|
||||||
using ntqq::hook::gInstanceRevokeMsgHook;
|
using ntqq::hook::gInstanceRevokeMsgHook;
|
||||||
using ntqq::hook::handleRecallSysMsgFromNtKernel;
|
using ntqq::hook::handleRecallSysMsgFromNtKernel;
|
||||||
|
|||||||
119
app/src/main/cpp/qauxv_core/linker_utils.cc
Normal file
119
app/src/main/cpp/qauxv_core/linker_utils.cc
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
//
|
||||||
|
// Created by sulfate on 2024-07-11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "linker_utils.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <atomic>
|
||||||
|
#include <optional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <android/dlext.h>
|
||||||
|
|
||||||
|
#include "utils/Log.h"
|
||||||
|
#include "qauxv_core/HostInfo.h"
|
||||||
|
#include "utils/ProcessView.h"
|
||||||
|
#include "utils/ElfScan.h"
|
||||||
|
#include "utils/ElfView.h"
|
||||||
|
#include "utils/FileMemMap.h"
|
||||||
|
#include "utils/ThreadUtils.h"
|
||||||
|
|
||||||
|
namespace qauxv {
|
||||||
|
|
||||||
|
void* loader_android_dlopen_ext(const char* filename,
|
||||||
|
int flag,
|
||||||
|
const android_dlextinfo* extinfo,
|
||||||
|
const void* caller_addr) {
|
||||||
|
int sdk = qauxv::HostInfo::GetSdkInt();
|
||||||
|
// there is no linker namespace pre-N
|
||||||
|
if (sdk < 24) {
|
||||||
|
return android_dlopen_ext(filename, flag, extinfo);
|
||||||
|
}
|
||||||
|
static std::mutex sMutex;
|
||||||
|
std::scoped_lock lock_(sMutex);
|
||||||
|
// 1. get ld-android.so
|
||||||
|
static void* handleLoader = nullptr;
|
||||||
|
if (handleLoader == nullptr) {
|
||||||
|
handleLoader = dlopen("libdl.so", RTLD_NOW | RTLD_NOLOAD);
|
||||||
|
}
|
||||||
|
if (handleLoader == nullptr) {
|
||||||
|
// this should not happen
|
||||||
|
LOGE("loader_android_dlopen_ext: failed to find libdl.so");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// for 8.0/SDK26+, we have the famous __loader_android_dlopen_ext
|
||||||
|
static std::optional<void*> p_loader_android_dlopen_ext = std::nullopt;
|
||||||
|
if (!p_loader_android_dlopen_ext.has_value()) {
|
||||||
|
p_loader_android_dlopen_ext = dlsym(handleLoader, "__loader_android_dlopen_ext");
|
||||||
|
}
|
||||||
|
// for 7.0/7.1, use static symbol __dl__ZL10dlopen_extPKciPK17android_dlextinfoPv
|
||||||
|
if (p_loader_android_dlopen_ext.value() == nullptr) {
|
||||||
|
using utils::ElfView;
|
||||||
|
const char* soname;
|
||||||
|
// it's actually ld-android.so, not linker(64)
|
||||||
|
if constexpr (sizeof(void*) == 8) {
|
||||||
|
soname = "linker64";
|
||||||
|
} else {
|
||||||
|
soname = "linker";
|
||||||
|
}
|
||||||
|
utils::ProcessView processView;
|
||||||
|
int rc;
|
||||||
|
if ((rc = processView.readProcess(getpid())) != 0) {
|
||||||
|
LOGE("HookLoadLibrary: failed to read process, rc = {}", rc);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const void* linkerBaseAddress = nullptr;
|
||||||
|
std::string linkerPath;
|
||||||
|
for (const auto& m: processView.getModules()) {
|
||||||
|
if (m.name == soname || m.name == "ld.so" || m.name == "ld-android.so") {
|
||||||
|
linkerBaseAddress = reinterpret_cast<void*>(m.baseAddress);
|
||||||
|
linkerPath = m.path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (linkerBaseAddress == nullptr || linkerPath.empty()) {
|
||||||
|
LOGE("HookLoadLibrary: failed to find linker module");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
FileMemMap linkerFileMap;
|
||||||
|
if ((rc = linkerFileMap.mapFilePath(linkerPath.c_str())) != 0) {
|
||||||
|
LOGE("HookLoadLibrary: failed to map linker file, rc = {}", rc);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ElfView linkerElfView;
|
||||||
|
linkerElfView.AttachFileMemMapping(linkerFileMap.getAddress(), linkerFileMap.getLength());
|
||||||
|
if (!linkerElfView.IsValid()) {
|
||||||
|
LOGE("HookLoadLibrary: failed to attach linker file");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto linkerSymbolResolver = [&](const char* symbol) -> void* {
|
||||||
|
auto offset = linkerElfView.GetSymbolOffset(symbol);
|
||||||
|
if (offset == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(linkerBaseAddress) + static_cast<uintptr_t>(offset));
|
||||||
|
};
|
||||||
|
const char* sym_dlopen_ext = "__dl__ZL10dlopen_extPKciPK17android_dlextinfoPv";
|
||||||
|
p_loader_android_dlopen_ext = linkerSymbolResolver(sym_dlopen_ext);
|
||||||
|
if (p_loader_android_dlopen_ext.value() == nullptr) {
|
||||||
|
LOGE("loader_android_dlopen_ext: failed to find symbol {}", sym_dlopen_ext);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using loader_android_dlopen_ext_t = void* (*)(const char*, int, const android_dlextinfo*, const void*);
|
||||||
|
auto fn_loader_android_dlopen_ext = reinterpret_cast<loader_android_dlopen_ext_t>(p_loader_android_dlopen_ext.value());
|
||||||
|
if (fn_loader_android_dlopen_ext == nullptr) {
|
||||||
|
LOGE("loader_android_dlopen_ext: failed to find symbol");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// invoke the function
|
||||||
|
return fn_loader_android_dlopen_ext(filename, flag, extinfo, caller_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* loader_dlopen(const char* filename, int flag, const void* caller_addr) {
|
||||||
|
return loader_android_dlopen_ext(filename, flag, nullptr, caller_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
app/src/main/cpp/qauxv_core/linker_utils.h
Normal file
21
app/src/main/cpp/qauxv_core/linker_utils.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Created by sulfate on 2024-07-11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QAUXV_LINKER_UTILS_H
|
||||||
|
#define QAUXV_LINKER_UTILS_H
|
||||||
|
|
||||||
|
#include <android/dlext.h>
|
||||||
|
|
||||||
|
namespace qauxv {
|
||||||
|
|
||||||
|
void* loader_android_dlopen_ext(const char* filename,
|
||||||
|
int flag,
|
||||||
|
const android_dlextinfo* extinfo,
|
||||||
|
const void* caller_addr);
|
||||||
|
|
||||||
|
void* loader_dlopen(const char* filename, int flag, const void* caller_addr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QAUXV_LINKER_UTILS_H
|
||||||
113
app/src/main/cpp/utils/endian.h
Normal file
113
app/src/main/cpp/utils/endian.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace platform::arch::endian {
|
||||||
|
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
static constexpr bool kIsLittleEndian = true;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
static constexpr bool kIsLittleEndian = false;
|
||||||
|
#else
|
||||||
|
#error "Unknown endianness"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr bool kIsBigEndian = !kIsLittleEndian;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires(std::is_integral_v<T> && std::is_unsigned_v<T> && sizeof(T) == 2)
|
||||||
|
static constexpr T SwapEndian16(T value) {
|
||||||
|
return static_cast<T>((value >> 8) | (value << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires(std::is_integral_v<T> && std::is_unsigned_v<T> && sizeof(T) == 4)
|
||||||
|
static constexpr T SwapEndian32(T value) {
|
||||||
|
return static_cast<T>((value >> 24) | ((value & 0x00ff0000u) >> 8) |
|
||||||
|
((value & 0x0000ff00u) << 8) | (value << 24));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires(std::is_integral_v<T> && std::is_unsigned_v<T> && sizeof(T) == 8)
|
||||||
|
static constexpr T SwapEndian64(T value) {
|
||||||
|
return static_cast<T>((value >> 56) | ((value & 0x00ff000000000000ULL) >> 40) |
|
||||||
|
((value & 0x0000ff0000000000ULL) >> 24) |
|
||||||
|
((value & 0x000000ff00000000ULL) >> 8) |
|
||||||
|
((value & 0x00000000ff000000ULL) << 8) |
|
||||||
|
((value & 0x0000000000ff0000ULL) << 24) |
|
||||||
|
((value & 0x000000000000ff00ULL) << 40) | (value << 56));
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint16_t ltoh16(uint16_t value) {
|
||||||
|
return kIsLittleEndian ? value : SwapEndian16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t ltoh32(uint32_t value) {
|
||||||
|
return kIsLittleEndian ? value : SwapEndian32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t ltoh64(uint64_t value) {
|
||||||
|
return kIsLittleEndian ? value : SwapEndian64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint16_t htol16(uint16_t value) {
|
||||||
|
return kIsLittleEndian ? value : SwapEndian16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t htol32(uint32_t value) {
|
||||||
|
return kIsLittleEndian ? value : SwapEndian32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t htol64(uint64_t value) {
|
||||||
|
return kIsLittleEndian ? value : SwapEndian64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint16_t btoh16(uint16_t value) {
|
||||||
|
return kIsBigEndian ? value : SwapEndian16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t btoh32(uint32_t value) {
|
||||||
|
return kIsBigEndian ? value : SwapEndian32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t btoh64(uint64_t value) {
|
||||||
|
return kIsBigEndian ? value : SwapEndian64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint16_t htob16(uint16_t value) {
|
||||||
|
return kIsBigEndian ? value : SwapEndian16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t htob32(uint32_t value) {
|
||||||
|
return kIsBigEndian ? value : SwapEndian32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t htob64(uint64_t value) {
|
||||||
|
return kIsBigEndian ? value : SwapEndian64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint16_t ntoh16(uint16_t value) {
|
||||||
|
return btoh16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t ntoh32(uint32_t value) {
|
||||||
|
return btoh32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t ntoh64(uint64_t value) {
|
||||||
|
return btoh64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint16_t hton16(uint16_t value) {
|
||||||
|
return htob16(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t hton32(uint32_t value) {
|
||||||
|
return htob32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint64_t hton64(uint64_t value) {
|
||||||
|
return htob64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ import android.util.Log;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import cc.hicore.Env;
|
import cc.hicore.Env;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.ui.CommonContextWrapper;
|
import io.github.qauxv.ui.CommonContextWrapper;
|
||||||
import io.github.qauxv.util.Toasts;
|
import io.github.qauxv.util.Toasts;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import cc.hicore.ReflectUtil.XField;
|
|||||||
import cc.hicore.ReflectUtil.XMethod;
|
import cc.hicore.ReflectUtil.XMethod;
|
||||||
import cc.hicore.dialog.RepeaterPlusIconSettingDialog;
|
import cc.hicore.dialog.RepeaterPlusIconSettingDialog;
|
||||||
import cc.ioctl.util.LayoutHelper;
|
import cc.ioctl.util.LayoutHelper;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import io.github.qauxv.R;
|
import io.github.qauxv.R;
|
||||||
import io.github.qauxv.util.CustomMenu;
|
import io.github.qauxv.util.CustomMenu;
|
||||||
import io.github.qauxv.util.LicenseStatus;
|
import io.github.qauxv.util.LicenseStatus;
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgAttributeInfo;
|
|||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
||||||
import com.xiaoniu.util.ContextUtils;
|
import com.xiaoniu.util.ContextUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.R;
|
import io.github.qauxv.R;
|
||||||
import io.github.qauxv.base.ISwitchCellAgent;
|
import io.github.qauxv.base.ISwitchCellAgent;
|
||||||
import io.github.qauxv.base.IUiItemAgent;
|
import io.github.qauxv.base.IUiItemAgent;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
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.bridge.AppRuntimeHelper;
|
import io.github.qauxv.bridge.AppRuntimeHelper;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import androidx.annotation.NonNull;
|
|||||||
import cc.hicore.ReflectUtil.XMethod;
|
import cc.hicore.ReflectUtil.XMethod;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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;
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import androidx.annotation.NonNull;
|
|||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
|||||||
import com.tencent.qqnt.kernel.nativeinterface.PicElement;
|
import com.tencent.qqnt.kernel.nativeinterface.PicElement;
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
||||||
import com.xiaoniu.util.ContextUtils;
|
import com.xiaoniu.util.ContextUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
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;
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import cc.hicore.QApp.QAppUtils;
|
|||||||
import cc.hicore.ReflectUtil.XField;
|
import cc.hicore.ReflectUtil.XField;
|
||||||
import cc.hicore.hook.RepeaterPlus;
|
import cc.hicore.hook.RepeaterPlus;
|
||||||
import cc.hicore.hook.stickerPanel.Hooker.StickerPanelEntryHooker;
|
import cc.hicore.hook.stickerPanel.Hooker.StickerPanelEntryHooker;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.base.IDynamicHook;
|
import io.github.qauxv.base.IDynamicHook;
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
||||||
import io.github.qauxv.hook.BaseHookDispatcher;
|
import io.github.qauxv.hook.BaseHookDispatcher;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ package cc.ioctl.hook;
|
|||||||
import static android.widget.LinearLayout.LayoutParams.MATCH_PARENT;
|
import static android.widget.LinearLayout.LayoutParams.MATCH_PARENT;
|
||||||
import static android.widget.LinearLayout.LayoutParams.WRAP_CONTENT;
|
import static android.widget.LinearLayout.LayoutParams.WRAP_CONTENT;
|
||||||
import static cc.ioctl.util.LayoutHelper.dip2px;
|
import static cc.ioctl.util.LayoutHelper.dip2px;
|
||||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
import static io.github.qauxv.util.xpcompat.XposedHelpers.findAndHookMethod;
|
||||||
import static io.github.qauxv.util.Initiator.load;
|
import static io.github.qauxv.util.Initiator.load;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -42,8 +42,8 @@ import cc.ioctl.hook.friend.ShowDeletedFriendListEntry;
|
|||||||
import cc.ioctl.util.ExfriendManager;
|
import cc.ioctl.util.ExfriendManager;
|
||||||
import cc.ioctl.util.LayoutHelper;
|
import cc.ioctl.util.LayoutHelper;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
||||||
import io.github.qauxv.bridge.AppRuntimeHelper;
|
import io.github.qauxv.bridge.AppRuntimeHelper;
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ import cc.ioctl.util.HookUtils;
|
|||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.LayoutHelper;
|
import cc.ioctl.util.LayoutHelper;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.BuildConfig;
|
import io.github.qauxv.BuildConfig;
|
||||||
import io.github.qauxv.R;
|
import io.github.qauxv.R;
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import static io.github.qauxv.util.Initiator.load;
|
|||||||
import cc.ioctl.util.ExfriendManager;
|
import cc.ioctl.util.ExfriendManager;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.util.SyncUtils;
|
import io.github.qauxv.util.SyncUtils;
|
||||||
import io.github.qauxv.config.ConfigItems;
|
import io.github.qauxv.config.ConfigItems;
|
||||||
import io.github.qauxv.hook.BasePersistBackgroundHook;
|
import io.github.qauxv.hook.BasePersistBackgroundHook;
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ import cc.ioctl.util.HookUtils;
|
|||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.VASMsgBubble;
|
import com.tencent.qqnt.kernel.nativeinterface.VASMsgBubble;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Simplify;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Simplify;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import androidx.annotation.Nullable;
|
|||||||
import cc.hicore.QApp.QAppUtils;
|
import cc.hicore.QApp.QAppUtils;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.VASMsgFont;
|
import com.tencent.qqnt.kernel.nativeinterface.VASMsgFont;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Simplify;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Simplify;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import androidx.annotation.NonNull;
|
|||||||
import cc.hicore.QApp.QAppUtils;
|
import cc.hicore.QApp.QAppUtils;
|
||||||
import cc.hicore.ReflectUtil.XMethod;
|
import cc.hicore.ReflectUtil.XMethod;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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.bridge.AIOUtilsImpl;
|
import io.github.qauxv.bridge.AIOUtilsImpl;
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ package cc.ioctl.hook.chat;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Auxiliary;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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.Locations.Auxiliary;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ object GagInfoDisclosure : CommonSwitchFunctionHook(
|
|||||||
if (vMsg[4].toInt() == 12) {
|
if (vMsg[4].toInt() == 12) {
|
||||||
val selfUin = AppRuntimeHelper.getAccount()
|
val selfUin = AppRuntimeHelper.getAccount()
|
||||||
val troopUin = getLongData(vMsg, 0).toString()
|
val troopUin = getLongData(vMsg, 0).toString()
|
||||||
val opUin = getLongData(vMsg, 6).toString()
|
val opUinTmp = getLongData(vMsg, 6)
|
||||||
|
val opUin = (opUinTmp.takeIf { it > 0 } ?: (opUinTmp and 0xFFFFFFFFL)).toString()
|
||||||
val victimUinTmp = getLongData(vMsg, 16)
|
val victimUinTmp = getLongData(vMsg, 16)
|
||||||
val victimUin = (victimUinTmp.takeIf { it > 0 } ?: (victimUinTmp and 0xFFFFFFFFL)).toString()
|
val victimUin = (victimUinTmp.takeIf { it > 0 } ?: (victimUinTmp and 0xFFFFFFFFL)).toString()
|
||||||
val victimTime = getLongData(vMsg, 20)
|
val victimTime = getLongData(vMsg, 20)
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import static io.github.qauxv.util.QQVersion.QQ_8_8_11;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Auxiliary;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.fragment.FakeBatteryConfigFragment;
|
import cc.ioctl.fragment.FakeBatteryConfigFragment;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.util.SyncUtils;
|
import io.github.qauxv.util.SyncUtils;
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
||||||
import io.github.qauxv.base.ISwitchCellAgent;
|
import io.github.qauxv.base.ISwitchCellAgent;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import cc.ioctl.util.HostInfo
|
|||||||
import cc.ioctl.util.hookAfterIfEnabled
|
import cc.ioctl.util.hookAfterIfEnabled
|
||||||
import com.github.kyuubiran.ezxhelper.utils.Log
|
import com.github.kyuubiran.ezxhelper.utils.Log
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
import io.github.duzhaokun123.util.FilePicker
|
import io.github.duzhaokun123.util.FilePicker
|
||||||
import io.github.qauxv.base.IUiItemAgent
|
import io.github.qauxv.base.IUiItemAgent
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import android.view.View
|
|||||||
import cc.hicore.QApp.QAppUtils
|
import cc.hicore.QApp.QAppUtils
|
||||||
import cc.ioctl.util.hookBeforeIfEnabled
|
import cc.ioctl.util.hookBeforeIfEnabled
|
||||||
import com.github.kyuubiran.ezxhelper.utils.isPrivate
|
import com.github.kyuubiran.ezxhelper.utils.isPrivate
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
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
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ import androidx.annotation.Nullable;
|
|||||||
import cc.ioctl.dialog.RikkaBaseApkFormatDialog;
|
import cc.ioctl.dialog.RikkaBaseApkFormatDialog;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.base.IUiItemAgent;
|
import io.github.qauxv.base.IUiItemAgent;
|
||||||
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,9 +29,9 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.dialog.RikkaCustomDeviceModelDialog;
|
import cc.ioctl.dialog.RikkaCustomDeviceModelDialog;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XC_MethodReplacement;
|
import io.github.qauxv.util.xpcompat.XC_MethodReplacement;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import io.github.qauxv.base.IUiItemAgent;
|
import io.github.qauxv.base.IUiItemAgent;
|
||||||
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;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
package cc.ioctl.hook.misc
|
package cc.ioctl.hook.misc
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import io.github.qauxv.base.IDynamicHook
|
import io.github.qauxv.base.IDynamicHook
|
||||||
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
|
||||||
@@ -60,7 +60,7 @@ object NoAskContinueRecvShortVideoOrNot : BaseSwitchFunctionDecorator(), IStartA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import android.view.View
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import cc.ioctl.util.HookUtils
|
import cc.ioctl.util.HookUtils
|
||||||
import cc.ioctl.util.Reflex
|
import cc.ioctl.util.Reflex
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import io.github.qauxv.R
|
import io.github.qauxv.R
|
||||||
import io.github.qauxv.base.annotation.ComponentHookEntry
|
import io.github.qauxv.base.annotation.ComponentHookEntry
|
||||||
import io.github.qauxv.hook.BaseComponentHook
|
import io.github.qauxv.hook.BaseComponentHook
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ import androidx.core.view.inputmethod.InputConnectionCompat;
|
|||||||
import cc.hicore.message.bridge.Chat_facade_bridge;
|
import cc.hicore.message.bridge.Chat_facade_bridge;
|
||||||
import cc.ioctl.util.SendCacheUtils;
|
import cc.ioctl.util.SendCacheUtils;
|
||||||
import cc.ioctl.util.ui.FaultyDialog;
|
import cc.ioctl.util.ui.FaultyDialog;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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;
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ import cc.ioctl.util.beforeHookIfEnabled
|
|||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder
|
import com.xiaoniu.dispatcher.OnMenuBuilder
|
||||||
import com.xiaoniu.util.ContextUtils
|
import com.xiaoniu.util.ContextUtils
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
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
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ import cc.ioctl.util.HookUtils;
|
|||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import cc.ioctl.util.ui.FaultyDialog;
|
import cc.ioctl.util.ui.FaultyDialog;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
|
||||||
import de.robv.android.xposed.XposedBridge;
|
|
||||||
import io.github.qauxv.R;
|
import io.github.qauxv.R;
|
||||||
import io.github.qauxv.activity.ShadowShareFileAgentActivity;
|
import io.github.qauxv.activity.ShadowShareFileAgentActivity;
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
||||||
@@ -56,6 +54,8 @@ import io.github.qauxv.util.dexkit.DefaultFileModel;
|
|||||||
import io.github.qauxv.util.dexkit.DexKit;
|
import io.github.qauxv.util.dexkit.DexKit;
|
||||||
import io.github.qauxv.util.dexkit.DexKitTarget;
|
import io.github.qauxv.util.dexkit.DexKitTarget;
|
||||||
import io.github.qauxv.util.dexkit.FileBrowserActivity_InnerClass_onItemClick;
|
import io.github.qauxv.util.dexkit.FileBrowserActivity_InnerClass_onItemClick;
|
||||||
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@@ -112,7 +112,9 @@ public class FileShareExtHook extends CommonSwitchFunctionHook {
|
|||||||
Class<?> kFileBrowserModelBase = Initiator.loadClass("com.tencent.mobileqq.filemanager.fileviewer.model.FileBrowserModelBase");
|
Class<?> kFileBrowserModelBase = Initiator.loadClass("com.tencent.mobileqq.filemanager.fileviewer.model.FileBrowserModelBase");
|
||||||
Class<?> kDefaultFileModel = DexKit.requireClassFromCache(DefaultFileModel.INSTANCE);
|
Class<?> kDefaultFileModel = DexKit.requireClassFromCache(DefaultFileModel.INSTANCE);
|
||||||
String fileViewerAdapterClassName;
|
String fileViewerAdapterClassName;
|
||||||
if (requireMinQQVersion(QQVersion.QQ_9_0_15)) {
|
if (requireMinQQVersion(QQVersion.QQ_9_0_80)) {
|
||||||
|
fileViewerAdapterClassName = "com.tencent.mobileqq.filemanager.fileviewer.h";
|
||||||
|
} else if (requireMinQQVersion(QQVersion.QQ_9_0_15)) {
|
||||||
fileViewerAdapterClassName = "com.tencent.mobileqq.filemanager.fileviewer.g";
|
fileViewerAdapterClassName = "com.tencent.mobileqq.filemanager.fileviewer.g";
|
||||||
} else if (requireMinQQVersion(QQVersion.QQ_8_9_0)) {
|
} else if (requireMinQQVersion(QQVersion.QQ_8_9_0)) {
|
||||||
fileViewerAdapterClassName = "com.tencent.mobileqq.filemanager.fileviewer.h";
|
fileViewerAdapterClassName = "com.tencent.mobileqq.filemanager.fileviewer.h";
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import cc.hicore.QApp.QAppUtils;
|
|||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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.Locations.Auxiliary;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import cc.ioctl.util.hookBeforeIfEnabled
|
|||||||
import cc.ioctl.util.ui.FaultyDialog
|
import cc.ioctl.util.ui.FaultyDialog
|
||||||
import com.github.kyuubiran.ezxhelper.utils.hookBefore
|
import com.github.kyuubiran.ezxhelper.utils.hookBefore
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam
|
||||||
import io.github.qauxv.R
|
import io.github.qauxv.R
|
||||||
import io.github.qauxv.base.annotation.DexDeobfs
|
import io.github.qauxv.base.annotation.DexDeobfs
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry
|
import io.github.qauxv.base.annotation.FunctionHookEntry
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ import com.tencent.qphone.base.remote.FromServiceMsg;
|
|||||||
import com.tencent.qqnt.kernel.nativeinterface.PicElement;
|
import com.tencent.qqnt.kernel.nativeinterface.PicElement;
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
||||||
import com.xiaoniu.util.ContextUtils;
|
import com.xiaoniu.util.ContextUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import static cc.ioctl.util.LayoutHelper.dip2sp;
|
|||||||
import static cc.ioctl.util.LayoutHelper.newLinearLayoutParams;
|
import static cc.ioctl.util.LayoutHelper.newLinearLayoutParams;
|
||||||
import static cc.ioctl.util.Reflex.findField;
|
import static cc.ioctl.util.Reflex.findField;
|
||||||
import static cc.ioctl.util.Reflex.getFirstByType;
|
import static cc.ioctl.util.Reflex.getFirstByType;
|
||||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
import static io.github.qauxv.util.xpcompat.XposedHelpers.findAndHookMethod;
|
||||||
import static io.github.qauxv.bridge.AppRuntimeHelper.getQQAppInterface;
|
import static io.github.qauxv.bridge.AppRuntimeHelper.getQQAppInterface;
|
||||||
import static io.github.qauxv.util.Initiator._PttItemBuilder;
|
import static io.github.qauxv.util.Initiator._PttItemBuilder;
|
||||||
import static io.github.qauxv.util.Initiator.load;
|
import static io.github.qauxv.util.Initiator.load;
|
||||||
@@ -60,8 +60,8 @@ import cc.ioctl.util.Reflex;
|
|||||||
import com.tencent.qqnt.kernel.nativeinterface.PttElement;
|
import com.tencent.qqnt.kernel.nativeinterface.PttElement;
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
import com.xiaoniu.dispatcher.OnMenuBuilder;
|
||||||
import com.xiaoniu.util.ContextUtils;
|
import com.xiaoniu.util.ContextUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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;
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
package cc.ioctl.hook.msg;
|
package cc.ioctl.hook.msg;
|
||||||
|
|
||||||
import static de.robv.android.xposed.XposedHelpers.callMethod;
|
import static io.github.qauxv.util.xpcompat.XposedHelpers.callMethod;
|
||||||
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
import static io.github.qauxv.util.xpcompat.XposedHelpers.setObjectField;
|
||||||
import static io.github.qauxv.util.Initiator._C2CMessageProcessor;
|
import static io.github.qauxv.util.Initiator._C2CMessageProcessor;
|
||||||
import static io.github.qauxv.util.Initiator._QQMessageFacade;
|
import static io.github.qauxv.util.Initiator._QQMessageFacade;
|
||||||
|
|
||||||
@@ -33,12 +33,16 @@ import android.text.TextUtils;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import cc.hicore.QApp.QAppUtils;
|
import cc.hicore.QApp.QAppUtils;
|
||||||
import cc.ioctl.fragment.RevokeMsgConfigFragment;
|
import cc.ioctl.fragment.RevokeMsgConfigFragment;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord;
|
||||||
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
||||||
import io.github.qauxv.base.IUiItemAgent;
|
import io.github.qauxv.base.IUiItemAgent;
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
||||||
@@ -56,6 +60,14 @@ import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi;
|
|||||||
import io.github.qauxv.config.ConfigManager;
|
import io.github.qauxv.config.ConfigManager;
|
||||||
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
||||||
import io.github.qauxv.hook.CommonConfigFunctionHook;
|
import io.github.qauxv.hook.CommonConfigFunctionHook;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.C2CMsgRecallOuterClass;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.ContentHeadOuterClass;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.GroupMsgRecallOuterClass;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.InfoSyncPushOuterClass;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.MessageBodyOuterClass;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.MessageOuterClass;
|
||||||
|
import io.github.qauxv.proto.trpc.msg.MsgPushOuterClass;
|
||||||
|
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.QQVersion;
|
||||||
import io.github.qauxv.util.SyncUtils;
|
import io.github.qauxv.util.SyncUtils;
|
||||||
@@ -64,13 +76,19 @@ import io.github.qauxv.util.dexkit.DexKit;
|
|||||||
import io.github.qauxv.util.dexkit.DexKitTarget;
|
import io.github.qauxv.util.dexkit.DexKitTarget;
|
||||||
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;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
|
import kotlin.collections.ArraysKt;
|
||||||
import kotlin.jvm.functions.Function3;
|
import kotlin.jvm.functions.Function3;
|
||||||
import kotlin.jvm.internal.Intrinsics;
|
import kotlin.jvm.internal.Intrinsics;
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow;
|
import kotlinx.coroutines.flow.MutableStateFlow;
|
||||||
@@ -89,6 +107,8 @@ import mqq.app.AppRuntime;
|
|||||||
* 2023-06-16 Fri.12:40 Initial support for NT kernel.
|
* 2023-06-16 Fri.12:40 Initial support for NT kernel.
|
||||||
* <p>
|
* <p>
|
||||||
* 2023-07-12 Mon.23:12 Basic support for NT kernel.
|
* 2023-07-12 Mon.23:12 Basic support for NT kernel.
|
||||||
|
* <p>
|
||||||
|
* 2024-07-17 Wed.22:03 Use ProtoBuf to get recall info.
|
||||||
*/
|
*/
|
||||||
@FunctionHookEntry
|
@FunctionHookEntry
|
||||||
@UiItemAgentEntry
|
@UiItemAgentEntry
|
||||||
@@ -101,6 +121,8 @@ public class RevokeMsgHook extends CommonConfigFunctionHook {
|
|||||||
private static final String KEY_KEEP_SELF_REVOKE_MSG = "RevokeMsgHook.KEY_KEEP_SELF_REVOKE_MSG";
|
private static final String KEY_KEEP_SELF_REVOKE_MSG = "RevokeMsgHook.KEY_KEEP_SELF_REVOKE_MSG";
|
||||||
private static final String KEY_SHOW_SHMSGSEQ = "RevokeMsgHook.KEY_SHOW_SHMSGSEQ";
|
private static final String KEY_SHOW_SHMSGSEQ = "RevokeMsgHook.KEY_SHOW_SHMSGSEQ";
|
||||||
|
|
||||||
|
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||||
|
|
||||||
private RevokeMsgHook() {
|
private RevokeMsgHook() {
|
||||||
//FIXME: is MSF really necessary?
|
//FIXME: is MSF really necessary?
|
||||||
super(SyncUtils.PROC_MAIN | SyncUtils.PROC_MSF, new DexKitTarget[]{
|
super(SyncUtils.PROC_MAIN | SyncUtils.PROC_MSF, new DexKitTarget[]{
|
||||||
@@ -182,7 +204,9 @@ public class RevokeMsgHook extends CommonConfigFunctionHook {
|
|||||||
public boolean initOnce() throws Exception {
|
public boolean initOnce() throws Exception {
|
||||||
boolean isSuccess = true;
|
boolean isSuccess = true;
|
||||||
if (QAppUtils.isQQnt()) {
|
if (QAppUtils.isQQnt()) {
|
||||||
isSuccess = nativeInitNtKernelRecallMsgHook();
|
boolean p1 = nativeInitNtKernelRecallMsgHookV1p2();
|
||||||
|
boolean p2 = initNtRecallMsgHookV2();
|
||||||
|
isSuccess = p1 && p2;
|
||||||
}
|
}
|
||||||
// The method is still there, even on NT.
|
// The method is still there, even on NT.
|
||||||
// I decided to hook them as long as they are there.
|
// I decided to hook them as long as they are there.
|
||||||
@@ -216,7 +240,225 @@ public class RevokeMsgHook extends CommonConfigFunctionHook {
|
|||||||
return isSuccess;
|
return isSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native boolean nativeInitNtKernelRecallMsgHook();
|
private boolean initNtRecallMsgHookV2() throws ReflectiveOperationException {
|
||||||
|
Class<?> kIQQNTWrapperSessionProxy = Initiator.loadClass("com.tencent.qqnt.kernel.nativeinterface.IQQNTWrapperSession$CppProxy");
|
||||||
|
Method onMsfPushMethod = ArraysKt.single(kIQQNTWrapperSessionProxy.getDeclaredMethods(), method -> {
|
||||||
|
return "onMsfPush".equals(method.getName()) && (method.getParameterCount() == 3 || method.getParameterCount() == 2);
|
||||||
|
});
|
||||||
|
Class<?> kPushExtraInfo = null;
|
||||||
|
final Field transInfoMapField;
|
||||||
|
if (onMsfPushMethod.getParameterCount() == 3) {
|
||||||
|
kPushExtraInfo = onMsfPushMethod.getParameterTypes()[2];
|
||||||
|
transInfoMapField = kPushExtraInfo.getDeclaredField("transInfoMap");
|
||||||
|
transInfoMapField.setAccessible(true);
|
||||||
|
} else {
|
||||||
|
transInfoMapField = null;
|
||||||
|
}
|
||||||
|
HookUtils.hookBeforeIfEnabled(this, onMsfPushMethod, -51, param -> {
|
||||||
|
String cmd = (String) param.args[0];
|
||||||
|
if (cmd == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] protoBuf = (byte[]) param.args[1];
|
||||||
|
if (protoBuf == null) {
|
||||||
|
protoBuf = EMPTY_BYTE_ARRAY;
|
||||||
|
}
|
||||||
|
HashMap<String, byte[]> transInfoMap = null;
|
||||||
|
if (transInfoMapField != null) {
|
||||||
|
Object pushExtraInfo = param.args[2];
|
||||||
|
if (pushExtraInfo != null) {
|
||||||
|
transInfoMap = (HashMap<String, byte[]>) transInfoMapField.get(pushExtraInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMsfPushNtMethodCallback(param, cmd, protoBuf, transInfoMap);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMsfPushNtMethodCallback(@NonNull XC_MethodHook.MethodHookParam param, @NonNull String cmd,
|
||||||
|
@NonNull byte[] protoBuf, @Nullable HashMap<String, byte[]> transInfoMap) {
|
||||||
|
if ("trpc.msg.register_proxy.RegisterProxy.InfoSyncPush".equals(cmd)) {
|
||||||
|
handleRegisterProxyInfoSyncPush(param, protoBuf, transInfoMap);
|
||||||
|
} else if ("trpc.msg.olpush.OlPushService.MsgPush".equals(cmd)) {
|
||||||
|
handleOlPushServiceMsgPush(param, protoBuf, transInfoMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trpc.msg.register_proxy.RegisterProxy.InfoSyncPush
|
||||||
|
private void handleRegisterProxyInfoSyncPush(
|
||||||
|
@NonNull XC_MethodHook.MethodHookParam param,
|
||||||
|
@NonNull byte[] protoBuf,
|
||||||
|
@Nullable HashMap<String, byte[]> transInfoMap
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
InfoSyncPushOuterClass.InfoSyncPush infoSyncPush = InfoSyncPushOuterClass.InfoSyncPush.parseFrom(protoBuf);
|
||||||
|
if (!infoSyncPush.hasSyncMsgRecall()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InfoSyncPushOuterClass.InfoSyncPush.SyncMsgRecall syncMsgRecall = infoSyncPush.getSyncMsgRecall();
|
||||||
|
List<InfoSyncPushOuterClass.InfoSyncPush.SyncMsgRecall.SyncInfoBody> msgRecalls = syncMsgRecall.getBodyList();
|
||||||
|
for (InfoSyncPushOuterClass.InfoSyncPush.SyncMsgRecall.SyncInfoBody msgRecall : msgRecalls) {
|
||||||
|
String peerUid = msgRecall.getPeerUid();
|
||||||
|
long groupCode;
|
||||||
|
try {
|
||||||
|
groupCode = Long.parseLong(peerUid);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// not a group
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (groupCode == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<MessageOuterClass.Message> msgs = msgRecall.getMsgList();
|
||||||
|
for (MessageOuterClass.Message msg : msgs) {
|
||||||
|
handleCommonGroupMessageRecall(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidProtocolBufferException | ReflectiveOperationException e) {
|
||||||
|
traceError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trpc.msg.olpush.OlPushService.MsgPush
|
||||||
|
private void handleOlPushServiceMsgPush(@NonNull XC_MethodHook.MethodHookParam param,
|
||||||
|
@NonNull byte[] protoBuf, @Nullable HashMap<String, byte[]> transInfoMap) {
|
||||||
|
try {
|
||||||
|
MsgPushOuterClass.MsgPush msgPush = MsgPushOuterClass.MsgPush.parseFrom(protoBuf);
|
||||||
|
if (!msgPush.hasMessage()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageOuterClass.Message message = msgPush.getMessage();
|
||||||
|
if (!message.hasBody() || !message.hasContentHead()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ContentHeadOuterClass.ContentHead contentHead = message.getContentHead();
|
||||||
|
int type = contentHead.getType();
|
||||||
|
int subType = contentHead.getSubType();
|
||||||
|
// c2c recall: 528, 138
|
||||||
|
// group recall: 732, 17
|
||||||
|
if (type == 528 && subType == 138) {
|
||||||
|
handleMsgPushForC2cRecall(param, msgPush, message);
|
||||||
|
} else if (type == 732 && subType == 17) {
|
||||||
|
handleMsgPushForGroupRecall(param, msgPush, message);
|
||||||
|
}
|
||||||
|
} catch (InvalidProtocolBufferException | ReflectiveOperationException e) {
|
||||||
|
traceError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMsgPushForC2cRecall(
|
||||||
|
@NonNull XC_MethodHook.MethodHookParam param,
|
||||||
|
@NonNull MsgPushOuterClass.MsgPush msgPush,
|
||||||
|
@NonNull MessageOuterClass.Message message
|
||||||
|
) throws InvalidProtocolBufferException, ReflectiveOperationException {
|
||||||
|
MessageBodyOuterClass.MessageBody body = message.getBody();
|
||||||
|
if (!body.hasMsgContent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ByteString msgContent = body.getMsgContent();
|
||||||
|
C2CMsgRecallOuterClass.C2CMsgRecall msgRecall = C2CMsgRecallOuterClass.C2CMsgRecall.parseFrom(msgContent);
|
||||||
|
List<C2CMsgRecallOuterClass.C2CMsgRecall.MsgInfo> msgInfoList = msgRecall.getMsgInfosList();
|
||||||
|
String selfUid = RelationNTUinAndUidApi.getUidFromUin(AppRuntimeHelper.getAccount());
|
||||||
|
if (TextUtils.isEmpty(selfUid)) {
|
||||||
|
Log.e("handleMsgPushForC2cRecall fatal: selfUid is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (C2CMsgRecallOuterClass.C2CMsgRecall.MsgInfo msgInfo : msgInfoList) {
|
||||||
|
long msgUid = msgInfo.getMsgUid();
|
||||||
|
long msgSeq = msgInfo.getMsgSeq();
|
||||||
|
long msgClientSeq = msgInfo.getMsgClientSeq();
|
||||||
|
long timeSeconds = msgInfo.getTimestamp();
|
||||||
|
String fromUid = msgInfo.getFromUid();
|
||||||
|
String toUid = msgInfo.getToUid();
|
||||||
|
long random64 = msgInfo.getRandomId();
|
||||||
|
// from uid is always operator
|
||||||
|
String peerUid;
|
||||||
|
if (selfUid.equals(fromUid)) {
|
||||||
|
// msg is revoked by myself
|
||||||
|
peerUid = toUid;
|
||||||
|
} else {
|
||||||
|
peerUid = fromUid;
|
||||||
|
}
|
||||||
|
// invoke the handler
|
||||||
|
onRecallSysMsgForNT(ChatTypeConstants.C2C, peerUid, fromUid, fromUid, toUid, random64, timeSeconds, msgUid, msgSeq, (int) msgClientSeq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMsgPushForGroupRecall(
|
||||||
|
@NonNull XC_MethodHook.MethodHookParam param,
|
||||||
|
@NonNull MsgPushOuterClass.MsgPush msgPush,
|
||||||
|
@NonNull MessageOuterClass.Message message
|
||||||
|
) throws InvalidProtocolBufferException, ReflectiveOperationException {
|
||||||
|
handleCommonGroupMessageRecall(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCommonGroupMessageRecall(
|
||||||
|
@NonNull MessageOuterClass.Message message
|
||||||
|
) throws InvalidProtocolBufferException, ReflectiveOperationException {
|
||||||
|
String selfUid = RelationNTUinAndUidApi.getUidFromUin(AppRuntimeHelper.getAccount());
|
||||||
|
if (TextUtils.isEmpty(selfUid)) {
|
||||||
|
Log.e("handleMsgPushForC2cRecall fatal: selfUid is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// verify the message type
|
||||||
|
ContentHeadOuterClass.ContentHead contentHead = message.getContentHead();
|
||||||
|
int type = contentHead.getType();
|
||||||
|
int subType = contentHead.getSubType();
|
||||||
|
// group recall: 732, 17
|
||||||
|
if (!(type == 732 && subType == 17)) {
|
||||||
|
// not our business
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageBodyOuterClass.MessageBody body = message.getBody();
|
||||||
|
if (!body.hasMsgContent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ByteString msgContent = body.getMsgContent();
|
||||||
|
if (msgContent.size() < 8) {
|
||||||
|
Log.e("handleMsgPushForGroupRecall: msgContent size is less than 8");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// skip first 7 bytes
|
||||||
|
byte[] msgContentBytes = msgContent.toByteArray();
|
||||||
|
byte[] msgContentBytesTrimmed = new byte[msgContentBytes.length - 7];
|
||||||
|
System.arraycopy(msgContentBytes, 7, msgContentBytesTrimmed, 0, msgContentBytesTrimmed.length);
|
||||||
|
GroupMsgRecallOuterClass.GroupMsgRecall groupMsgRecall = GroupMsgRecallOuterClass.GroupMsgRecall.parseFrom(msgContentBytesTrimmed);
|
||||||
|
if (groupMsgRecall.getOpType() != 7) {
|
||||||
|
Log.w("handleMsgPushForGroupRecall: on recall group sys msg! no Prompt_MsgRecallReminder op_type: " + groupMsgRecall.getOpType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (groupMsgRecall.getGroupCode() == 0) {
|
||||||
|
Log.e("handleMsgPushForGroupRecall: groupMsgRecall has no groupCode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String groupCodeText = String.valueOf(groupMsgRecall.getGroupCode());
|
||||||
|
if (!groupMsgRecall.hasMsgRecall()) {
|
||||||
|
Log.e("handleMsgPushForGroupRecall: groupMsgRecall has no MsgRecall");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GroupMsgRecallOuterClass.GroupMsgRecall.MsgRecallInfo groupMsgRecallInfo = groupMsgRecall.getMsgRecall();
|
||||||
|
String operatorUid = groupMsgRecallInfo.getOperatorUid();
|
||||||
|
List<GroupMsgRecallOuterClass.GroupMsgRecall.MsgRecallInfo.MsgInfo> msgs = groupMsgRecallInfo.getMsgInfosList();
|
||||||
|
for (GroupMsgRecallOuterClass.GroupMsgRecall.MsgRecallInfo.MsgInfo msgInfo : msgs) {
|
||||||
|
long msgSeq = msgInfo.getMsgSeq();
|
||||||
|
long timeSeconds = msgInfo.getTimestamp();
|
||||||
|
String authorUid = msgInfo.getMsgAuthorUid();
|
||||||
|
long random64 = msgInfo.getRandomId();
|
||||||
|
|
||||||
|
// Log.d("handleMsgPushForGroupRecall: groupCode=" + groupCodeText + ", operatorUid=" + operatorUid
|
||||||
|
// + ", authorUid=" + authorUid + ", random64=" + random64 + ", timeSeconds=" + timeSeconds
|
||||||
|
// + ", msgSeq=" + msgSeq);
|
||||||
|
|
||||||
|
// invoke the handler
|
||||||
|
onRecallSysMsgForNT(ChatTypeConstants.GROUP, groupCodeText, operatorUid, authorUid, groupCodeText, random64, timeSeconds, 0, msgSeq, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String b64encode(byte[] data) {
|
||||||
|
return android.util.Base64.encodeToString(data, android.util.Base64.NO_WRAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
private native boolean nativeInitNtKernelRecallMsgHookV1p2();
|
||||||
|
|
||||||
private void onRevokeMsgLegacy(Object revokeMsgInfo) throws Exception {
|
private void onRevokeMsgLegacy(Object revokeMsgInfo) throws Exception {
|
||||||
RevokeMsgInfoImpl info = new RevokeMsgInfoImpl((Parcelable) revokeMsgInfo);
|
RevokeMsgInfoImpl info = new RevokeMsgInfoImpl((Parcelable) revokeMsgInfo);
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ import cc.ioctl.util.HookUtils;
|
|||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import cc.ioctl.util.ui.FaultyDialog;
|
import cc.ioctl.util.ui.FaultyDialog;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.R;
|
import io.github.qauxv.R;
|
||||||
import io.github.qauxv.activity.ShadowShareFileAgentActivity;
|
import io.github.qauxv.activity.ShadowShareFileAgentActivity;
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
||||||
|
|||||||
@@ -28,17 +28,20 @@ import cc.ioctl.util.HookUtils.BeforeAndAfterHookedMethod
|
|||||||
import cc.ioctl.util.HookUtils.hookBeforeAndAfterIfEnabled
|
import cc.ioctl.util.HookUtils.hookBeforeAndAfterIfEnabled
|
||||||
import cc.ioctl.util.LayoutHelper
|
import cc.ioctl.util.LayoutHelper
|
||||||
import cc.ioctl.util.hookBeforeIfEnabled
|
import cc.ioctl.util.hookBeforeIfEnabled
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
|
import com.github.kyuubiran.ezxhelper.utils.hookAfter
|
||||||
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.util.Initiator
|
import io.github.qauxv.util.Initiator
|
||||||
import io.github.qauxv.util.QQVersion
|
import io.github.qauxv.util.QQVersion
|
||||||
|
import io.github.qauxv.util.dexkit.AIOTitleVB_updateLeftTopBack_NT
|
||||||
import io.github.qauxv.util.dexkit.CCustomWidgetUtil_updateCustomNoteTxt_NT
|
import io.github.qauxv.util.dexkit.CCustomWidgetUtil_updateCustomNoteTxt_NT
|
||||||
import io.github.qauxv.util.dexkit.DexKit
|
import io.github.qauxv.util.dexkit.DexKit
|
||||||
import io.github.qauxv.util.dexkit.NCustomWidgetUtil_updateCustomNoteTxt
|
import io.github.qauxv.util.dexkit.NCustomWidgetUtil_updateCustomNoteTxt
|
||||||
import io.github.qauxv.util.requireMinQQVersion
|
import io.github.qauxv.util.requireMinQQVersion
|
||||||
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam
|
||||||
|
import xyz.nextalone.util.get
|
||||||
import xyz.nextalone.util.throwOrTrue
|
import xyz.nextalone.util.throwOrTrue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,8 +53,9 @@ import xyz.nextalone.util.throwOrTrue
|
|||||||
@UiItemAgentEntry
|
@UiItemAgentEntry
|
||||||
object ShowMsgCount : CommonSwitchFunctionHook(
|
object ShowMsgCount : CommonSwitchFunctionHook(
|
||||||
targets = arrayOf(
|
targets = arrayOf(
|
||||||
NCustomWidgetUtil_updateCustomNoteTxt,
|
|
||||||
CCustomWidgetUtil_updateCustomNoteTxt_NT,
|
CCustomWidgetUtil_updateCustomNoteTxt_NT,
|
||||||
|
AIOTitleVB_updateLeftTopBack_NT,
|
||||||
|
NCustomWidgetUtil_updateCustomNoteTxt,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -60,8 +64,8 @@ object ShowMsgCount : CommonSwitchFunctionHook(
|
|||||||
|
|
||||||
override fun initOnce() = throwOrTrue {
|
override fun initOnce() = throwOrTrue {
|
||||||
|
|
||||||
// 群消息数量
|
|
||||||
if (requireMinQQVersion(QQVersion.QQ_9_0_8)) {
|
if (requireMinQQVersion(QQVersion.QQ_9_0_8)) {
|
||||||
|
// 群消息数量 + 群聊左上角返回消息数量
|
||||||
val clz = Initiator.loadClass("com.tencent.mobileqq.quibadge.QUIBadge")
|
val clz = Initiator.loadClass("com.tencent.mobileqq.quibadge.QUIBadge")
|
||||||
val (updateNumName, mNumName, mTextName) = if (requireMinQQVersion(QQVersion.QQ_9_0_15)) {
|
val (updateNumName, mNumName, mTextName) = if (requireMinQQVersion(QQVersion.QQ_9_0_15)) {
|
||||||
Triple("updateNum", "mNum", "mText")
|
Triple("updateNum", "mNum", "mText")
|
||||||
@@ -78,32 +82,53 @@ object ShowMsgCount : CommonSwitchFunctionHook(
|
|||||||
param.result = null
|
param.result = null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val clz = DexKit.requireClassFromCache(CCustomWidgetUtil_updateCustomNoteTxt_NT)
|
if (requireMinQQVersion(QQVersion.QQ_8_9_63)) {
|
||||||
val updateNum = clz.declaredMethods.single { method ->
|
// 群消息数量
|
||||||
val params = method.parameterTypes
|
val clz = DexKit.requireClassFromCache(CCustomWidgetUtil_updateCustomNoteTxt_NT)
|
||||||
params.size == 6 && params[0] == TextView::class.java
|
val updateNum = clz.declaredMethods.single { method ->
|
||||||
&& params[1] == Int::class.java && params[2] == Int::class.java
|
val params = method.parameterTypes
|
||||||
&& params[3] == Int::class.java && params[4] == Int::class.java
|
params.size == 6 && params[0] == TextView::class.java
|
||||||
&& params[5] == String::class.java
|
&& params[1] == Int::class.java && params[2] == Int::class.java
|
||||||
}
|
&& params[3] == Int::class.java && params[4] == Int::class.java
|
||||||
hookBeforeAndAfterIfEnabled(this, updateNum, 50, object : BeforeAndAfterHookedMethod {
|
&& params[5] == String::class.java
|
||||||
override fun beforeHookedMethod(param: MethodHookParam) {
|
|
||||||
param.args[4] = Int.MAX_VALUE
|
|
||||||
}
|
}
|
||||||
|
hookBeforeAndAfterIfEnabled(this, updateNum, 50, object : BeforeAndAfterHookedMethod {
|
||||||
|
override fun beforeHookedMethod(param: MethodHookParam) {
|
||||||
|
param.args[4] = Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
override fun afterHookedMethod(param: MethodHookParam) {
|
override fun afterHookedMethod(param: MethodHookParam) {
|
||||||
val tv = param.args[0] as TextView
|
val tv = param.args[0] as TextView
|
||||||
val count = param.args[2] as Int
|
val count = param.args[2] as Int
|
||||||
val str = count.toString()
|
val str = count.toString()
|
||||||
val lp = tv.layoutParams
|
val lp = tv.layoutParams
|
||||||
lp.width = LayoutHelper.dip2px(tv.context, (9 + 7 * str.length).toFloat())
|
lp.width = LayoutHelper.dip2px(tv.context, (9 + 7 * str.length).toFloat())
|
||||||
tv.layoutParams = lp
|
tv.layoutParams = lp
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 群聊左上角返回消息数量
|
||||||
|
DexKit.requireMethodFromCache(AIOTitleVB_updateLeftTopBack_NT).hookAfter {
|
||||||
|
if (it.args[0] is Int) {
|
||||||
|
val count = it.args[0] as Int
|
||||||
|
if (count > 0) {
|
||||||
|
val (mTitleBinding, unreadTv) = when {
|
||||||
|
requireMinQQVersion(QQVersion.QQ_9_0_0) -> Pair("e", "v")
|
||||||
|
requireMinQQVersion(QQVersion.QQ_8_9_80) -> Pair("e", "s")
|
||||||
|
requireMinQQVersion(QQVersion.QQ_8_9_70) -> Pair("e", "t")
|
||||||
|
requireMinQQVersion(QQVersion.QQ_8_9_63) -> Pair("e", "s")
|
||||||
|
else -> Pair("", "")
|
||||||
|
}
|
||||||
|
if (mTitleBinding.isNotEmpty() && unreadTv.isNotEmpty()) {
|
||||||
|
(it.thisObject.get(mTitleBinding).get(unreadTv) as TextView).text = count.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 总消息数量
|
|
||||||
if (requireMinQQVersion(QQVersion.QQ_9_0_8)) {
|
if (requireMinQQVersion(QQVersion.QQ_9_0_8)) {
|
||||||
|
// 总消息数量
|
||||||
val clz = DexKit.requireClassFromCache(NCustomWidgetUtil_updateCustomNoteTxt)
|
val clz = DexKit.requireClassFromCache(NCustomWidgetUtil_updateCustomNoteTxt)
|
||||||
val method = clz.declaredMethods.single { method ->
|
val method = clz.declaredMethods.single { method ->
|
||||||
val params = method.parameterTypes
|
val params = method.parameterTypes
|
||||||
@@ -115,6 +140,7 @@ object ShowMsgCount : CommonSwitchFunctionHook(
|
|||||||
param.args[3] = Int.MAX_VALUE
|
param.args[3] = Int.MAX_VALUE
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 总消息数量(QQ[9.0.8]之前) + 群消息数量(QQNT[8.9.63]之前)
|
||||||
val clz = DexKit.requireClassFromCache(NCustomWidgetUtil_updateCustomNoteTxt)
|
val clz = DexKit.requireClassFromCache(NCustomWidgetUtil_updateCustomNoteTxt)
|
||||||
val method = clz.declaredMethods.single { method ->
|
val method = clz.declaredMethods.single { method ->
|
||||||
val params = method.parameterTypes
|
val params = method.parameterTypes
|
||||||
@@ -136,11 +162,11 @@ object ShowMsgCount : CommonSwitchFunctionHook(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun afterHookedMethod(param: MethodHookParam) {
|
override fun afterHookedMethod(param: MethodHookParam) {
|
||||||
val tv = param.args[0] as TextView
|
(param.args[0] as TextView).apply {
|
||||||
tv.maxWidth = Int.MAX_VALUE
|
maxWidth = Int.MAX_VALUE
|
||||||
val lp = tv.layoutParams
|
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
lp.width = ViewGroup.LayoutParams.WRAP_CONTENT
|
setPadding(0, 0, 0, 0)
|
||||||
tv.layoutParams = lp
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ package cc.ioctl.hook.notification
|
|||||||
|
|
||||||
import cc.ioctl.util.Reflex
|
import cc.ioctl.util.Reflex
|
||||||
import cc.ioctl.util.msg.MessageManager
|
import cc.ioctl.util.msg.MessageManager
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
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
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import androidx.annotation.NonNull;
|
|||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Auxiliary;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary;
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
|
* https://github.com/cinit/QAuxiliary
|
||||||
|
*
|
||||||
|
* This software is an opensource software: you can redistribute it
|
||||||
|
* and/or modify it under the terms of the General Public License
|
||||||
|
* as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version as published
|
||||||
|
* by QAuxiliary contributors.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the General Public License
|
||||||
|
* along with this software.
|
||||||
|
* If not, see
|
||||||
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cc.ioctl.hook.profile
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import cc.hicore.QApp.QAppUtils
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.ArgTypes
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.Args
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.hookBefore
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.newInstance
|
||||||
|
import com.xiaoniu.util.ContextUtils
|
||||||
|
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.ui.CommonContextWrapper
|
||||||
|
import io.github.qauxv.util.Initiator
|
||||||
|
import io.github.qauxv.util.dexkit.DexKit
|
||||||
|
import io.github.qauxv.util.dexkit.RecentPopup_onClickAction
|
||||||
|
import xyz.nextalone.util.get
|
||||||
|
import xyz.nextalone.util.throwOrTrue
|
||||||
|
|
||||||
|
@FunctionHookEntry
|
||||||
|
@UiItemAgentEntry
|
||||||
|
object OpenProfileCardMenu : CommonSwitchFunctionHook(
|
||||||
|
targets = arrayOf(RecentPopup_onClickAction)
|
||||||
|
) {
|
||||||
|
override val name = "打开资料卡"
|
||||||
|
override val description = "在首页加号菜单中添加打开资料卡功能"
|
||||||
|
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.PROFILE_CATEGORY
|
||||||
|
override val isAvailable = QAppUtils.isQQnt()
|
||||||
|
|
||||||
|
private fun context() = CommonContextWrapper.createMaterialDesignContext(ContextUtils.getCurrentActivity())
|
||||||
|
|
||||||
|
override fun initOnce() = throwOrTrue {
|
||||||
|
val menuItemId = 414414
|
||||||
|
val entryMenuItem = Initiator.loadClass("com.tencent.widget.PopupMenuDialog\$MenuItem").newInstance(
|
||||||
|
Args(arrayOf(menuItemId, "打开资料卡", "打开资料卡", R.drawable.ic_item_tool_72dp)),
|
||||||
|
ArgTypes(arrayOf(Int::class.java, String::class.java, String::class.java, Int::class.java))
|
||||||
|
)!!
|
||||||
|
Initiator.loadClass("com.tencent.widget.PopupMenuDialog").getDeclaredMethod(
|
||||||
|
"conversationPlusBuild",
|
||||||
|
Activity::class.java,
|
||||||
|
List::class.java,
|
||||||
|
Initiator.loadClass("com.tencent.widget.PopupMenuDialog\$OnClickActionListener"),
|
||||||
|
Initiator.loadClass("com.tencent.widget.PopupMenuDialog\$OnDismissListener")
|
||||||
|
).hookBefore {
|
||||||
|
it.args[1] = it.args[1] as List<*> + listOf(entryMenuItem)
|
||||||
|
}
|
||||||
|
DexKit.requireMethodFromCache(RecentPopup_onClickAction).hookBefore {
|
||||||
|
if (it.args[0].get("id") == menuItemId) {
|
||||||
|
OpenProfileCard.onClick(context())
|
||||||
|
it.result = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ 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.hookBefore
|
import com.github.kyuubiran.ezxhelper.utils.hookBefore
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam
|
||||||
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
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.view.ViewGroup
|
|||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.forEachIndexed
|
import androidx.core.view.forEachIndexed
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
@@ -38,8 +39,6 @@ import com.github.kyuubiran.ezxhelper.utils.hookAfter
|
|||||||
import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
|
import com.github.kyuubiran.ezxhelper.utils.hookReturnConstant
|
||||||
import com.github.kyuubiran.ezxhelper.utils.paramCount
|
import com.github.kyuubiran.ezxhelper.utils.paramCount
|
||||||
import com.github.kyuubiran.ezxhelper.utils.setViewZeroSize
|
import com.github.kyuubiran.ezxhelper.utils.setViewZeroSize
|
||||||
import de.robv.android.xposed.XC_MethodReplacement
|
|
||||||
import de.robv.android.xposed.XposedBridge
|
|
||||||
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
|
||||||
@@ -59,6 +58,8 @@ import io.github.qauxv.util.dexkit.QQSettingMeABTestHelper_isZplanExpGroup_Old
|
|||||||
import io.github.qauxv.util.dexkit.QQ_SETTING_ME_CONFIG_CLASS
|
import io.github.qauxv.util.dexkit.QQ_SETTING_ME_CONFIG_CLASS
|
||||||
import io.github.qauxv.util.hostInfo
|
import io.github.qauxv.util.hostInfo
|
||||||
import io.github.qauxv.util.requireMinQQVersion
|
import io.github.qauxv.util.requireMinQQVersion
|
||||||
|
import io.github.qauxv.util.xpcompat.XC_MethodReplacement
|
||||||
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import xyz.nextalone.base.MultiItemDelayableHook
|
import xyz.nextalone.base.MultiItemDelayableHook
|
||||||
import xyz.nextalone.util.*
|
import xyz.nextalone.util.*
|
||||||
import java.lang.reflect.Array
|
import java.lang.reflect.Array
|
||||||
@@ -284,6 +285,19 @@ object SimplifyQQSettingMe :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QQ 9.0.80 在xml布局中固定了14个item,这里将上面步骤完成后还未初始化的item隐藏
|
||||||
|
if (requireMinQQVersion(QQVersion.QQ_9_0_80)) {
|
||||||
|
"com.tencent.mobileqq.bizParts.QQSettingMeMenuPanelPart".clazz!!.method("onInitView")!!.hookAfter { param ->
|
||||||
|
// val parent=param.thisObject.javaClass.declaredFields.first {
|
||||||
|
// it.javaClass==ViewGroup::class.java && (it.get(param.thisObject) as ViewGroup).childCount>=14
|
||||||
|
// }.get(param.thisObject) as ViewGroup
|
||||||
|
val parent = param.thisObject.get("h") as ViewGroup
|
||||||
|
parent.children.forEach {
|
||||||
|
if (!it.isClickable) it.setViewZeroSize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (requireMinQQVersion(QQVersion.QQ_9_0_0)) {
|
if (requireMinQQVersion(QQVersion.QQ_9_0_0)) {
|
||||||
// View层隐藏超级QQ秀 (到这里应该只需要处理 超级QQ秀 了
|
// View层隐藏超级QQ秀 (到这里应该只需要处理 超级QQ秀 了
|
||||||
// 9.0.20起此段代码无效果,且该版本起超级QQ秀可以在上面移除,所以不再执行
|
// 9.0.20起此段代码无效果,且该版本起超级QQ秀可以在上面移除,所以不再执行
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ package cc.ioctl.hook.troop
|
|||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import cc.ioctl.util.Reflex
|
import cc.ioctl.util.Reflex
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
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
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ package cc.ioctl.hook.ui.chat;
|
|||||||
import static io.github.qauxv.util.Initiator.load;
|
import static io.github.qauxv.util.Initiator.load;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
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.Locations.Simplify;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Simplify;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ import cc.ioctl.util.HookUtils.BeforeAndAfterHookedMethod;
|
|||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.LayoutHelper;
|
import cc.ioctl.util.LayoutHelper;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import io.github.qauxv.base.ISwitchCellAgent;
|
import io.github.qauxv.base.ISwitchCellAgent;
|
||||||
import io.github.qauxv.base.IUiItemAgent;
|
import io.github.qauxv.base.IUiItemAgent;
|
||||||
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
import io.github.qauxv.base.annotation.FunctionHookEntry;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import com.github.kyuubiran.ezxhelper.utils.findMethod
|
|||||||
import com.github.kyuubiran.ezxhelper.utils.hookAfter
|
import com.github.kyuubiran.ezxhelper.utils.hookAfter
|
||||||
import com.github.kyuubiran.ezxhelper.utils.hookAllConstructorAfter
|
import com.github.kyuubiran.ezxhelper.utils.hookAllConstructorAfter
|
||||||
import com.github.kyuubiran.ezxhelper.utils.paramCount
|
import com.github.kyuubiran.ezxhelper.utils.paramCount
|
||||||
import de.robv.android.xposed.XC_MethodReplacement
|
import io.github.qauxv.util.xpcompat.XC_MethodReplacement
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
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.config.ConfigItems
|
import io.github.qauxv.config.ConfigItems
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import android.view.View
|
|||||||
import androidx.appcompat.widget.AppCompatCheckBox
|
import androidx.appcompat.widget.AppCompatCheckBox
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
import cc.ioctl.util.HookUtils
|
import cc.ioctl.util.HookUtils
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import io.github.qauxv.base.IUiItemAgent
|
import io.github.qauxv.base.IUiItemAgent
|
||||||
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,8 +36,8 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.LayoutHelper;
|
import cc.ioctl.util.LayoutHelper;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.base.IUiItemAgent;
|
import io.github.qauxv.base.IUiItemAgent;
|
||||||
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;
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import androidx.annotation.NonNull;
|
|||||||
import cc.hicore.QApp.QAppUtils;
|
import cc.hicore.QApp.QAppUtils;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.VASMsgAvatarPendant;
|
import com.tencent.qqnt.kernel.nativeinterface.VASMsgAvatarPendant;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Simplify;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Simplify;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import com.github.kyuubiran.ezxhelper.utils.findMethod
|
|||||||
import com.github.kyuubiran.ezxhelper.utils.getObjectAs
|
import com.github.kyuubiran.ezxhelper.utils.getObjectAs
|
||||||
import com.github.kyuubiran.ezxhelper.utils.hookAfter
|
import com.github.kyuubiran.ezxhelper.utils.hookAfter
|
||||||
import com.github.kyuubiran.ezxhelper.utils.setViewZeroSize
|
import com.github.kyuubiran.ezxhelper.utils.setViewZeroSize
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
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
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ package cc.ioctl.hook.ui.title;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import de.robv.android.xposed.XC_MethodReplacement;
|
import io.github.qauxv.util.xpcompat.XC_MethodReplacement;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.Locations.Simplify;
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Simplify;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ package cc.ioctl.util;
|
|||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam;
|
||||||
import io.github.qauxv.util.Log;
|
import io.github.qauxv.util.Log;
|
||||||
import io.github.qauxv.util.dexkit.DexMethodDescriptor;
|
import io.github.qauxv.util.dexkit.DexMethodDescriptor;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
@@ -93,13 +93,46 @@ public class ExfriendManager {
|
|||||||
private boolean dirtySerializedFlag = true;
|
private boolean dirtySerializedFlag = true;
|
||||||
|
|
||||||
private static final long[] ROBOT_ENTERPRISE_UIN_ARRAY = new long[]{
|
private static final long[] ROBOT_ENTERPRISE_UIN_ARRAY = new long[]{
|
||||||
66600000L, // BabyQ
|
// 查询ROBOT信息 https://qun.qq.com/qunpro/robot/qunshare?robot_uin=66600000
|
||||||
2854196306L, // 小冰
|
66600000L, // babyQ
|
||||||
|
2854196925L, // QQ小店助手
|
||||||
|
2854202683L, // 游戏助手
|
||||||
2854204259L, // 赞噢机器人
|
2854204259L, // 赞噢机器人
|
||||||
2854196925L, // 小店助手
|
2854209338L, // 频道管理助手
|
||||||
2854211892L,
|
2854211892L, // 饭团团
|
||||||
2854202683L,
|
// 热门
|
||||||
|
3889031420L, // 庆余年 | 庆帝
|
||||||
|
3889019833L, // 鹅探长
|
||||||
|
2854208500L, // 修仙之路
|
||||||
|
2854202509L, // 饲养小猫
|
||||||
|
2854197266L, // AL_1S
|
||||||
|
2854214035L, // 心情复杂
|
||||||
|
2854196310L, // Q群管家
|
||||||
2854203763L, // 小YOYO
|
2854203763L, // 小YOYO
|
||||||
|
// 游戏
|
||||||
|
3889011373L, // 武林侠影
|
||||||
|
3889017942L, // 快说喜欢我
|
||||||
|
2854211478L, // 小念同学
|
||||||
|
2854198976L, // 小德娱乐菌
|
||||||
|
3889009909L, // 钓鱼达人
|
||||||
|
2854196306L, // 小冰
|
||||||
|
3889001741L, // 小小
|
||||||
|
// 娱乐
|
||||||
|
2854197548L, // 开心农场
|
||||||
|
3889000472L, // 麦麦子MaiBot
|
||||||
|
3889001044L, // 益智扫雷
|
||||||
|
2854207033L, // 房东人生
|
||||||
|
2854202692L, // 元梦甜橙喵
|
||||||
|
// 工具
|
||||||
|
2854203783L, // 阿罗娜小助手
|
||||||
|
2854213832L, // 小虾米
|
||||||
|
3889001607L, // 海兰德小助手
|
||||||
|
3889000871L, // 战地1小电视
|
||||||
|
2854196311L, // 王者荣耀小狐狸
|
||||||
|
2854207085L, // DNF手游-赛丽亚
|
||||||
|
2854196316L, // 和平精英-小几
|
||||||
|
2854212997L, // 机器人66
|
||||||
|
2854203945L, // 暗区突围老皮
|
||||||
};
|
};
|
||||||
|
|
||||||
private ExfriendManager(long uin) {
|
private ExfriendManager(long uin) {
|
||||||
@@ -149,14 +182,14 @@ public class ExfriendManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ConcurrentHashMap getFriendsConcurrentHashMap(Object friendsManager)
|
public static ConcurrentHashMap getFriendsConcurrentHashMap(Object friendsManager)
|
||||||
throws IllegalAccessException, NoSuchFieldException {
|
throws IllegalAccessException, NoSuchFieldException {
|
||||||
for (Field field : Initiator.load("com.tencent.mobileqq.app.FriendsManager").getDeclaredFields()) {
|
for (Field field : Initiator.load("com.tencent.mobileqq.app.FriendsManager").getDeclaredFields()) {
|
||||||
if (ConcurrentHashMap.class == field.getType()) {
|
if (ConcurrentHashMap.class == field.getType()) {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
ConcurrentHashMap concurrentHashMap = (ConcurrentHashMap) field.get(friendsManager);
|
ConcurrentHashMap concurrentHashMap = (ConcurrentHashMap) field.get(friendsManager);
|
||||||
if (concurrentHashMap != null && concurrentHashMap.size() > 0) {
|
if (concurrentHashMap != null && concurrentHashMap.size() > 0) {
|
||||||
if (concurrentHashMap.get(concurrentHashMap.keySet().toArray()[0]).getClass()
|
if (concurrentHashMap.get(concurrentHashMap.keySet().toArray()[0]).getClass()
|
||||||
== Initiator.load("com.tencent.mobileqq.data.Friends")) {
|
== Initiator.load("com.tencent.mobileqq.data.Friends")) {
|
||||||
return concurrentHashMap;
|
return concurrentHashMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -477,7 +510,7 @@ public class ExfriendManager {
|
|||||||
t.addField("_friendStatus", Table.TYPE_INT);
|
t.addField("_friendStatus", Table.TYPE_INT);
|
||||||
// 2. fill table
|
// 2. fill table
|
||||||
Iterator<Map.Entry<Integer, EventRecord>> it =/*(Iterator<Map.Entry<Long, FriendRecord>>)*/events
|
Iterator<Map.Entry<Integer, EventRecord>> it =/*(Iterator<Map.Entry<Long, FriendRecord>>)*/events
|
||||||
.entrySet().iterator();
|
.entrySet().iterator();
|
||||||
Map.Entry<Integer, EventRecord> ent;
|
Map.Entry<Integer, EventRecord> ent;
|
||||||
EventRecord ev;
|
EventRecord ev;
|
||||||
int k;
|
int k;
|
||||||
@@ -651,7 +684,7 @@ public class ExfriendManager {
|
|||||||
mConfig.putInt("unread", 0);
|
mConfig.putInt("unread", 0);
|
||||||
try {
|
try {
|
||||||
NotificationManager nm = (NotificationManager) HostInfo.getApplication()
|
NotificationManager nm = (NotificationManager) HostInfo.getApplication()
|
||||||
.getSystemService(Context.NOTIFICATION_SERVICE);
|
.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
nm.cancel(ID_EX_NOTIFY);
|
nm.cancel(ID_EX_NOTIFY);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
@@ -791,13 +824,13 @@ public class ExfriendManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Notification createNotiComp(NotificationManager nm, String ticker, String title,
|
public Notification createNotiComp(NotificationManager nm, String ticker, String title,
|
||||||
String content, long[] vibration, PendingIntent pi) {
|
String content, long[] vibration, PendingIntent pi) {
|
||||||
Application app = HostInfo.getApplication();
|
Application app = HostInfo.getApplication();
|
||||||
//Do not use NotificationCompat, NotificationCompat does NOT support setSmallIcon with Bitmap.
|
//Do not use NotificationCompat, NotificationCompat does NOT support setSmallIcon with Bitmap.
|
||||||
Notification.Builder builder;
|
Notification.Builder builder;
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||||
NotificationChannel channel = new NotificationChannel("qn_del_notify", "删好友通知",
|
NotificationChannel channel = new NotificationChannel("qn_del_notify", "删好友通知",
|
||||||
NotificationManager.IMPORTANCE_DEFAULT);
|
NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
channel.setSound(null, null);
|
channel.setSound(null, null);
|
||||||
channel.setVibrationPattern(vibration);
|
channel.setVibrationPattern(vibration);
|
||||||
nm.createNotificationChannel(channel);
|
nm.createNotificationChannel(channel);
|
||||||
@@ -825,7 +858,7 @@ public class ExfriendManager {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Reflex.invokeVirtualAny(ManagerHelper.getFriendListHandler(), true, true, boolean.class,
|
Reflex.invokeVirtualAny(ManagerHelper.getFriendListHandler(), true, true, boolean.class,
|
||||||
boolean.class, void.class);
|
boolean.class, void.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
package cc.ioctl.util;
|
package cc.ioctl.util;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.base.ITraceableDynamicHook;
|
import io.github.qauxv.base.ITraceableDynamicHook;
|
||||||
import io.github.qauxv.hook.BaseFunctionHook;
|
import io.github.qauxv.hook.BaseFunctionHook;
|
||||||
import io.github.qauxv.hook.BaseHookDispatcher;
|
import io.github.qauxv.hook.BaseHookDispatcher;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
package cc.ioctl.util
|
package cc.ioctl.util
|
||||||
|
|
||||||
import dalvik.system.BaseDexClassLoader
|
import dalvik.system.BaseDexClassLoader
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import io.github.qauxv.hook.BaseFunctionHook
|
import io.github.qauxv.hook.BaseFunctionHook
|
||||||
import io.github.qauxv.util.LicenseStatus
|
import io.github.qauxv.util.LicenseStatus
|
||||||
import java.lang.reflect.Constructor
|
import java.lang.reflect.Constructor
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ package cc.ioctl.util;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.util.Natives;
|
import io.github.qauxv.util.Natives;
|
||||||
import io.github.qauxv.util.dexkit.DexMethodDescriptor;
|
import io.github.qauxv.util.dexkit.DexMethodDescriptor;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ object ImageCustomSummary : CommonConfigFunctionHook("ImageCustomSummary", array
|
|||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun showConfigDialog(ctx: Context) {
|
private fun showConfigDialog(ctx: Context) {
|
||||||
val switchEnable = SwitchCompat(ctx).apply {
|
val switchEnable = SwitchCompat(ctx).apply {
|
||||||
isChecked = isEnabled
|
isChecked = this@ImageCustomSummary.isEnabled
|
||||||
textSize = 16f
|
textSize = 16f
|
||||||
text = "功能总开关"
|
text = "功能总开关"
|
||||||
}
|
}
|
||||||
@@ -179,6 +179,9 @@ object ImageCustomSummary : CommonConfigFunctionHook("ImageCustomSummary", array
|
|||||||
setView(rootLayout)
|
setView(rootLayout)
|
||||||
setPositiveButton("确定") { _, _ ->
|
setPositiveButton("确定") { _, _ ->
|
||||||
isEnabled = switchEnable.isChecked
|
isEnabled = switchEnable.isChecked
|
||||||
|
typePic0 = checkBoxTypePic0.isChecked
|
||||||
|
typePic1247 = checkBoxTypePic1247.isChecked
|
||||||
|
typeMarketFace = checkBoxTypeMarketFace.isChecked
|
||||||
summaryText = summaryTextEdit.text.toString()
|
summaryText = summaryTextEdit.text.toString()
|
||||||
valueState.update { if (isEnabled) "已开启" else "禁用" }
|
valueState.update { if (isEnabled) "已开启" else "禁用" }
|
||||||
}
|
}
|
||||||
@@ -191,7 +194,6 @@ object ImageCustomSummary : CommonConfigFunctionHook("ImageCustomSummary", array
|
|||||||
val sendMsgMethod = Initiator.loadClass("com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService\$CppProxy").method("sendMsg")!!
|
val sendMsgMethod = Initiator.loadClass("com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService\$CppProxy").method("sendMsg")!!
|
||||||
hookBeforeIfEnabled(sendMsgMethod) { param ->
|
hookBeforeIfEnabled(sendMsgMethod) { param ->
|
||||||
val contact = ContactCompat.fromKernelObject(param.args[1] as Serializable)
|
val contact = ContactCompat.fromKernelObject(param.args[1] as Serializable)
|
||||||
val chatType = contact.chatType
|
|
||||||
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)
|
||||||
@@ -202,9 +204,7 @@ object ImageCustomSummary : CommonConfigFunctionHook("ImageCustomSummary", array
|
|||||||
}
|
}
|
||||||
if (typePic1247 && picSubType != 0) {
|
if (typePic1247 && picSubType != 0) {
|
||||||
picElement.summary = summaryText
|
picElement.summary = summaryText
|
||||||
if (chatType != 4) { // 不是频道才修改类型, 不然会发送不出去
|
if (contact.chatType != 4) picElement.picSubType = 7
|
||||||
picElement.picSubType = 7
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msgElement.marketFaceElement?.let { marketFaceElement ->
|
msgElement.marketFaceElement?.let { marketFaceElement ->
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ package cn.lliiooll.hook
|
|||||||
|
|
||||||
import cc.ioctl.hook.notification.MessageInterception
|
import cc.ioctl.hook.notification.MessageInterception
|
||||||
import cc.ioctl.util.msg.MessageReceiver
|
import cc.ioctl.util.msg.MessageReceiver
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
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.bridge.AppRuntimeHelper
|
import io.github.qauxv.bridge.AppRuntimeHelper
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import android.view.View;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HookUtils;
|
import cc.ioctl.util.HookUtils;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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;
|
||||||
|
|||||||
@@ -30,14 +30,18 @@ import cc.ioctl.hook.msg.PicMd5Hook
|
|||||||
import cc.ioctl.hook.msg.PttForwardHook
|
import cc.ioctl.hook.msg.PttForwardHook
|
||||||
import cc.ioctl.util.HookUtils
|
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 io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import io.github.duzhaokun123.hook.MessageCopyHook
|
import io.github.duzhaokun123.hook.MessageCopyHook
|
||||||
import io.github.duzhaokun123.hook.MessageTTSHook
|
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
|
||||||
import me.hd.hook.CopyMarkdown
|
import me.hd.hook.menu.CopyMarkdown
|
||||||
|
import me.hd.hook.menu.EditTextContent
|
||||||
|
import me.hd.hook.menu.RecallMsgRecord
|
||||||
|
import me.hd.hook.menu.RepeatToImg
|
||||||
import me.ketal.hook.PicCopyToClipboard
|
import me.ketal.hook.PicCopyToClipboard
|
||||||
|
import me.qcuncle.hook.TranslateTextMsg
|
||||||
import top.xunflash.hook.MiniAppDirectJump
|
import top.xunflash.hook.MiniAppDirectJump
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
@@ -55,6 +59,10 @@ object MenuBuilderHook : BasePersistBackgroundHook() {
|
|||||||
MiniAppDirectJump,
|
MiniAppDirectJump,
|
||||||
CopyMarkdown,
|
CopyMarkdown,
|
||||||
MessageTTSHook,
|
MessageTTSHook,
|
||||||
|
EditTextContent,
|
||||||
|
TranslateTextMsg,
|
||||||
|
RecallMsgRecord,
|
||||||
|
RepeatToImg,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun initOnce(): Boolean {
|
override fun initOnce(): Boolean {
|
||||||
|
|||||||
@@ -32,23 +32,21 @@ import io.github.qauxv.hook.CommonSwitchFunctionHook
|
|||||||
import io.github.qauxv.util.QQVersion
|
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.TroopInfoCardPageABConfig
|
import io.github.qauxv.util.dexkit.TroopInfoCardPageABConfig
|
||||||
import io.github.qauxv.util.requireMinQQVersion
|
import io.github.qauxv.util.hostInfo
|
||||||
import xyz.nextalone.util.throwOrTrue
|
import xyz.nextalone.util.throwOrTrue
|
||||||
|
|
||||||
@FunctionHookEntry
|
@FunctionHookEntry
|
||||||
@UiItemAgentEntry
|
@UiItemAgentEntry
|
||||||
object DisableNewTroopInfoPage : CommonSwitchFunctionHook(arrayOf(TroopInfoCardPageABConfig)) {
|
object DisableNewTroopInfoPage : CommonSwitchFunctionHook(arrayOf(TroopInfoCardPageABConfig)) {
|
||||||
|
|
||||||
override val name = "禁用新版群资料页"
|
override val name = "禁用新版群资料页"
|
||||||
|
|
||||||
override val description = "新版群资料页功能缺失,中看不中用,遂禁用之"
|
override val description = "新版群资料页功能缺失,中看不中用,遂禁用之"
|
||||||
|
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.GROUP_CATEGORY
|
||||||
override val isAvailable = requireMinQQVersion(QQVersion.QQ_8_9_78)
|
override val isAvailable = hostInfo.versionCode in QQVersion.QQ_8_9_78..QQVersion.QQ_9_0_71
|
||||||
|
|
||||||
override fun initOnce() = throwOrTrue {
|
override fun initOnce() = throwOrTrue {
|
||||||
DexKit.requireClassFromCache(TroopInfoCardPageABConfig).findMethod {
|
DexKit.requireClassFromCache(TroopInfoCardPageABConfig).findMethod {
|
||||||
returnType == Boolean::class.java && paramCount == 0
|
returnType == Boolean::class.java && paramCount == 0
|
||||||
}.hookReturnConstant(false)
|
}.hookReturnConstant(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.GROUP_CATEGORY
|
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ package com.xiaoniu.hook
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import cc.ioctl.util.HostInfo.isQQ
|
import cc.ioctl.util.HostInfo.isQQ
|
||||||
import cc.ioctl.util.afterHookIfEnabled
|
import cc.ioctl.util.afterHookIfEnabled
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
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.Locations.Auxiliary
|
import io.github.qauxv.dsl.FunctionEntryRouter.Locations.Auxiliary
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ object TroopGroupHook : CommonSwitchFunctionHook(arrayOf(RecentPopup_onClickActi
|
|||||||
override fun initOnce() = throwOrTrue {
|
override fun initOnce() = throwOrTrue {
|
||||||
val itemClazz = "Lcom/tencent/widget/PopupMenuDialog\$MenuItem;".clazz!!
|
val itemClazz = "Lcom/tencent/widget/PopupMenuDialog\$MenuItem;".clazz!!
|
||||||
val entryItem = itemClazz.newInstance(
|
val entryItem = itemClazz.newInstance(
|
||||||
Args(arrayOf(415411, "群聊分组", "群聊分组", R.drawable.ic_troop_group)),
|
Args(arrayOf(415411, "群聊分组", "群聊分组", R.drawable.ic_item_troop_group_72dp)),
|
||||||
ArgTypes(arrayOf(Int::class.java, String::class.java, String::class.java, Int::class.java))
|
ArgTypes(arrayOf(Int::class.java, String::class.java, String::class.java, Int::class.java))
|
||||||
)!!
|
)!!
|
||||||
"Lcom/tencent/widget/PopupMenuDialog;->conversationPlusBuild(Landroid/app/Activity;Ljava/util/List;Lcom/tencent/widget/PopupMenuDialog\$OnClickActionListener;Lcom/tencent/widget/PopupMenuDialog\$OnDismissListener;)Lcom/tencent/widget/PopupMenuDialog;".method.hookBefore {
|
"Lcom/tencent/widget/PopupMenuDialog;->conversationPlusBuild(Landroid/app/Activity;Ljava/util/List;Lcom/tencent/widget/PopupMenuDialog\$OnClickActionListener;Lcom/tencent/widget/PopupMenuDialog\$OnDismissListener;)Lcom/tencent/widget/PopupMenuDialog;".method.hookBefore {
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ import cc.ioctl.util.Reflex
|
|||||||
import cc.ioctl.util.afterHookIfEnabled
|
import cc.ioctl.util.afterHookIfEnabled
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder
|
import com.xiaoniu.dispatcher.OnMenuBuilder
|
||||||
import com.xiaoniu.util.ContextUtils
|
import com.xiaoniu.util.ContextUtils
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
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
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ import cc.ioctl.util.Reflex
|
|||||||
import cc.ioctl.util.afterHookIfEnabled
|
import cc.ioctl.util.afterHookIfEnabled
|
||||||
import com.xiaoniu.dispatcher.OnMenuBuilder
|
import com.xiaoniu.dispatcher.OnMenuBuilder
|
||||||
import com.xiaoniu.util.ContextUtils
|
import com.xiaoniu.util.ContextUtils
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import de.robv.android.xposed.XposedHelpers
|
import io.github.qauxv.util.xpcompat.XposedHelpers
|
||||||
import io.github.duzhaokun123.hook.MessageCopyHook.TAG
|
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
|
||||||
@@ -132,7 +132,7 @@ object MessageTTSHook : CommonSwitchFunctionHook(), OnMenuBuilder, DexKitFinder
|
|||||||
|
|
||||||
override fun onGetMenuNt(msg: Any, componentType: String, param: XC_MethodHook.MethodHookParam) {
|
override fun onGetMenuNt(msg: Any, componentType: String, param: XC_MethodHook.MethodHookParam) {
|
||||||
if (!isEnabled) return
|
if (!isEnabled) return
|
||||||
val item = CustomMenu.createItemIconNt(msg, "TTS", 0, R.id.item_tts) {
|
val item = CustomMenu.createItemIconNt(msg, "TTS", R.drawable.ic_item_tts_72dp, R.id.item_tts) {
|
||||||
val ctx = ContextUtils.getCurrentActivity()
|
val ctx = ContextUtils.getCurrentActivity()
|
||||||
val wc = CommonContextWrapper.createAppCompatContext(ctx)
|
val wc = CommonContextWrapper.createAppCompatContext(ctx)
|
||||||
val text = try {
|
val text = try {
|
||||||
@@ -144,7 +144,7 @@ object MessageTTSHook : CommonSwitchFunctionHook(), OnMenuBuilder, DexKitFinder
|
|||||||
}
|
}
|
||||||
TTS.speak(wc, text.toString())
|
TTS.speak(wc, text.toString())
|
||||||
}
|
}
|
||||||
val item2 = CustomMenu.createItemIconNt(msg, "TTS+", 0, R.id.item_tts2) {
|
val item2 = CustomMenu.createItemIconNt(msg, "TTS+", R.drawable.ic_item_tts_plus_72dp, R.id.item_tts2) {
|
||||||
val ctx = ContextUtils.getCurrentActivity()
|
val ctx = ContextUtils.getCurrentActivity()
|
||||||
val wc = CommonContextWrapper.createAppCompatContext(ctx)
|
val wc = CommonContextWrapper.createAppCompatContext(ctx)
|
||||||
val text = try {
|
val text = try {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.view.View
|
|||||||
import cc.ioctl.util.HookUtils.hookBeforeIfEnabled
|
import cc.ioctl.util.HookUtils.hookBeforeIfEnabled
|
||||||
import cc.ioctl.util.hookBeforeIfEnabled
|
import cc.ioctl.util.hookBeforeIfEnabled
|
||||||
import com.alphi.qhmk.module.HiddenVipIconForSe
|
import com.alphi.qhmk.module.HiddenVipIconForSe
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam
|
||||||
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
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ package io.github.fusumayuki.hook
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewStub
|
import android.view.ViewStub
|
||||||
import cc.ioctl.util.HookUtils.hookBeforeIfEnabled
|
import cc.ioctl.util.HookUtils.hookBeforeIfEnabled
|
||||||
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
|
import io.github.qauxv.util.xpcompat.XC_MethodHook.MethodHookParam
|
||||||
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
|
||||||
|
|||||||
56
app/src/main/java/io/github/memory2314/hook/GuildOldStyle.kt
Normal file
56
app/src/main/java/io/github/memory2314/hook/GuildOldStyle.kt
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
|
* https://github.com/cinit/QAuxiliary
|
||||||
|
*
|
||||||
|
* This software is an opensource software: you can redistribute it
|
||||||
|
* and/or modify it under the terms of the General Public License
|
||||||
|
* as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version as published
|
||||||
|
* by QAuxiliary contributors.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the General Public License
|
||||||
|
* along with this software.
|
||||||
|
* If not, see
|
||||||
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.memory2314.hook
|
||||||
|
|
||||||
|
import cc.ioctl.util.hookBeforeIfEnabled
|
||||||
|
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.util.QQVersion
|
||||||
|
import io.github.qauxv.util.hostInfo
|
||||||
|
import io.github.qauxv.util.requireMinQQVersion
|
||||||
|
import xyz.nextalone.util.invoke
|
||||||
|
import xyz.nextalone.util.method
|
||||||
|
import xyz.nextalone.util.throwOrTrue
|
||||||
|
|
||||||
|
@FunctionHookEntry
|
||||||
|
@UiItemAgentEntry
|
||||||
|
object GuildOldStyle : CommonSwitchFunctionHook() {
|
||||||
|
override val name = "频道旧版样式"
|
||||||
|
override val description = "仅支持QQ9.0.15~9.0.73版本"
|
||||||
|
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.GUILD_CATEGORY
|
||||||
|
override val isAvailable = hostInfo.versionCode in QQVersion.QQ_9_0_15..QQVersion.QQ_9_0_73
|
||||||
|
|
||||||
|
override fun initOnce() = throwOrTrue {
|
||||||
|
if (requireMinQQVersion(QQVersion.QQ_9_0_30)) { // 9.0.30~9.0.73(之后的版本获取布局方法不存在)
|
||||||
|
hookBeforeIfEnabled("Lcom/tencent/mobileqq/guild/mainframe/GuildFragmentDelegateFrame;->getCurrentMainFragment()Lcom/tencent/mobileqq/guild/mainframe/AbsGuildMainFragment;".method) {
|
||||||
|
it.result = it.thisObject.invoke("getMainFrameFragment")
|
||||||
|
}
|
||||||
|
} else { // (第一个新版频道)9.0.15~9.0.25
|
||||||
|
hookBeforeIfEnabled("Lcom/tencent/mobileqq/guild/mainframe/GuildFragmentDelegateFrame;->s()Lcom/tencent/mobileqq/guild/mainframe/AbsGuildMainFragment;".method) {
|
||||||
|
it.result = it.thisObject.invoke("u")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
|
* https://github.com/cinit/QAuxiliary
|
||||||
|
*
|
||||||
|
* This software is an opensource software: you can redistribute it
|
||||||
|
* and/or modify it under the terms of the General Public License
|
||||||
|
* as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version as published
|
||||||
|
* by QAuxiliary contributors.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the General Public License
|
||||||
|
* along with this software.
|
||||||
|
* If not, see
|
||||||
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.memory2314.hook
|
||||||
|
|
||||||
|
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 xyz.nextalone.util.method
|
||||||
|
import xyz.nextalone.util.replace
|
||||||
|
import xyz.nextalone.util.throwOrTrue
|
||||||
|
|
||||||
|
@FunctionHookEntry
|
||||||
|
@UiItemAgentEntry
|
||||||
|
object RemoveShareLimit : CommonSwitchFunctionHook() {
|
||||||
|
override val name = "去除转发9名联系人限制"
|
||||||
|
override val uiItemLocation = FunctionEntryRouter.Locations.Auxiliary.CHAT_CATEGORY
|
||||||
|
|
||||||
|
override fun initOnce() = throwOrTrue {
|
||||||
|
"Lcom/tencent/mobileqq/activity/ForwardRecentActivity;->add2ForwardTargetList(Lcom/tencent/mobileqq/selectmember/ResultRecord;)Z".method.replace(this, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ import io.github.qauxv.fragment.AboutFragment;
|
|||||||
import io.github.qauxv.fragment.CheckAbiVariantFragment;
|
import io.github.qauxv.fragment.CheckAbiVariantFragment;
|
||||||
import io.github.qauxv.fragment.CheckAbiVariantModel;
|
import io.github.qauxv.fragment.CheckAbiVariantModel;
|
||||||
import io.github.qauxv.lifecycle.JumpActivityEntryHook;
|
import io.github.qauxv.lifecycle.JumpActivityEntryHook;
|
||||||
import io.github.qauxv.startup.HookEntry;
|
import io.github.qauxv.util.PackageConstants;
|
||||||
import io.github.qauxv.util.SyncUtils;
|
import io.github.qauxv.util.SyncUtils;
|
||||||
import io.github.qauxv.util.Toasts;
|
import io.github.qauxv.util.Toasts;
|
||||||
import io.github.qauxv.util.UiThread;
|
import io.github.qauxv.util.UiThread;
|
||||||
@@ -165,11 +165,11 @@ public class ConfigV2Activity extends AppCompatTransferActivity {
|
|||||||
String pkg = null;
|
String pkg = null;
|
||||||
var id = view.getId();
|
var id = view.getId();
|
||||||
if (id == R.id.mainRelativeLayoutButtonOpenQQ) {
|
if (id == R.id.mainRelativeLayoutButtonOpenQQ) {
|
||||||
pkg = HookEntry.PACKAGE_NAME_QQ;
|
pkg = PackageConstants.PACKAGE_NAME_QQ;
|
||||||
} else if (id == R.id.mainRelativeLayoutButtonOpenTIM) {
|
} else if (id == R.id.mainRelativeLayoutButtonOpenTIM) {
|
||||||
pkg = HookEntry.PACKAGE_NAME_TIM;
|
pkg = PackageConstants.PACKAGE_NAME_TIM;
|
||||||
} else if (id == R.id.mainRelativeLayoutButtonOpenQQLite) {
|
} else if (id == R.id.mainRelativeLayoutButtonOpenQQLite) {
|
||||||
pkg = HookEntry.PACKAGE_NAME_QQ_LITE;
|
pkg = PackageConstants.PACKAGE_NAME_QQ_LITE;
|
||||||
}
|
}
|
||||||
if (pkg != null) {
|
if (pkg != null) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
@@ -205,19 +205,19 @@ public class ConfigV2Activity extends AppCompatTransferActivity {
|
|||||||
String pkg = null;
|
String pkg = null;
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case 0: {
|
case 0: {
|
||||||
pkg = HookEntry.PACKAGE_NAME_QQ;
|
pkg = PackageConstants.PACKAGE_NAME_QQ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
pkg = HookEntry.PACKAGE_NAME_TIM;
|
pkg = PackageConstants.PACKAGE_NAME_TIM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
pkg = HookEntry.PACKAGE_NAME_QQ_LITE;
|
pkg = PackageConstants.PACKAGE_NAME_QQ_LITE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: {
|
case 3: {
|
||||||
pkg = HookEntry.PACKAGE_NAME_QQ_HD;
|
pkg = PackageConstants.PACKAGE_NAME_QQ_HD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import com.tencent.common.app.AppInterface;
|
import com.tencent.common.app.AppInterface;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.xpcompat.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.HostInfo;
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.qauxv.bridge;
|
package io.github.qauxv.bridge;
|
||||||
|
|
||||||
import static de.robv.android.xposed.XposedHelpers.callMethod;
|
import static io.github.qauxv.util.xpcompat.XposedHelpers.callMethod;
|
||||||
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
import static io.github.qauxv.util.xpcompat.XposedHelpers.setObjectField;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
package io.github.qauxv.config;
|
package io.github.qauxv.config;
|
||||||
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import io.github.qauxv.startup.HookEntry;
|
import io.github.qauxv.util.PackageConstants;
|
||||||
import io.github.qauxv.util.HostInfo;
|
import io.github.qauxv.util.HostInfo;
|
||||||
import io.github.qauxv.util.Log;
|
import io.github.qauxv.util.Log;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -44,7 +44,7 @@ public class SafeModeManager {
|
|||||||
}
|
}
|
||||||
INSTANCE.mSafeModeEnableFile = new File(
|
INSTANCE.mSafeModeEnableFile = new File(
|
||||||
Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" +
|
Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" +
|
||||||
HookEntry.sCurrentPackageName + "/" + SAFE_MODE_FILE_NAME
|
HostInfo.getHostInfo().getPackageName() + "/" + SAFE_MODE_FILE_NAME
|
||||||
);
|
);
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
@@ -73,10 +73,6 @@ public class SafeModeManager {
|
|||||||
if (!isAvailable()) {
|
if (!isAvailable()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (HookEntry.sCurrentPackageName == null || HookEntry.sCurrentPackageName.isBlank()) {
|
|
||||||
Log.e("Failed to enable or disable safe mode, sCurrentPackageName is null or blank");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isEnable) {
|
if (isEnable) {
|
||||||
try {
|
try {
|
||||||
boolean isCreated = mSafeModeEnableFile.createNewFile();
|
boolean isCreated = mSafeModeEnableFile.createNewFile();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.hook.SettingEntryHook;
|
import cc.ioctl.hook.SettingEntryHook;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.BuildConfig;
|
import io.github.qauxv.BuildConfig;
|
||||||
import io.github.qauxv.util.SyncUtils;
|
import io.github.qauxv.util.SyncUtils;
|
||||||
import io.github.qauxv.base.IDynamicHook;
|
import io.github.qauxv.base.IDynamicHook;
|
||||||
|
|||||||
@@ -123,6 +123,9 @@ public class InjectDelayableHooks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
final ArrayList<Step> steps = new ArrayList<>(todos);
|
final ArrayList<Step> steps = new ArrayList<>(todos);
|
||||||
// collect all dex-deobfs steps if backend supports
|
// collect all dex-deobfs steps if backend supports
|
||||||
HashSet<String> deobfIndexList = new HashSet<>(16);
|
HashSet<String> deobfIndexList = new HashSet<>(16);
|
||||||
@@ -208,6 +211,8 @@ public class InjectDelayableHooks {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
DexDeobfsProvider.INSTANCE.exitDeobfsSection();
|
DexDeobfsProvider.INSTANCE.exitDeobfsSection();
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
Log.i("DexDeobfsProvider: cost " + (end - start) + "ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (LicenseStatus.hasUserAcceptEula()) {
|
if (LicenseStatus.hasUserAcceptEula()) {
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ import cc.ioctl.hook.ui.misc.OptXListViewScrollBar;
|
|||||||
import cc.ioctl.hook.ui.title.RemoveCameraButton;
|
import cc.ioctl.hook.ui.title.RemoveCameraButton;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import cc.ioctl.util.Reflex;
|
import cc.ioctl.util.Reflex;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.config.ConfigItems;
|
import io.github.qauxv.config.ConfigItems;
|
||||||
import io.github.qauxv.config.SafeModeManager;
|
import io.github.qauxv.config.SafeModeManager;
|
||||||
import io.github.qauxv.lifecycle.ActProxyMgr;
|
import io.github.qauxv.lifecycle.ActProxyMgr;
|
||||||
|
|||||||
@@ -46,8 +46,17 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
HotUpdateManager.CHANNEL_CANARY to R.id.hotUpdateConfig_channel_canary,
|
HotUpdateManager.CHANNEL_CANARY to R.id.hotUpdateConfig_channel_canary,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val actionIdToViewId = mapOf(
|
||||||
|
HotUpdateManager.ACTION_DISABLE to R.id.hotUpdateConfig_action_disabled,
|
||||||
|
HotUpdateManager.ACTION_QUERY to R.id.hotUpdateConfig_action_query_before_update,
|
||||||
|
HotUpdateManager.ACTION_AUTO_UPDATE_WITH_NOTIFICATION to R.id.hotUpdateConfig_notice_after_update,
|
||||||
|
HotUpdateManager.ACTION_AUTO_UPDATE_WITHOUT_NOTIFICATION to R.id.hotUpdateConfig_auto_update_without_notice,
|
||||||
|
)
|
||||||
|
|
||||||
private fun viewIdToChannelId(viewId: Int) = channelIdToViewId.filterValues { it == viewId }.keys.first()
|
private fun viewIdToChannelId(viewId: Int) = channelIdToViewId.filterValues { it == viewId }.keys.first()
|
||||||
|
|
||||||
|
private fun viewIdToActionId(viewId: Int) = actionIdToViewId.filterValues { it == viewId }.keys.first()
|
||||||
|
|
||||||
override fun doOnCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun doOnCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
title = "热更新配置"
|
title = "热更新配置"
|
||||||
binding = FragmentHotUpdateConfigBinding.inflate(inflater, container, false).apply {
|
binding = FragmentHotUpdateConfigBinding.inflate(inflater, container, false).apply {
|
||||||
@@ -55,6 +64,12 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
hotUpdateConfigChannelStable.setOnClickListener(this@HotUpdateConfigFragment)
|
hotUpdateConfigChannelStable.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
hotUpdateConfigChannelBeta.setOnClickListener(this@HotUpdateConfigFragment)
|
hotUpdateConfigChannelBeta.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
hotUpdateConfigChannelCanary.setOnClickListener(this@HotUpdateConfigFragment)
|
hotUpdateConfigChannelCanary.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
|
|
||||||
|
hotUpdateConfigActionDisabled.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
|
hotUpdateConfigActionQueryBeforeUpdate.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
|
hotUpdateConfigNoticeAfterUpdate.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
|
hotUpdateConfigAutoUpdateWithoutNotice.setOnClickListener(this@HotUpdateConfigFragment)
|
||||||
|
|
||||||
updateViewStatus(this)
|
updateViewStatus(this)
|
||||||
|
|
||||||
fun adjustTitleTextSize(v: AppCompatTextView) {
|
fun adjustTitleTextSize(v: AppCompatTextView) {
|
||||||
@@ -79,6 +94,11 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
adjustTitleTextSize(hotUpdateConfigChannelStable)
|
adjustTitleTextSize(hotUpdateConfigChannelStable)
|
||||||
adjustTitleTextSize(hotUpdateConfigChannelBeta)
|
adjustTitleTextSize(hotUpdateConfigChannelBeta)
|
||||||
adjustTitleTextSize(hotUpdateConfigChannelCanary)
|
adjustTitleTextSize(hotUpdateConfigChannelCanary)
|
||||||
|
|
||||||
|
adjustTitleTextSize(hotUpdateConfigActionDisabled)
|
||||||
|
adjustTitleTextSize(hotUpdateConfigActionQueryBeforeUpdate)
|
||||||
|
adjustTitleTextSize(hotUpdateConfigNoticeAfterUpdate)
|
||||||
|
adjustTitleTextSize(hotUpdateConfigAutoUpdateWithoutNotice)
|
||||||
}
|
}
|
||||||
rootLayoutView = binding!!.root
|
rootLayoutView = binding!!.root
|
||||||
return binding!!.root
|
return binding!!.root
|
||||||
@@ -92,6 +112,7 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
private fun updateViewStatus(binding: FragmentHotUpdateConfigBinding) {
|
private fun updateViewStatus(binding: FragmentHotUpdateConfigBinding) {
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val currentChannel = HotUpdateManager.currentChannel
|
val currentChannel = HotUpdateManager.currentChannel
|
||||||
|
val currentAction = HotUpdateManager.currentAction
|
||||||
|
|
||||||
binding.hotUpdateConfigCurrentInfo.text = "别看了,这个功能还没做好,选什么都没用"
|
binding.hotUpdateConfigCurrentInfo.text = "别看了,这个功能还没做好,选什么都没用"
|
||||||
|
|
||||||
@@ -101,6 +122,12 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
binding.hotUpdateConfigChannelBeta,
|
binding.hotUpdateConfigChannelBeta,
|
||||||
binding.hotUpdateConfigChannelCanary,
|
binding.hotUpdateConfigChannelCanary,
|
||||||
)
|
)
|
||||||
|
val actionButtons = arrayOf(
|
||||||
|
binding.hotUpdateConfigActionDisabled,
|
||||||
|
binding.hotUpdateConfigActionQueryBeforeUpdate,
|
||||||
|
binding.hotUpdateConfigNoticeAfterUpdate,
|
||||||
|
binding.hotUpdateConfigAutoUpdateWithoutNotice,
|
||||||
|
)
|
||||||
val accentColor = ThemeAttrUtils.resolveColorOrDefaultColorRes(
|
val accentColor = ThemeAttrUtils.resolveColorOrDefaultColorRes(
|
||||||
ctx,
|
ctx,
|
||||||
androidx.appcompat.R.attr.colorAccent,
|
androidx.appcompat.R.attr.colorAccent,
|
||||||
@@ -123,6 +150,22 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
it.setTextColor(secondTextColor)
|
it.setTextColor(secondTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
actionButtons.forEach {
|
||||||
|
val actionId = viewIdToActionId(it.id)
|
||||||
|
if (currentAction == actionId) {
|
||||||
|
it.setTextColor(accentColor)
|
||||||
|
if (it.compoundDrawables[2] == null) {
|
||||||
|
it.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
null, null, ResourcesCompat.getDrawable(
|
||||||
|
ctx.resources, R.drawable.ic_check_24, ctx.theme
|
||||||
|
), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
it.setCompoundDrawables(null, null, null, null)
|
||||||
|
it.setTextColor(secondTextColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onChannelClick(v: View, channelId: Int) {
|
private fun onChannelClick(v: View, channelId: Int) {
|
||||||
@@ -159,12 +202,25 @@ class HotUpdateConfigFragment : BaseRootLayoutFragment(), View.OnClickListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onActionClick(v: View, actionId: Int) {
|
||||||
|
if (HotUpdateManager.currentAction == actionId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
HotUpdateManager.currentAction = actionId
|
||||||
|
updateViewStatus(binding!!)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onClick(v: View) {
|
override fun onClick(v: View) {
|
||||||
when (v.id) {
|
when (v.id) {
|
||||||
R.id.hotUpdateConfig_channel_disabled -> onChannelClick(v, HotUpdateManager.CHANNEL_DISABLED)
|
R.id.hotUpdateConfig_channel_disabled -> onChannelClick(v, HotUpdateManager.CHANNEL_DISABLED)
|
||||||
R.id.hotUpdateConfig_channel_stable -> onChannelClick(v, HotUpdateManager.CHANNEL_STABLE)
|
R.id.hotUpdateConfig_channel_stable -> onChannelClick(v, HotUpdateManager.CHANNEL_STABLE)
|
||||||
R.id.hotUpdateConfig_channel_beta -> onChannelClick(v, HotUpdateManager.CHANNEL_BETA)
|
R.id.hotUpdateConfig_channel_beta -> onChannelClick(v, HotUpdateManager.CHANNEL_BETA)
|
||||||
R.id.hotUpdateConfig_channel_canary -> onChannelClick(v, HotUpdateManager.CHANNEL_CANARY)
|
R.id.hotUpdateConfig_channel_canary -> onChannelClick(v, HotUpdateManager.CHANNEL_CANARY)
|
||||||
|
|
||||||
|
R.id.hotUpdateConfig_action_disabled -> onActionClick(v, HotUpdateManager.ACTION_DISABLE)
|
||||||
|
R.id.hotUpdateConfig_action_query_before_update -> onActionClick(v, HotUpdateManager.ACTION_QUERY)
|
||||||
|
R.id.hotUpdateConfig_notice_after_update -> onActionClick(v, HotUpdateManager.ACTION_AUTO_UPDATE_WITH_NOTIFICATION)
|
||||||
|
R.id.hotUpdateConfig_auto_update_without_notice -> onActionClick(v, HotUpdateManager.ACTION_AUTO_UPDATE_WITHOUT_NOTIFICATION)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,14 @@ import android.util.TypedValue
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.LinearLayout
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.widget.AppCompatCheckBox
|
||||||
|
import androidx.appcompat.widget.AppCompatEditText
|
||||||
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -49,12 +54,13 @@ import cc.ioctl.fragment.ExfriendListFragment
|
|||||||
import cc.ioctl.util.ExfriendManager
|
import cc.ioctl.util.ExfriendManager
|
||||||
import cc.ioctl.util.HostInfo
|
import cc.ioctl.util.HostInfo
|
||||||
import cc.ioctl.util.LayoutHelper
|
import cc.ioctl.util.LayoutHelper
|
||||||
|
import cc.ioctl.util.LayoutHelper.dip2px
|
||||||
import cc.ioctl.util.Reflex
|
import cc.ioctl.util.Reflex
|
||||||
import cc.ioctl.util.data.EventRecord
|
import cc.ioctl.util.data.EventRecord
|
||||||
import cc.ioctl.util.data.FriendRecord
|
import cc.ioctl.util.data.FriendRecord
|
||||||
import cc.ioctl.util.ui.ThemeAttrUtils
|
import cc.ioctl.util.ui.ThemeAttrUtils
|
||||||
import cc.ioctl.util.ui.dsl.RecyclerListViewController
|
import cc.ioctl.util.ui.dsl.RecyclerListViewController
|
||||||
import de.robv.android.xposed.XposedBridge
|
import io.github.qauxv.util.xpcompat.XposedBridge
|
||||||
import io.github.qauxv.R
|
import io.github.qauxv.R
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity.Companion.createStartActivityForFragmentIntent
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity.Companion.createStartActivityForFragmentIntent
|
||||||
@@ -66,11 +72,12 @@ import io.github.qauxv.dsl.item.CategoryItem
|
|||||||
import io.github.qauxv.dsl.item.DslTMsgListItemInflatable
|
import io.github.qauxv.dsl.item.DslTMsgListItemInflatable
|
||||||
import io.github.qauxv.dsl.item.TextSwitchItem
|
import io.github.qauxv.dsl.item.TextSwitchItem
|
||||||
import io.github.qauxv.lifecycle.ActProxyMgr
|
import io.github.qauxv.lifecycle.ActProxyMgr
|
||||||
import io.github.qauxv.startup.HookEntry
|
import io.github.qauxv.poststartup.StartupInfo
|
||||||
import io.github.qauxv.startup.HybridClassLoader
|
import io.github.qauxv.startup.HybridClassLoader
|
||||||
import io.github.qauxv.tlb.ConfigTable.cacheMap
|
import io.github.qauxv.tlb.ConfigTable.cacheMap
|
||||||
import io.github.qauxv.ui.CustomDialog
|
import io.github.qauxv.ui.CustomDialog
|
||||||
import io.github.qauxv.util.Initiator
|
import io.github.qauxv.util.Initiator
|
||||||
|
import io.github.qauxv.util.LoaderExtensionHelper
|
||||||
import io.github.qauxv.util.Natives
|
import io.github.qauxv.util.Natives
|
||||||
import io.github.qauxv.util.Toasts
|
import io.github.qauxv.util.Toasts
|
||||||
import io.github.qauxv.util.dexkit.DexKit
|
import io.github.qauxv.util.dexkit.DexKit
|
||||||
@@ -166,14 +173,7 @@ class TroubleshootFragment : BaseRootLayoutFragment() {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
CategoryItem("调试信息") {
|
CategoryItem("调试信息") {
|
||||||
val statusInfo = "PID: " + android.os.Process.myPid() +
|
description(generateStatusText(), isTextSelectable = true)
|
||||||
", UID: " + android.os.Process.myUid() +
|
|
||||||
", " + (if (android.os.Process.is64Bit()) "64 bit" else "32 bit") + "\n" +
|
|
||||||
"Xposed API version: " + XposedBridge.getXposedVersion() + "\n" +
|
|
||||||
HybridClassLoader.getXposedBridgeClassName() + "\n" +
|
|
||||||
"module: " + HookEntry.getModulePath() + "\n" +
|
|
||||||
"ctx.dataDir: " + hostInfo.application.dataDir
|
|
||||||
description(statusInfo, isTextSelectable = true)
|
|
||||||
description(generateDebugInfo(), isTextSelectable = true)
|
description(generateDebugInfo(), isTextSelectable = true)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -222,8 +222,9 @@ class TroubleshootFragment : BaseRootLayoutFragment() {
|
|||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val clickToResetDefaultConfig = confirmBeforeAction(
|
private val clickToResetDefaultConfig = confirmTwiceBeforeAction(
|
||||||
"此操作将删除该模块的所有配置信息,包括屏蔽通知的群列表,但不包括历史好友列表.点击确认后请等待3秒后手动重启" + hostInfo.hostName + ".\n此操作不可恢复"
|
"此操作将删除该模块的所有配置信息,包括屏蔽通知的群列表,但不包括历史好友列表.点击确认后请等待3秒后手动重启" + hostInfo.hostName + ".\n此操作不可恢复",
|
||||||
|
"删除所有配置信息"
|
||||||
) {
|
) {
|
||||||
ConfigManager.getCache().apply {
|
ConfigManager.getCache().apply {
|
||||||
clear()
|
clear()
|
||||||
@@ -237,12 +238,13 @@ class TroubleshootFragment : BaseRootLayoutFragment() {
|
|||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val clickToClearRecoveredFriends = confirmBeforeAction(
|
private val clickToClearRecoveredFriends = confirmTwiceBeforeAction(
|
||||||
"""
|
"""
|
||||||
此操作将删除当前账号(${getLongAccountUin()})下的 已恢复 的历史好友记录(记录可单独删除).
|
此操作将删除当前账号(${getLongAccountUin()})下的 已恢复 的历史好友记录(记录可单独删除).
|
||||||
如果因 BUG 大量好友被标记为已删除, 请先刷新好友列表, 然后再点击此按钮.
|
如果因 BUG 大量好友被标记为已删除, 请先刷新好友列表, 然后再点击此按钮.
|
||||||
此操作不可恢复
|
此操作不可恢复
|
||||||
""".trimIndent()
|
""".trimIndent(),
|
||||||
|
"删除已恢复的好友记录"
|
||||||
) {
|
) {
|
||||||
val exm = ExfriendManager.getCurrent()
|
val exm = ExfriendManager.getCurrent()
|
||||||
val it: MutableIterator<*> = exm.events.entries.iterator()
|
val it: MutableIterator<*> = exm.events.entries.iterator()
|
||||||
@@ -258,11 +260,12 @@ class TroubleshootFragment : BaseRootLayoutFragment() {
|
|||||||
Toasts.success(requireContext(), "操作成功")
|
Toasts.success(requireContext(), "操作成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val clickToClearAllFriends = confirmBeforeAction(
|
private val clickToClearAllFriends = confirmTwiceBeforeAction(
|
||||||
"此操作将删除当前账号(" + getLongAccountUin()
|
"此操作将删除当前账号(" + getLongAccountUin()
|
||||||
+ ")下的 全部 的历史好友记录, 通常您不需要进行此操作. \n" +
|
+ ")下的 全部 的历史好友记录, 通常您不需要进行此操作. \n" +
|
||||||
"如果您的历史好友列表中因bug出现大量好友,请在联系人列表下拉刷新后点击 删除标记为已恢复的好友. \n" +
|
"如果您的历史好友列表中因bug出现大量好友,请在联系人列表下拉刷新后点击 删除标记为已恢复的好友. \n" +
|
||||||
"此操作不可恢复"
|
"此操作不可恢复",
|
||||||
|
"删除所有好友记录"
|
||||||
) {
|
) {
|
||||||
val uin = getLongAccountUin()
|
val uin = getLongAccountUin()
|
||||||
if (uin < 10000) {
|
if (uin < 10000) {
|
||||||
@@ -303,6 +306,57 @@ class TroubleshootFragment : BaseRootLayoutFragment() {
|
|||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun confirmTwiceBeforeAction(
|
||||||
|
confirmMessage: String,
|
||||||
|
secondConfirmCheckBoxText: String,
|
||||||
|
action: () -> Unit
|
||||||
|
) = View.OnClickListener {
|
||||||
|
val ctx = requireContext()
|
||||||
|
val builder = AlertDialog.Builder(ctx)
|
||||||
|
builder.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
try {
|
||||||
|
action()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
CustomDialog.createFailsafe(ctx)
|
||||||
|
.setTitle(Reflex.getShortClassName(e))
|
||||||
|
.setCancelable(true)
|
||||||
|
.setMessage(e.toString())
|
||||||
|
.ok().show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
builder.setCancelable(true)
|
||||||
|
builder.setTitle("确认操作")
|
||||||
|
// create a linear layout to hold the message and checkbox
|
||||||
|
val layout = LinearLayout(ctx).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
val padding = ctx.resources.getDimension(androidx.appcompat.R.dimen.abc_dialog_padding_material).toInt()
|
||||||
|
setPadding(padding, padding / 3, padding, 0)
|
||||||
|
}
|
||||||
|
val message = AppCompatTextView(ctx).apply {
|
||||||
|
text = confirmMessage
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
|
||||||
|
setTextColor(ResourcesCompat.getColor(resources, R.color.firstTextColor, ctx.theme))
|
||||||
|
}
|
||||||
|
val checkBox = AppCompatCheckBox(ctx).apply {
|
||||||
|
text = secondConfirmCheckBoxText
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
|
||||||
|
setTextColor(ResourcesCompat.getColor(resources, R.color.firstTextColor, ctx.theme))
|
||||||
|
isClickable = true
|
||||||
|
isChecked = false
|
||||||
|
}
|
||||||
|
layout.addView(message)
|
||||||
|
layout.addView(checkBox)
|
||||||
|
builder.setView(layout)
|
||||||
|
val dialog = builder.show()
|
||||||
|
// get positive button and set listener
|
||||||
|
val positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
checkBox.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
positiveButton.isEnabled = isChecked
|
||||||
|
}
|
||||||
|
positiveButton.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun actionOrShowError(action: () -> Unit) = View.OnClickListener {
|
private fun actionOrShowError(action: () -> Unit) = View.OnClickListener {
|
||||||
runOrShowError(action)
|
runOrShowError(action)
|
||||||
}
|
}
|
||||||
@@ -423,6 +477,26 @@ class TroubleshootFragment : BaseRootLayoutFragment() {
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateStatusText(): String {
|
||||||
|
val loader = StartupInfo.getLoaderInfo()
|
||||||
|
val hook = StartupInfo.requireHookBridge()
|
||||||
|
var statusInfo = "PID: " + android.os.Process.myPid() +
|
||||||
|
", UID: " + android.os.Process.myUid() +
|
||||||
|
", " + (if (android.os.Process.is64Bit()) "64 bit" else "32 bit") + "\n" +
|
||||||
|
"Xposed API version: " + hook.apiLevel + "\n" +
|
||||||
|
"module: " + StartupInfo.getModulePath() + "\n" +
|
||||||
|
"ctx.dataDir: " + hostInfo.application.dataDir + "\n"
|
||||||
|
statusInfo += "entry: " + loader.entryPointName + "\n"
|
||||||
|
var xp = loader.queryExtension("GetXposedBridgeClass") as Class<*>?
|
||||||
|
if (xp == null) {
|
||||||
|
xp = loader.queryExtension("GetXposedInterfaceClass") as Class<*>?
|
||||||
|
}
|
||||||
|
statusInfo += "XposedBridge: " + (if (xp != null) xp.name else "null") + "\n"
|
||||||
|
statusInfo += hook.frameworkName + " " + hook.frameworkVersion + " (" + hook.frameworkVersionCode + ")\n"
|
||||||
|
statusInfo += "Hook counter: " + LoaderExtensionHelper.getHookCounter();
|
||||||
|
return statusInfo
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateDebugInfo(): CharSequence {
|
private fun generateDebugInfo(): CharSequence {
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val colorError: Int = ThemeAttrUtils.resolveColorOrDefaultColorInt(ctx, R.attr.unusableColor, Color.RED)
|
val colorError: Int = ThemeAttrUtils.resolveColorOrDefaultColorInt(ctx, R.attr.unusableColor, Color.RED)
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
import io.github.qauxv.activity.SettingsUiFragmentHostActivity;
|
||||||
import io.github.qauxv.fragment.EulaFragment;
|
import io.github.qauxv.fragment.EulaFragment;
|
||||||
import io.github.qauxv.fragment.TroubleshootFragment;
|
import io.github.qauxv.fragment.TroubleshootFragment;
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ import androidx.annotation.RequiresApi;
|
|||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import io.github.qauxv.R;
|
import io.github.qauxv.R;
|
||||||
import io.github.qauxv.core.MainHook;
|
import io.github.qauxv.core.MainHook;
|
||||||
import io.github.qauxv.startup.HookEntry;
|
import io.github.qauxv.poststartup.StartupInfo;
|
||||||
|
import io.github.qauxv.util.PackageConstants;
|
||||||
import io.github.qauxv.ui.WindowIsTranslucent;
|
import io.github.qauxv.ui.WindowIsTranslucent;
|
||||||
import io.github.qauxv.util.Initiator;
|
import io.github.qauxv.util.Initiator;
|
||||||
import io.github.qauxv.util.Log;
|
import io.github.qauxv.util.Log;
|
||||||
@@ -113,7 +114,7 @@ public class Parasitics {
|
|||||||
return;
|
return;
|
||||||
} catch (Resources.NotFoundException ignored) {
|
} catch (Resources.NotFoundException ignored) {
|
||||||
}
|
}
|
||||||
String sModulePath = HookEntry.getModulePath();
|
String sModulePath = StartupInfo.getModulePath();
|
||||||
if (sModulePath == null) {
|
if (sModulePath == null) {
|
||||||
throw new RuntimeException("get module path failed, loader=" + MainHook.class.getClassLoader());
|
throw new RuntimeException("get module path failed, loader=" + MainHook.class.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ import android.provider.OpenableColumns;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import cc.ioctl.util.HostInfo;
|
import cc.ioctl.util.HostInfo;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
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.SyncUtils;
|
import io.github.qauxv.util.SyncUtils;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ package io.github.qauxv.omnifix.hw;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
import io.github.qauxv.BuildConfig;
|
import io.github.qauxv.BuildConfig;
|
||||||
import io.github.qauxv.util.Log;
|
import io.github.qauxv.util.Log;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|||||||
138
app/src/main/java/io/github/qauxv/poststartup/StartupAgent.java
Normal file
138
app/src/main/java/io/github/qauxv/poststartup/StartupAgent.java
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
|
* https://github.com/cinit/QAuxiliary
|
||||||
|
*
|
||||||
|
* This software is an opensource software: you can redistribute it
|
||||||
|
* and/or modify it under the terms of the General Public License
|
||||||
|
* as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version as published
|
||||||
|
* by QAuxiliary contributors.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the General Public License
|
||||||
|
* along with this software.
|
||||||
|
* If not, see
|
||||||
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.qauxv.poststartup;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.os.Build;
|
||||||
|
import androidx.annotation.Keep;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import io.github.qauxv.loader.hookapi.IHookBridge;
|
||||||
|
import io.github.qauxv.loader.hookapi.ILoaderInfo;
|
||||||
|
import io.github.qauxv.util.IoUtils;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import org.lsposed.hiddenapibypass.HiddenApiBypass;
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public class StartupAgent {
|
||||||
|
|
||||||
|
private static boolean sInitialized = false;
|
||||||
|
|
||||||
|
private StartupAgent() {
|
||||||
|
throw new AssertionError("No instance for you!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public static void startup(
|
||||||
|
@NonNull String modulePath,
|
||||||
|
@NonNull ApplicationInfo appInfo,
|
||||||
|
@NonNull ILoaderInfo loaderInfo,
|
||||||
|
@NonNull ClassLoader hostClassLoader,
|
||||||
|
@Nullable IHookBridge hookBridge
|
||||||
|
) {
|
||||||
|
if (sInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sInitialized = true;
|
||||||
|
if (io.github.qauxv.R.string.res_inject_success >>> 24 == 0x7f) {
|
||||||
|
throw new AssertionError("package id must NOT be 0x7f, reject loading...");
|
||||||
|
}
|
||||||
|
if ("true".equals(System.getProperty(StartupAgent.class.getName()))) {
|
||||||
|
android.util.Log.e("QAuxv", "Error: QAuxiliary reloaded??");
|
||||||
|
// I don't know... What happened?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.setProperty(StartupAgent.class.getName(), "true");
|
||||||
|
StartupInfo.setModulePath(modulePath);
|
||||||
|
StartupInfo.setLoaderInfo(loaderInfo);
|
||||||
|
StartupInfo.setHookBridge(hookBridge);
|
||||||
|
StartupInfo.setInHostProcess(true);
|
||||||
|
// bypass hidden api
|
||||||
|
ensureHiddenApiAccess();
|
||||||
|
// we want context
|
||||||
|
Context ctx = getBaseApplicationImpl(hostClassLoader);
|
||||||
|
if (ctx == null) {
|
||||||
|
if (hookBridge == null) {
|
||||||
|
throw new UnsupportedOperationException("neither base application nor hook bridge found");
|
||||||
|
}
|
||||||
|
StartupHook.getInstance().initializeBeforeAppCreate(hostClassLoader);
|
||||||
|
} else {
|
||||||
|
StartupHook.getInstance().initializeAfterAppCreate(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Context getBaseApplicationImpl(@NonNull ClassLoader classLoader) {
|
||||||
|
Context app;
|
||||||
|
try {
|
||||||
|
Class<?> clz = classLoader.loadClass("com.tencent.common.app.BaseApplicationImpl");
|
||||||
|
Field fsApp = null;
|
||||||
|
for (Field f : clz.getDeclaredFields()) {
|
||||||
|
if (f.getType() == clz) {
|
||||||
|
fsApp = f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fsApp == null) {
|
||||||
|
throw new UnsupportedOperationException("field BaseApplicationImpl.sApplication not found");
|
||||||
|
}
|
||||||
|
app = (Context) fsApp.get(null);
|
||||||
|
return app;
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
android.util.Log.e("QAuxv", "getBaseApplicationImpl: failed", e);
|
||||||
|
throw IoUtils.unsafeThrow(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureHiddenApiAccess() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !isHiddenApiAccessible()) {
|
||||||
|
android.util.Log.w("QAuxv", "Hidden API access not accessible, SDK_INT is " + Build.VERSION.SDK_INT);
|
||||||
|
HiddenApiBypass.setHiddenApiExemptions("L");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint({"BlockedPrivateApi", "PrivateApi"})
|
||||||
|
public static boolean isHiddenApiAccessible() {
|
||||||
|
Class<?> kContextImpl;
|
||||||
|
try {
|
||||||
|
kContextImpl = Class.forName("android.app.ContextImpl");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Field mActivityToken = null;
|
||||||
|
Field mToken = null;
|
||||||
|
try {
|
||||||
|
mActivityToken = kContextImpl.getDeclaredField("mActivityToken");
|
||||||
|
} catch (NoSuchFieldException ignored) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mToken = kContextImpl.getDeclaredField("mToken");
|
||||||
|
} catch (NoSuchFieldException ignored) {
|
||||||
|
}
|
||||||
|
return mActivityToken != null || mToken != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,34 +1,36 @@
|
|||||||
/*
|
/*
|
||||||
* QAuxiliary - An Xposed module for QQ/TIM
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
* Copyright (C) 2019-2022 qwq233@qwq2333.top
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
* https://github.com/cinit/QAuxiliary
|
* https://github.com/cinit/QAuxiliary
|
||||||
*
|
*
|
||||||
* This software is non-free but opensource software: you can redistribute it
|
* This software is an opensource software: you can redistribute it
|
||||||
* and/or modify it under the terms of the GNU Affero General Public License
|
* and/or modify it under the terms of the General Public License
|
||||||
* as published by the Free Software Foundation; either
|
* as published by the Free Software Foundation; either
|
||||||
* version 3 of the License, or any later version and our eula as published
|
* version 3 of the License, or any later version as published
|
||||||
* by QAuxiliary contributors.
|
* by QAuxiliary contributors.
|
||||||
*
|
*
|
||||||
* This software is distributed in the hope that it will be useful,
|
* This software is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* Affero General Public License for more details.
|
* See the General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the General Public License
|
||||||
* and eula along with this software. If not, see
|
* along with this software.
|
||||||
* <https://www.gnu.org/licenses/>
|
* If not, see
|
||||||
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
*/
|
*/
|
||||||
package io.github.qauxv.startup;
|
package io.github.qauxv.poststartup;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import androidx.annotation.NonNull;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import io.github.qauxv.startup.HybridClassLoader;
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
import io.github.qauxv.util.IoUtils;
|
||||||
|
import io.github.qauxv.util.xpcompat.XC_MethodHook;
|
||||||
|
import io.github.qauxv.util.xpcompat.XposedBridge;
|
||||||
|
import io.github.qauxv.util.xpcompat.XposedHelpers;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -38,9 +40,11 @@ import java.lang.reflect.Modifier;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Startup hook for QQ/TIM They should act differently according to the process they belong to. I don't want to cope
|
* Startup hook for QQ/TIM They should act differently according to the process they belong to.
|
||||||
* with them any more, enjoy it as long as possible. DO NOT INVOKE ANY METHOD THAT MAY GET IN TOUCH WITH KOTLIN HERE. DO
|
* <p>
|
||||||
* NOT MODIFY ANY CODE HERE UNLESS NECESSARY.
|
* I don't want to cope with them anymore, enjoy it as long as possible.
|
||||||
|
* <p>
|
||||||
|
* DO NOT MODIFY ANY CODE HERE UNLESS NECESSARY.
|
||||||
*
|
*
|
||||||
* @author cinit
|
* @author cinit
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +52,6 @@ public class StartupHook {
|
|||||||
|
|
||||||
private static StartupHook sInstance;
|
private static StartupHook sInstance;
|
||||||
private static boolean sSecondStageInit = false;
|
private static boolean sSecondStageInit = false;
|
||||||
private boolean mFirstStageInit = false;
|
|
||||||
|
|
||||||
private StartupHook() {
|
private StartupHook() {
|
||||||
}
|
}
|
||||||
@@ -65,44 +68,12 @@ public class StartupHook {
|
|||||||
if (sSecondStageInit) {
|
if (sSecondStageInit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ClassLoader classLoader = ctx.getClassLoader();
|
HybridClassLoader.setHostClassLoader(ctx.getClassLoader());
|
||||||
if (classLoader == null) {
|
|
||||||
throw new AssertionError("ERROR: classLoader == null");
|
|
||||||
}
|
|
||||||
if ("true".equals(System.getProperty(StartupHook.class.getName()))) {
|
|
||||||
XposedBridge.log("Err:QAuxiliary reloaded??");
|
|
||||||
//I don't know... What happened?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
System.setProperty(StartupHook.class.getName(), "true");
|
|
||||||
injectClassLoader(classLoader);
|
|
||||||
StartupRoutine.execPostStartupInit(ctx, step, lpwReserved, bReserved);
|
StartupRoutine.execPostStartupInit(ctx, step, lpwReserved, bReserved);
|
||||||
sSecondStageInit = true;
|
sSecondStageInit = true;
|
||||||
deleteDirIfNecessaryNoThrow(ctx);
|
deleteDirIfNecessaryNoThrow(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("JavaReflectionMemberAccess")
|
|
||||||
@SuppressLint("DiscouragedPrivateApi")
|
|
||||||
private static void injectClassLoader(ClassLoader classLoader) {
|
|
||||||
if (classLoader == null) {
|
|
||||||
throw new NullPointerException("classLoader == null");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Field fParent = ClassLoader.class.getDeclaredField("parent");
|
|
||||||
fParent.setAccessible(true);
|
|
||||||
ClassLoader mine = StartupHook.class.getClassLoader();
|
|
||||||
ClassLoader curr = (ClassLoader) fParent.get(mine);
|
|
||||||
if (curr == null) {
|
|
||||||
curr = XposedBridge.class.getClassLoader();
|
|
||||||
}
|
|
||||||
if (!curr.getClass().getName().equals(HybridClassLoader.class.getName())) {
|
|
||||||
fParent.set(mine, new HybridClassLoader(curr, classLoader));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log_e(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void deleteDirIfNecessaryNoThrow(Context ctx) {
|
static void deleteDirIfNecessaryNoThrow(Context ctx) {
|
||||||
try {
|
try {
|
||||||
deleteFile(new File(ctx.getDataDir(), "app_qqprotect"));
|
deleteFile(new File(ctx.getDataDir(), "app_qqprotect"));
|
||||||
@@ -147,58 +118,27 @@ public class StartupHook {
|
|||||||
String msg = Log.getStackTraceString(th);
|
String msg = Log.getStackTraceString(th);
|
||||||
Log.e("QAuxv", msg);
|
Log.e("QAuxv", msg);
|
||||||
try {
|
try {
|
||||||
XposedBridge.log(th);
|
StartupInfo.getLoaderInfo().log(th);
|
||||||
} catch (NoClassDefFoundError e) {
|
} catch (NoClassDefFoundError | NullPointerException e) {
|
||||||
Log.e("Xposed", msg);
|
Log.e("Xposed", msg);
|
||||||
Log.e("EdXposed-Bridge", msg);
|
Log.e("EdXposed-Bridge", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkClassLoaderIsolation() {
|
public void initializeAfterAppCreate(@NonNull Context ctx) {
|
||||||
Class<?> stub;
|
execStartupInit(ctx, null, null, false);
|
||||||
try {
|
applyTargetDpiIfNecessary(ctx);
|
||||||
stub = Class.forName("com.tencent.common.app.BaseApplicationImpl");
|
deleteDirIfNecessaryNoThrow(ctx);
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
Log.d("QAuxv", "checkClassLoaderIsolation success");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Log.e("QAuxv", "checkClassLoaderIsolation failure!");
|
|
||||||
Log.e("QAuxv", "HostApp: " + stub.getClassLoader());
|
|
||||||
Log.e("QAuxv", "Module: " + StartupHook.class.getClassLoader());
|
|
||||||
Log.e("QAuxv", "Module.parent: " + StartupHook.class.getClassLoader().getParent());
|
|
||||||
Log.e("QAuxv", "XposedBridge: " + XposedBridge.class.getClassLoader());
|
|
||||||
Log.e("QAuxv", "SystemClassLoader: " + ClassLoader.getSystemClassLoader());
|
|
||||||
Log.e("QAuxv", "Context.class: " + Context.class.getClassLoader());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(ClassLoader rtLoader) throws Throwable {
|
public void initializeBeforeAppCreate(@NonNull ClassLoader rtLoader) {
|
||||||
if (mFirstStageInit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
XC_MethodHook startup = new XC_MethodHook(51) {
|
XC_MethodHook startup = new XC_MethodHook(51) {
|
||||||
@Override
|
@Override
|
||||||
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||||
try {
|
ClassLoader cl = param.thisObject.getClass().getClassLoader();
|
||||||
Context app;
|
Context app = StartupAgent.getBaseApplicationImpl(cl);
|
||||||
Class<?> clz = param.thisObject.getClass().getClassLoader()
|
execStartupInit(app, param.thisObject, null, false);
|
||||||
.loadClass("com.tencent.common.app.BaseApplicationImpl");
|
|
||||||
Field fsApp = null;
|
|
||||||
for (Field f : clz.getDeclaredFields()) {
|
|
||||||
if (f.getType() == clz) {
|
|
||||||
fsApp = f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fsApp == null) {
|
|
||||||
throw new NoSuchFieldException("field BaseApplicationImpl.sApplication not found");
|
|
||||||
}
|
|
||||||
app = (Context) fsApp.get(null);
|
|
||||||
execStartupInit(app, param.thisObject, null, false);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log_e(e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Class<?> loadDex = findLoadDexTaskClass(rtLoader);
|
Class<?> loadDex = findLoadDexTaskClass(rtLoader);
|
||||||
@@ -218,7 +158,6 @@ public class StartupHook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
XposedBridge.hookMethod(m, startup);
|
XposedBridge.hookMethod(m, startup);
|
||||||
mFirstStageInit = true;
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if ((e + "").contains("com.bug.zqq")) {
|
if ((e + "").contains("com.bug.zqq")) {
|
||||||
return;
|
return;
|
||||||
@@ -227,7 +166,7 @@ public class StartupHook {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_e(e);
|
log_e(e);
|
||||||
throw e;
|
throw IoUtils.unsafeThrow(e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
XposedHelpers.findAndHookMethod(rtLoader.loadClass("com.tencent.mobileqq.qfix.QFixApplication"),
|
XposedHelpers.findAndHookMethod(rtLoader.loadClass("com.tencent.mobileqq.qfix.QFixApplication"),
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
|
* https://github.com/cinit/QAuxiliary
|
||||||
|
*
|
||||||
|
* This software is an opensource software: you can redistribute it
|
||||||
|
* and/or modify it under the terms of the General Public License
|
||||||
|
* as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version as published
|
||||||
|
* by QAuxiliary contributors.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the General Public License
|
||||||
|
* along with this software.
|
||||||
|
* If not, see
|
||||||
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.qauxv.poststartup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import io.github.qauxv.loader.hookapi.IHookBridge;
|
||||||
|
import io.github.qauxv.loader.hookapi.ILoaderInfo;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class StartupInfo {
|
||||||
|
|
||||||
|
private StartupInfo() {
|
||||||
|
throw new AssertionError("No instance for you!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String modulePath;
|
||||||
|
|
||||||
|
private static ILoaderInfo loaderInfo;
|
||||||
|
|
||||||
|
private static IHookBridge hookBridge;
|
||||||
|
|
||||||
|
private static Boolean inHostProcess = null;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getModulePath() {
|
||||||
|
return modulePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static ILoaderInfo getLoaderInfo() {
|
||||||
|
return loaderInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static IHookBridge getHookBridge() {
|
||||||
|
return hookBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static IHookBridge requireHookBridge() {
|
||||||
|
if (hookBridge == null) {
|
||||||
|
throw new IllegalStateException("HookBridge is not initialized");
|
||||||
|
}
|
||||||
|
return hookBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setHookBridge(@Nullable IHookBridge hookBridge) {
|
||||||
|
StartupInfo.hookBridge = hookBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLoaderInfo(@NonNull ILoaderInfo loaderInfo) {
|
||||||
|
Objects.requireNonNull(loaderInfo);
|
||||||
|
StartupInfo.loaderInfo = loaderInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setModulePath(@NonNull String modulePath) {
|
||||||
|
Objects.requireNonNull(modulePath);
|
||||||
|
StartupInfo.modulePath = modulePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInHostProcess() {
|
||||||
|
if (inHostProcess == null) {
|
||||||
|
throw new IllegalStateException("Host process status is not initialized");
|
||||||
|
}
|
||||||
|
return inHostProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setInHostProcess(boolean inHostProcess) {
|
||||||
|
if (StartupInfo.inHostProcess != null) {
|
||||||
|
throw new IllegalStateException("Host process status is already initialized");
|
||||||
|
}
|
||||||
|
StartupInfo.inHostProcess = inHostProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,38 +1,37 @@
|
|||||||
/*
|
/*
|
||||||
* QAuxiliary - An Xposed module for QQ/TIM
|
* QAuxiliary - An Xposed module for QQ/TIM
|
||||||
* Copyright (C) 2019-2022 qwq233@qwq2333.top
|
* Copyright (C) 2019-2024 QAuxiliary developers
|
||||||
* https://github.com/cinit/QAuxiliary
|
* https://github.com/cinit/QAuxiliary
|
||||||
*
|
*
|
||||||
* This software is non-free but opensource software: you can redistribute it
|
* This software is an opensource software: you can redistribute it
|
||||||
* and/or modify it under the terms of the GNU Affero General Public License
|
* and/or modify it under the terms of the General Public License
|
||||||
* as published by the Free Software Foundation; either
|
* as published by the Free Software Foundation; either
|
||||||
* version 3 of the License, or any later version and our eula as published
|
* version 3 of the License, or any later version as published
|
||||||
* by QAuxiliary contributors.
|
* by QAuxiliary contributors.
|
||||||
*
|
*
|
||||||
* This software is distributed in the hope that it will be useful,
|
* This software is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* Affero General Public License for more details.
|
* See the General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the General Public License
|
||||||
* and eula along with this software. If not, see
|
* along with this software.
|
||||||
* <https://www.gnu.org/licenses/>
|
* If not, see
|
||||||
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
* <https://github.com/cinit/QAuxiliary/blob/master/LICENSE.md>.
|
||||||
*/
|
*/
|
||||||
package io.github.qauxv.startup;
|
package io.github.qauxv.poststartup;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import com.github.kyuubiran.ezxhelper.init.EzXHelperInit;
|
import com.github.kyuubiran.ezxhelper.init.InitFields;
|
||||||
|
import com.github.kyuubiran.ezxhelper.utils.Log;
|
||||||
import io.github.qauxv.core.MainHook;
|
import io.github.qauxv.core.MainHook;
|
||||||
import io.github.qauxv.core.NativeCoreBridge;
|
import io.github.qauxv.core.NativeCoreBridge;
|
||||||
import io.github.qauxv.util.HostInfo;
|
import io.github.qauxv.util.HostInfo;
|
||||||
import io.github.qauxv.util.Initiator;
|
import io.github.qauxv.util.Initiator;
|
||||||
import io.github.qauxv.util.Natives;
|
import io.github.qauxv.util.Natives;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import org.lsposed.hiddenapibypass.HiddenApiBypass;
|
|
||||||
|
|
||||||
public class StartupRoutine {
|
public class StartupRoutine {
|
||||||
|
|
||||||
@@ -51,16 +50,13 @@ public class StartupRoutine {
|
|||||||
* @param bReserved false, not used
|
* @param bReserved false, not used
|
||||||
*/
|
*/
|
||||||
public static void execPostStartupInit(Context ctx, Object step, String lpwReserved, boolean bReserved) {
|
public static void execPostStartupInit(Context ctx, Object step, String lpwReserved, boolean bReserved) {
|
||||||
ensureHiddenApiAccess();
|
|
||||||
// init all kotlin utils here
|
// init all kotlin utils here
|
||||||
EzXHelperInit.INSTANCE.initZygote(HookEntry.getInitZygoteStartupParam());
|
|
||||||
EzXHelperInit.INSTANCE.initHandleLoadPackage(HookEntry.getLoadPackageParam());
|
|
||||||
// resource injection is done somewhere else, do not init it here
|
|
||||||
EzXHelperInit.INSTANCE.initAppContext(ctx, false, false);
|
|
||||||
EzXHelperInit.INSTANCE.setLogTag("QAuxv");
|
|
||||||
HostInfo.init((Application) ctx);
|
HostInfo.init((Application) ctx);
|
||||||
Initiator.init(ctx.getClassLoader());
|
Initiator.init(ctx.getClassLoader());
|
||||||
Natives.load(ctx);
|
InitFields.ezXClassLoader = ctx.getClassLoader();
|
||||||
|
// resource injection is done somewhere else, do not init it here
|
||||||
|
Log.INSTANCE.getCurrentLogger().setLogTag("QAuxv");
|
||||||
|
Natives.initialize(ctx);
|
||||||
overrideLSPatchModifiedVersionCodeIfNecessary(ctx);
|
overrideLSPatchModifiedVersionCodeIfNecessary(ctx);
|
||||||
NativeCoreBridge.initNativeCore(ctx.getPackageName(), Build.VERSION.SDK_INT,
|
NativeCoreBridge.initNativeCore(ctx.getPackageName(), Build.VERSION.SDK_INT,
|
||||||
HostInfo.getHostInfo().getVersionName(), HostInfo.getHostInfo().getVersionCode());
|
HostInfo.getHostInfo().getVersionName(), HostInfo.getHostInfo().getVersionCode());
|
||||||
@@ -92,31 +88,4 @@ public class StartupRoutine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureHiddenApiAccess() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !isHiddenApiAccessible()) {
|
|
||||||
android.util.Log.w("QAuxv", "Hidden API access not accessible, SDK_INT is " + Build.VERSION.SDK_INT);
|
|
||||||
HiddenApiBypass.setHiddenApiExemptions("L");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint({"BlockedPrivateApi", "PrivateApi"})
|
|
||||||
public static boolean isHiddenApiAccessible() {
|
|
||||||
Class<?> kContextImpl;
|
|
||||||
try {
|
|
||||||
kContextImpl = Class.forName("android.app.ContextImpl");
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Field mActivityToken = null;
|
|
||||||
Field mToken = null;
|
|
||||||
try {
|
|
||||||
mActivityToken = kContextImpl.getDeclaredField("mActivityToken");
|
|
||||||
} catch (NoSuchFieldException ignored) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mToken = kContextImpl.getDeclaredField("mToken");
|
|
||||||
} catch (NoSuchFieldException ignored) {
|
|
||||||
}
|
|
||||||
return mActivityToken != null || mToken != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.qauxv.router.decorator
|
package io.github.qauxv.router.decorator
|
||||||
|
|
||||||
import de.robv.android.xposed.XC_MethodHook
|
import io.github.qauxv.util.xpcompat.XC_MethodHook
|
||||||
import io.github.qauxv.base.IDynamicHook
|
import io.github.qauxv.base.IDynamicHook
|
||||||
import io.github.qauxv.base.RuntimeErrorTracer
|
import io.github.qauxv.base.RuntimeErrorTracer
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user