mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-06 10:45:47 +08:00
Modify move YukiHookBridge.Hooker to YukiHookFactory and fix some bug / add some feature
This commit is contained in:
@@ -43,26 +43,30 @@ import com.highcapable.yukihookapi.hook.param.PackageParam
|
|||||||
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
||||||
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookPriority
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberHook
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberReplacement
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.Member
|
import java.lang.reflect.Member
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [YukiHookAPI] 的 [Member] 核心 Hook 实现类
|
* [YukiHookAPI] 的 [Member] 核心 Hook 实现类
|
||||||
*
|
*
|
||||||
* 核心 API 对接 [YukiHookBridge.Hooker] 实现
|
* 核心 API 对接 [YukiHookHelper] 实现
|
||||||
* @param packageParam 需要传入 [PackageParam] 实现方法调用
|
* @param packageParam 需要传入 [PackageParam] 实现方法调用
|
||||||
* @param hookClass 要 Hook 的 [HookClass] 实例
|
* @param hookClass 要 Hook 的 [HookClass] 实例
|
||||||
*/
|
*/
|
||||||
class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackageParam, @PublishedApi internal val hookClass: HookClass) {
|
class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackageParam, @PublishedApi internal val hookClass: HookClass) {
|
||||||
|
|
||||||
/** 默认 Hook 回调优先级 */
|
/** 默认 Hook 回调优先级 */
|
||||||
val PRIORITY_DEFAULT = YukiHookBridge.Hooker.PRIORITY_DEFAULT
|
val PRIORITY_DEFAULT = YukiHookPriority.PRIORITY_DEFAULT
|
||||||
|
|
||||||
/** 延迟回调 Hook 方法结果 */
|
/** 延迟回调 Hook 方法结果 */
|
||||||
val PRIORITY_LOWEST = YukiHookBridge.Hooker.PRIORITY_LOWEST
|
val PRIORITY_LOWEST = YukiHookPriority.PRIORITY_LOWEST
|
||||||
|
|
||||||
/** 更快回调 Hook 方法结果 */
|
/** 更快回调 Hook 方法结果 */
|
||||||
val PRIORITY_HIGHEST = YukiHookBridge.Hooker.PRIORITY_HIGHEST
|
val PRIORITY_HIGHEST = YukiHookPriority.PRIORITY_HIGHEST
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 模式定义
|
* Hook 模式定义
|
||||||
@@ -208,7 +212,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
private var allMethodsName = ""
|
private var allMethodsName = ""
|
||||||
|
|
||||||
/** 当前被 Hook 的方法、构造方法实例 */
|
/** 当前被 Hook 的方法、构造方法实例 */
|
||||||
private var hookedMember: YukiHookBridge.Hooker.YukiHookedMember? = null
|
private var memberUnhook: YukiMemberHook.Unhook? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动指定要 Hook 的方法、构造方法
|
* 手动指定要 Hook 的方法、构造方法
|
||||||
@@ -458,7 +462,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
val replaceHookParam = HookParam(createrInstance = this@YukiMemberHookCreater)
|
val replaceHookParam = HookParam(createrInstance = this@YukiMemberHookCreater)
|
||||||
|
|
||||||
/** 定义替换 Hook 回调方法体 */
|
/** 定义替换 Hook 回调方法体 */
|
||||||
val replaceMent = object : YukiHookBridge.Hooker.YukiMemberReplacement(priority) {
|
val replaceMent = object : YukiMemberReplacement(priority) {
|
||||||
override fun replaceHookedMember(wrapper: HookParamWrapper): Any? {
|
override fun replaceHookedMember(wrapper: HookParamWrapper): Any? {
|
||||||
return replaceHookParam.assign(wrapper).let { param ->
|
return replaceHookParam.assign(wrapper).let { param ->
|
||||||
try {
|
try {
|
||||||
@@ -482,7 +486,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
val afterHookParam = HookParam(createrInstance = this@YukiMemberHookCreater)
|
val afterHookParam = HookParam(createrInstance = this@YukiMemberHookCreater)
|
||||||
|
|
||||||
/** 定义前后 Hook 回调方法体 */
|
/** 定义前后 Hook 回调方法体 */
|
||||||
val beforeAfterHook = object : YukiHookBridge.Hooker.YukiMemberHook(priority) {
|
val beforeAfterHook = object : YukiMemberHook(priority) {
|
||||||
override fun beforeHookedMember(wrapper: HookParamWrapper) {
|
override fun beforeHookedMember(wrapper: HookParamWrapper) {
|
||||||
beforeHookParam.assign(wrapper).also { param ->
|
beforeHookParam.assign(wrapper).also { param ->
|
||||||
runCatching {
|
runCatching {
|
||||||
@@ -517,13 +521,13 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
if (member != null)
|
if (member != null)
|
||||||
member.also { member ->
|
member.also { member ->
|
||||||
runCatching {
|
runCatching {
|
||||||
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookMethod(member, replaceMent)
|
(if (isReplaceHookMode) YukiHookHelper.hookMethod(member, replaceMent)
|
||||||
else YukiHookBridge.Hooker.hookMethod(member, beforeAfterHook)).also {
|
else YukiHookHelper.hookMethod(member, beforeAfterHook)).also {
|
||||||
when {
|
when {
|
||||||
it.first.member == null -> error("Hook Member [$member] failed")
|
it.first.member == null -> error("Hook Member [$member] failed")
|
||||||
it.second -> onAlreadyHookedCallback?.invoke(it.first.member!!)
|
it.second -> onAlreadyHookedCallback?.invoke(it.first.member!!)
|
||||||
else -> {
|
else -> {
|
||||||
hookedMember = it.first
|
memberUnhook = it.first
|
||||||
onHookedCallback?.invoke(it.first.member!!)
|
onHookedCallback?.invoke(it.first.member!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -548,25 +552,25 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
else runCatching {
|
else runCatching {
|
||||||
when (hookMemberMode) {
|
when (hookMemberMode) {
|
||||||
HookMemberMode.HOOK_ALL_METHODS ->
|
HookMemberMode.HOOK_ALL_METHODS ->
|
||||||
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, replaceMent)
|
(if (isReplaceHookMode) YukiHookHelper.hookAllMethods(hookClass.instance, allMethodsName, replaceMent)
|
||||||
else YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook)).also {
|
else YukiHookHelper.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook)).also {
|
||||||
when {
|
when {
|
||||||
it.first.isEmpty() -> throw NoSuchMethodError("No Method name \"$allMethodsName\" matched")
|
it.first.isEmpty() -> throw NoSuchMethodError("No Method name \"$allMethodsName\" matched")
|
||||||
it.second -> it.first.forEach { e -> if (e.member != null) onAlreadyHookedCallback?.invoke(e.member!!) }
|
it.second -> it.first.forEach { e -> if (e.member != null) onAlreadyHookedCallback?.invoke(e.member!!) }
|
||||||
else -> {
|
else -> {
|
||||||
hookedMember = it.first.first()
|
memberUnhook = it.first.first()
|
||||||
it.first.forEach { e -> if (e.member != null) onHookedCallback?.invoke(e.member!!) }
|
it.first.forEach { e -> if (e.member != null) onHookedCallback?.invoke(e.member!!) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HookMemberMode.HOOK_ALL_CONSTRUCTORS ->
|
HookMemberMode.HOOK_ALL_CONSTRUCTORS ->
|
||||||
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, replaceMent)
|
(if (isReplaceHookMode) YukiHookHelper.hookAllConstructors(hookClass.instance, replaceMent)
|
||||||
else YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, beforeAfterHook)).also {
|
else YukiHookHelper.hookAllConstructors(hookClass.instance, beforeAfterHook)).also {
|
||||||
when {
|
when {
|
||||||
it.first.isEmpty() -> throw NoSuchMethodError("No Constructor matched")
|
it.first.isEmpty() -> throw NoSuchMethodError("No Constructor matched")
|
||||||
it.second -> it.first.forEach { e -> if (e.member != null) onAlreadyHookedCallback?.invoke(e.member!!) }
|
it.second -> it.first.forEach { e -> if (e.member != null) onAlreadyHookedCallback?.invoke(e.member!!) }
|
||||||
else -> {
|
else -> {
|
||||||
hookedMember = it.first.first()
|
memberUnhook = it.first.first()
|
||||||
it.first.forEach { e -> if (e.member != null) onHookedCallback?.invoke(e.member!!) }
|
it.first.forEach { e -> if (e.member != null) onHookedCallback?.invoke(e.member!!) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -736,10 +740,11 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
|||||||
* @param result 回调是否成功
|
* @param result 回调是否成功
|
||||||
*/
|
*/
|
||||||
fun remove(result: (Boolean) -> Unit = {}) {
|
fun remove(result: (Boolean) -> Unit = {}) {
|
||||||
hookedMember?.unhook()
|
memberUnhook?.remove()
|
||||||
runCatching { preHookMembers.remove(this@MemberHookCreater.toString()) }
|
runCatching { preHookMembers.remove(this@MemberHookCreater.toString()) }
|
||||||
result(hookedMember != null)
|
if (memberUnhook != null) onHookLogMsg(msg = "Remove Hooked Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
|
||||||
hookedMember = null
|
result(memberUnhook != null)
|
||||||
|
memberUnhook = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,17 +48,19 @@ import com.highcapable.yukihookapi.hook.type.android.*
|
|||||||
import com.highcapable.yukihookapi.hook.type.java.IntType
|
import com.highcapable.yukihookapi.hook.type.java.IntType
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiModuleResources
|
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiModuleResources
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
|
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberHook
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberReplacement
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.inject.YukiHookBridge_Injector
|
import com.highcapable.yukihookapi.hook.xposed.bridge.inject.YukiHookBridge_Injector
|
||||||
import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
|
import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus
|
||||||
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
|
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
|
||||||
import dalvik.system.PathClassLoader
|
import dalvik.system.PathClassLoader
|
||||||
import de.robv.android.xposed.*
|
import de.robv.android.xposed.IXposedHookInitPackageResources
|
||||||
|
import de.robv.android.xposed.IXposedHookLoadPackage
|
||||||
|
import de.robv.android.xposed.IXposedHookZygoteInit
|
||||||
|
import de.robv.android.xposed.XposedBridge
|
||||||
import de.robv.android.xposed.callbacks.XC_InitPackageResources
|
import de.robv.android.xposed.callbacks.XC_InitPackageResources
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||||
import java.lang.reflect.Constructor
|
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.lang.reflect.Member
|
|
||||||
import java.lang.reflect.Method
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 这是一个对接 Xposed Hook 入口与 [XposedBridge] 的装载类实现桥
|
* 这是一个对接 Xposed Hook 入口与 [XposedBridge] 的装载类实现桥
|
||||||
@@ -124,8 +126,8 @@ object YukiHookBridge {
|
|||||||
*/
|
*/
|
||||||
internal val systemContext
|
internal val systemContext
|
||||||
get() = runCatching {
|
get() = runCatching {
|
||||||
Hooker.findMethod(ActivityThreadClass, name = "getSystemContext")
|
YukiHookHelper.findMethod(ActivityThreadClass, name = "getSystemContext")
|
||||||
.invoke(Hooker.findMethod(ActivityThreadClass, name = "currentActivityThread").invoke(null)) as? Context?
|
.invoke(YukiHookHelper.findMethod(ActivityThreadClass, name = "currentActivityThread").invoke(null)) as? Context?
|
||||||
}.getOrNull() ?: error("Failed to got SystemContext")
|
}.getOrNull() ?: error("Failed to got SystemContext")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +156,7 @@ object YukiHookBridge {
|
|||||||
*/
|
*/
|
||||||
internal val executorName
|
internal val executorName
|
||||||
get() = runCatching {
|
get() = runCatching {
|
||||||
(Hooker.findField(XposedBridge::class.java, name = "TAG").get(null) as? String?)
|
(YukiHookHelper.findField(XposedBridge::class.java, name = "TAG").get(null) as? String?)
|
||||||
?.replace(oldValue = "Bridge", newValue = "")?.replace(oldValue = "-", newValue = "")?.trim() ?: "unknown"
|
?.replace(oldValue = "Bridge", newValue = "")?.replace(oldValue = "-", newValue = "")?.trim() ?: "unknown"
|
||||||
}.getOrNull() ?: "invalid"
|
}.getOrNull() ?: "invalid"
|
||||||
|
|
||||||
@@ -241,7 +243,7 @@ object YukiHookBridge {
|
|||||||
/** Hook [Application] 装载方法 */
|
/** Hook [Application] 装载方法 */
|
||||||
runCatching {
|
runCatching {
|
||||||
if (AppLifecycleCallback.isCallbackSetUp) {
|
if (AppLifecycleCallback.isCallbackSetUp) {
|
||||||
Hooker.hookMethod(Hooker.findMethod(ApplicationClass, name = "attach", ContextClass), object : Hooker.YukiMemberHook() {
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(ApplicationClass, name = "attach", ContextClass), object : YukiMemberHook() {
|
||||||
override fun beforeHookedMember(wrapper: HookParamWrapper) {
|
override fun beforeHookedMember(wrapper: HookParamWrapper) {
|
||||||
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, false) }
|
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, false) }
|
||||||
}
|
}
|
||||||
@@ -250,26 +252,27 @@ object YukiHookBridge {
|
|||||||
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, true) }
|
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, true) }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Hooker.hookMethod(Hooker.findMethod(ApplicationClass, name = "onTerminate"), object : Hooker.YukiMemberHook() {
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(ApplicationClass, name = "onTerminate"), object : YukiMemberHook() {
|
||||||
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
||||||
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onTerminateCallback?.invoke(it) }
|
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onTerminateCallback?.invoke(it) }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Hooker.hookMethod(Hooker.findMethod(ApplicationClass, name = "onLowMemory"), object : Hooker.YukiMemberHook() {
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(ApplicationClass, name = "onLowMemory"), object : YukiMemberHook() {
|
||||||
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
||||||
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onLowMemoryCallback?.invoke(it) }
|
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onLowMemoryCallback?.invoke(it) }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Hooker.hookMethod(Hooker.findMethod(ApplicationClass, name = "onTrimMemory", IntType), object : Hooker.YukiMemberHook() {
|
YukiHookHelper.hookMethod(
|
||||||
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
YukiHookHelper.findMethod(ApplicationClass, name = "onTrimMemory", IntType),
|
||||||
val self = wrapper.instance as? Application? ?: return
|
object : YukiMemberHook() {
|
||||||
val type = wrapper.args?.get(0) as? Int? ?: return
|
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
||||||
AppLifecycleCallback.onTrimMemoryCallback?.invoke(self, type)
|
val self = wrapper.instance as? Application? ?: return
|
||||||
}
|
val type = wrapper.args?.get(0) as? Int? ?: return
|
||||||
})
|
AppLifecycleCallback.onTrimMemoryCallback?.invoke(self, type)
|
||||||
Hooker.hookMethod(
|
}
|
||||||
Hooker.findMethod(ApplicationClass, name = "onConfigurationChanged", ConfigurationClass),
|
})
|
||||||
object : Hooker.YukiMemberHook() {
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(ApplicationClass, name = "onConfigurationChanged", ConfigurationClass),
|
||||||
|
object : YukiMemberHook() {
|
||||||
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
||||||
val self = wrapper.instance as? Application? ?: return
|
val self = wrapper.instance as? Application? ?: return
|
||||||
val config = wrapper.args?.get(0) as? Configuration? ?: return
|
val config = wrapper.args?.get(0) as? Configuration? ?: return
|
||||||
@@ -278,9 +281,9 @@ object YukiHookBridge {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (YukiHookAPI.Configs.isEnableDataChannel || AppLifecycleCallback.isCallbackSetUp)
|
if (YukiHookAPI.Configs.isEnableDataChannel || AppLifecycleCallback.isCallbackSetUp)
|
||||||
Hooker.hookMethod(
|
YukiHookHelper.hookMethod(
|
||||||
Hooker.findMethod(InstrumentationClass, name = "callApplicationOnCreate", ApplicationClass),
|
YukiHookHelper.findMethod(InstrumentationClass, name = "callApplicationOnCreate", ApplicationClass),
|
||||||
object : Hooker.YukiMemberHook() {
|
object : YukiMemberHook() {
|
||||||
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
override fun afterHookedMember(wrapper: HookParamWrapper) {
|
||||||
(wrapper.args?.get(0) as? Application?)?.also {
|
(wrapper.args?.get(0) as? Application?)?.also {
|
||||||
hostApplication = it
|
hostApplication = it
|
||||||
@@ -317,23 +320,23 @@ object YukiHookBridge {
|
|||||||
@YukiGenerateApi
|
@YukiGenerateApi
|
||||||
fun hookModuleAppStatus(classLoader: ClassLoader?, isHookResourcesStatus: Boolean = false) {
|
fun hookModuleAppStatus(classLoader: ClassLoader?, isHookResourcesStatus: Boolean = false) {
|
||||||
if (YukiHookAPI.Configs.isEnableHookModuleStatus)
|
if (YukiHookAPI.Configs.isEnableHookModuleStatus)
|
||||||
Hooker.findClass(classLoader, YukiHookModuleStatus::class.java).also { statusClass ->
|
YukiHookHelper.findClass(classLoader, YukiHookModuleStatus::class.java).also { statusClass ->
|
||||||
if (isHookResourcesStatus.not()) {
|
if (isHookResourcesStatus.not()) {
|
||||||
Hooker.hookMethod(Hooker.findMethod(statusClass, YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME),
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME),
|
||||||
object : Hooker.YukiMemberReplacement() {
|
object : YukiMemberReplacement() {
|
||||||
override fun replaceHookedMember(wrapper: HookParamWrapper) = true
|
override fun replaceHookedMember(wrapper: HookParamWrapper) = true
|
||||||
})
|
})
|
||||||
Hooker.hookMethod(Hooker.findMethod(statusClass, YukiHookModuleStatus.GET_XPOSED_TAG_METHOD_NAME),
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.GET_XPOSED_TAG_METHOD_NAME),
|
||||||
object : Hooker.YukiMemberReplacement() {
|
object : YukiMemberReplacement() {
|
||||||
override fun replaceHookedMember(wrapper: HookParamWrapper) = executorName
|
override fun replaceHookedMember(wrapper: HookParamWrapper) = executorName
|
||||||
})
|
})
|
||||||
Hooker.hookMethod(Hooker.findMethod(statusClass, YukiHookModuleStatus.GET_XPOSED_VERSION_METHOD_NAME),
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.GET_XPOSED_VERSION_METHOD_NAME),
|
||||||
object : Hooker.YukiMemberReplacement() {
|
object : YukiMemberReplacement() {
|
||||||
override fun replaceHookedMember(wrapper: HookParamWrapper) = executorVersion
|
override fun replaceHookedMember(wrapper: HookParamWrapper) = executorVersion
|
||||||
})
|
})
|
||||||
} else
|
} else
|
||||||
Hooker.hookMethod(Hooker.findMethod(statusClass, YukiHookModuleStatus.HAS_RESOURCES_HOOK_METHOD_NAME),
|
YukiHookHelper.hookMethod(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.HAS_RESOURCES_HOOK_METHOD_NAME),
|
||||||
object : Hooker.YukiMemberReplacement() {
|
object : YukiMemberReplacement() {
|
||||||
override fun replaceHookedMember(wrapper: HookParamWrapper) = true
|
override fun replaceHookedMember(wrapper: HookParamWrapper) = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -430,247 +433,4 @@ object YukiHookBridge {
|
|||||||
/** 系统广播监听回调 */
|
/** 系统广播监听回调 */
|
||||||
internal val onReceiversCallback = HashMap<String, Pair<Array<out String>, (Context, Intent) -> Unit>>()
|
internal val onReceiversCallback = HashMap<String, Pair<Array<out String>, (Context, Intent) -> Unit>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 核心功能实现实例
|
|
||||||
*
|
|
||||||
* 对接 [XposedBridge] 实现 Hook 功能
|
|
||||||
*/
|
|
||||||
internal object Hooker {
|
|
||||||
|
|
||||||
/** 已经 Hook 的 [Member] 数组 */
|
|
||||||
private val hookedMembers = HashSet<YukiHookedMember>()
|
|
||||||
|
|
||||||
/** 已经 Hook 的全部 [Method] 数组 */
|
|
||||||
private val hookedAllMethods = HashMap<String, HashSet<YukiHookedMember>>()
|
|
||||||
|
|
||||||
/** 已经 Hook 的全部 [Constructor] 数组 */
|
|
||||||
private val hookedAllConstructors = HashMap<String, HashSet<YukiHookedMember>>()
|
|
||||||
|
|
||||||
/** 默认 Hook 回调优先级 */
|
|
||||||
internal const val PRIORITY_DEFAULT = 50
|
|
||||||
|
|
||||||
/** 延迟回调 Hook 方法结果 */
|
|
||||||
internal const val PRIORITY_LOWEST = -10000
|
|
||||||
|
|
||||||
/** 更快回调 Hook 方法结果 */
|
|
||||||
internal const val PRIORITY_HIGHEST = 10000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找 [Class]
|
|
||||||
* @param classLoader 当前 [ClassLoader]
|
|
||||||
* @param baseClass 当前类
|
|
||||||
* @return [Field]
|
|
||||||
* @throws IllegalStateException 如果 [ClassLoader] 为空
|
|
||||||
*/
|
|
||||||
internal fun findClass(classLoader: ClassLoader?, baseClass: Class<*>) =
|
|
||||||
classLoader?.loadClass(baseClass.name) ?: error("ClassLoader is null")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找变量
|
|
||||||
* @param baseClass 所在类
|
|
||||||
* @param name 变量名称
|
|
||||||
* @return [Field]
|
|
||||||
* @throws NoSuchFieldError 如果找不到变量
|
|
||||||
*/
|
|
||||||
internal fun findField(baseClass: Class<*>, name: String) = baseClass.getDeclaredField(name).apply { isAccessible = true }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找方法
|
|
||||||
* @param baseClass 所在类
|
|
||||||
* @param name 方法名称
|
|
||||||
* @param paramTypes 方法参数
|
|
||||||
* @return [Method]
|
|
||||||
* @throws NoSuchMethodError 如果找不到方法
|
|
||||||
*/
|
|
||||||
internal fun findMethod(baseClass: Class<*>, name: String, vararg paramTypes: Class<*>) =
|
|
||||||
baseClass.getDeclaredMethod(name, *paramTypes).apply { isAccessible = true }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 方法
|
|
||||||
*
|
|
||||||
* 对接 [XposedBridge.hookMethod]
|
|
||||||
* @param hookMethod 需要 Hook 的方法、构造方法
|
|
||||||
* @param callback 回调
|
|
||||||
* @return [Pair] - ([YukiHookedMember],[Boolean] 是否已经 Hook)
|
|
||||||
*/
|
|
||||||
internal fun hookMethod(hookMethod: Member?, callback: YukiHookCallback): Pair<YukiHookedMember, Boolean> {
|
|
||||||
runCatching {
|
|
||||||
hookedMembers.takeIf { it.isNotEmpty() }?.forEach {
|
|
||||||
if (it.member.toString() == hookMethod.toString()) return@runCatching it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return YukiHookedMember.wrapper(XposedBridge.hookMethod(hookMethod, compatCallback(callback))).let {
|
|
||||||
hookedMembers.add(it)
|
|
||||||
Pair(it, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 当前 [hookClass] 所有 [methodName] 的方法
|
|
||||||
*
|
|
||||||
* 对接 [XposedBridge.hookAllMethods]
|
|
||||||
* @param hookClass 当前 Hook 的 [Class]
|
|
||||||
* @param methodName 方法名
|
|
||||||
* @param callback 回调
|
|
||||||
* @return [Pair] - ([HashSet] 成功 Hook 的 [YukiHookedMember] 数组,[Boolean] 是否已经 Hook)
|
|
||||||
*/
|
|
||||||
internal fun hookAllMethods(
|
|
||||||
hookClass: Class<*>?, methodName: String, callback: YukiHookCallback
|
|
||||||
): Pair<HashSet<YukiHookedMember>, Boolean> {
|
|
||||||
var isAlreadyHook = false
|
|
||||||
val hookedMembers = HashSet<YukiHookedMember>().also {
|
|
||||||
val allMethodsName = "$hookClass$methodName"
|
|
||||||
if (hookedAllMethods.contains(allMethodsName)) {
|
|
||||||
isAlreadyHook = true
|
|
||||||
hookedAllMethods[allMethodsName]?.forEach { e -> it.add(e) }
|
|
||||||
return@also
|
|
||||||
}
|
|
||||||
XposedBridge.hookAllMethods(hookClass, methodName, compatCallback(callback)).takeIf { e -> e.isNotEmpty() }
|
|
||||||
?.forEach { e -> it.add(YukiHookedMember.wrapper(e, allMethodsName)) }
|
|
||||||
hookedAllMethods[allMethodsName] = it
|
|
||||||
}
|
|
||||||
return Pair(hookedMembers, isAlreadyHook)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 当前 [hookClass] 所有构造方法
|
|
||||||
*
|
|
||||||
* 对接 [XposedBridge.hookAllConstructors]
|
|
||||||
* @param hookClass 当前 Hook 的 [Class]
|
|
||||||
* @param callback 回调
|
|
||||||
* @return [Pair] - ([HashSet] 成功 Hook 的 [YukiHookedMember] 数组,[Boolean] 是否已经 Hook)
|
|
||||||
*/
|
|
||||||
internal fun hookAllConstructors(hookClass: Class<*>?, callback: YukiHookCallback): Pair<HashSet<YukiHookedMember>, Boolean> {
|
|
||||||
var isAlreadyHook = false
|
|
||||||
val hookedMembers = HashSet<YukiHookedMember>().also {
|
|
||||||
val allConstructorsName = "$hookClass<init>"
|
|
||||||
if (hookedAllConstructors.contains(allConstructorsName)) {
|
|
||||||
isAlreadyHook = true
|
|
||||||
hookedAllConstructors[allConstructorsName]?.forEach { e -> it.add(e) }
|
|
||||||
return@also
|
|
||||||
}
|
|
||||||
XposedBridge.hookAllConstructors(hookClass, compatCallback(callback)).takeIf { e -> e.isNotEmpty() }
|
|
||||||
?.forEach { e -> it.add(YukiHookedMember.wrapper(e, allConstructorsName)) }
|
|
||||||
hookedAllConstructors[allConstructorsName] = it
|
|
||||||
}
|
|
||||||
return Pair(hookedMembers, isAlreadyHook)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 兼容对接 Hook 回调接口
|
|
||||||
* @param callback [YukiHookCallback] 接口
|
|
||||||
* @return [XC_MethodHook] 原始接口
|
|
||||||
*/
|
|
||||||
private fun compatCallback(callback: YukiHookCallback) = when (callback) {
|
|
||||||
is YukiMemberHook -> object : XC_MethodHook(callback.priority) {
|
|
||||||
|
|
||||||
/** 创建 Hook 前 [HookParamWrapper] */
|
|
||||||
val beforeHookWrapper = HookParamWrapper()
|
|
||||||
|
|
||||||
/** 创建 Hook 后 [HookParamWrapper] */
|
|
||||||
val afterHookWrapper = HookParamWrapper()
|
|
||||||
|
|
||||||
override fun beforeHookedMethod(param: MethodHookParam?) {
|
|
||||||
if (param == null) return
|
|
||||||
callback.beforeHookedMember(beforeHookWrapper.assign(param))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterHookedMethod(param: MethodHookParam?) {
|
|
||||||
if (param == null) return
|
|
||||||
callback.afterHookedMember(afterHookWrapper.assign(param))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is YukiMemberReplacement -> object : XC_MethodReplacement(callback.priority) {
|
|
||||||
|
|
||||||
/** 创建替换 Hook [HookParamWrapper] */
|
|
||||||
val replaceHookWrapper = HookParamWrapper()
|
|
||||||
|
|
||||||
override fun replaceHookedMethod(param: MethodHookParam?): Any? {
|
|
||||||
if (param == null) return null
|
|
||||||
return callback.replaceHookedMember(replaceHookWrapper.assign(param))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> error("Invalid YukiHookCallback type")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 方法回调接口
|
|
||||||
* @param priority Hook 优先级 - 默认 [PRIORITY_DEFAULT]
|
|
||||||
*/
|
|
||||||
internal abstract class YukiMemberHook(override val priority: Int = PRIORITY_DEFAULT) : YukiHookCallback(priority) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在方法执行之前注入
|
|
||||||
* @param wrapper 包装实例
|
|
||||||
*/
|
|
||||||
open fun beforeHookedMember(wrapper: HookParamWrapper) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在方法执行之后注入
|
|
||||||
* @param wrapper 包装实例
|
|
||||||
*/
|
|
||||||
open fun afterHookedMember(wrapper: HookParamWrapper) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 替换方法回调接口
|
|
||||||
* @param priority Hook 优先级- 默认 [PRIORITY_DEFAULT]
|
|
||||||
*/
|
|
||||||
internal abstract class YukiMemberReplacement(override val priority: Int = PRIORITY_DEFAULT) : YukiHookCallback(priority) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拦截替换为指定结果
|
|
||||||
* @param wrapper 包装实例
|
|
||||||
* @return [Any] or null
|
|
||||||
*/
|
|
||||||
abstract fun replaceHookedMember(wrapper: HookParamWrapper): Any?
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook 回调接口父类
|
|
||||||
* @param priority Hook 优先级
|
|
||||||
*/
|
|
||||||
internal abstract class YukiHookCallback(open val priority: Int)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 已经 Hook 的 [Member] 实现类
|
|
||||||
* @param instance 对接 [XC_MethodHook.Unhook]
|
|
||||||
* @param tag 标识多个 [Member] Hook 的标签
|
|
||||||
*/
|
|
||||||
internal class YukiHookedMember private constructor(private val instance: XC_MethodHook.Unhook, private val tag: String) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 [XC_MethodHook.Unhook] 创建 [YukiHookedMember] 实例
|
|
||||||
* @param instance [XC_MethodHook.Unhook] 实例
|
|
||||||
* @param tag 标识多个 [Member] Hook 的标签 - 默认空
|
|
||||||
* @return [YukiHookedMember]
|
|
||||||
*/
|
|
||||||
internal fun wrapper(instance: XC_MethodHook.Unhook, tag: String = "") = YukiHookedMember(instance, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前被 Hook 的 [Member]
|
|
||||||
* @return [Member] or null
|
|
||||||
*/
|
|
||||||
internal val member: Member? get() = instance.hookedMethod
|
|
||||||
|
|
||||||
/** 解除 Hook */
|
|
||||||
internal fun unhook() {
|
|
||||||
if (tag.isNotBlank()) runCatching {
|
|
||||||
if (hookedAllMethods.contains(tag))
|
|
||||||
hookedAllMethods[tag]?.takeIf { it.isNotEmpty() }?.forEach { it.instance.unhook() }
|
|
||||||
if (hookedAllConstructors.contains(tag))
|
|
||||||
hookedAllConstructors[tag]?.takeIf { it.isNotEmpty() }?.forEach { it.instance.unhook() }
|
|
||||||
hookedAllMethods.remove(tag)
|
|
||||||
hookedAllConstructors.remove(tag)
|
|
||||||
} else {
|
|
||||||
instance.unhook()
|
|
||||||
runCatching { hookedMembers.remove(this) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -0,0 +1,304 @@
|
|||||||
|
/*
|
||||||
|
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
|
||||||
|
* Copyright (C) 2019-2022 HighCapable
|
||||||
|
* https://github.com/fankes/YukiHookAPI
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is Created by fankes on 2022/7/28.
|
||||||
|
*/
|
||||||
|
package com.highcapable.yukihookapi.hook.xposed.bridge.factory
|
||||||
|
|
||||||
|
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
||||||
|
import de.robv.android.xposed.XC_MethodHook
|
||||||
|
import de.robv.android.xposed.XposedBridge
|
||||||
|
import java.lang.reflect.Constructor
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
import java.lang.reflect.Member
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 回调优先级配置类
|
||||||
|
*/
|
||||||
|
internal object YukiHookPriority {
|
||||||
|
|
||||||
|
/** 默认 Hook 回调优先级 */
|
||||||
|
internal const val PRIORITY_DEFAULT = 50
|
||||||
|
|
||||||
|
/** 延迟回调 Hook 方法结果 */
|
||||||
|
internal const val PRIORITY_LOWEST = -10000
|
||||||
|
|
||||||
|
/** 更快回调 Hook 方法结果 */
|
||||||
|
internal const val PRIORITY_HIGHEST = 10000
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已经 Hook 的方法、构造方法缓存数组
|
||||||
|
*/
|
||||||
|
internal object YukiHookedMembers {
|
||||||
|
|
||||||
|
/** 已经 Hook 的 [Member] 数组 */
|
||||||
|
internal val hookedMembers = HashSet<YukiMemberHook.Unhook>()
|
||||||
|
|
||||||
|
/** 已经 Hook 的成组 [Method] 数组 */
|
||||||
|
internal val hookedQueueMethods = HashMap<String, HashSet<YukiMemberHook.Unhook>>()
|
||||||
|
|
||||||
|
/** 已经 Hook 的成组 [Constructor] 数组 */
|
||||||
|
internal val hookedQueueConstructors = HashMap<String, HashSet<YukiMemberHook.Unhook>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 核心功能实现实例
|
||||||
|
*
|
||||||
|
* 对接 [XposedBridge] 实现 Hook 功能
|
||||||
|
*/
|
||||||
|
internal object YukiHookHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找 [Class]
|
||||||
|
* @param classLoader 当前 [ClassLoader]
|
||||||
|
* @param baseClass 当前类
|
||||||
|
* @return [Field]
|
||||||
|
* @throws IllegalStateException 如果 [ClassLoader] 为空
|
||||||
|
*/
|
||||||
|
internal fun findClass(classLoader: ClassLoader?, baseClass: Class<*>) =
|
||||||
|
classLoader?.loadClass(baseClass.name) ?: error("ClassLoader is null")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找变量
|
||||||
|
* @param baseClass 所在类
|
||||||
|
* @param name 变量名称
|
||||||
|
* @return [Field]
|
||||||
|
* @throws NoSuchFieldError 如果找不到变量
|
||||||
|
*/
|
||||||
|
internal fun findField(baseClass: Class<*>, name: String) = baseClass.getDeclaredField(name).apply { isAccessible = true }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找方法
|
||||||
|
* @param baseClass 所在类
|
||||||
|
* @param name 方法名称
|
||||||
|
* @param paramTypes 方法参数
|
||||||
|
* @return [Method]
|
||||||
|
* @throws NoSuchMethodError 如果找不到方法
|
||||||
|
*/
|
||||||
|
internal fun findMethod(baseClass: Class<*>, name: String, vararg paramTypes: Class<*>) =
|
||||||
|
baseClass.getDeclaredMethod(name, *paramTypes).apply { isAccessible = true }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 方法
|
||||||
|
*
|
||||||
|
* 对接 [XposedBridge.hookMethod]
|
||||||
|
* @param hookMethod 需要 Hook 的方法、构造方法
|
||||||
|
* @param callback 回调
|
||||||
|
* @return [Pair] - ([YukiMemberHook.Unhook],[Boolean] 是否已经 Hook)
|
||||||
|
*/
|
||||||
|
internal fun hookMethod(hookMethod: Member?, callback: YukiHookCallback): Pair<YukiMemberHook.Unhook, Boolean> {
|
||||||
|
runCatching {
|
||||||
|
YukiHookedMembers.hookedMembers.takeIf { it.isNotEmpty() }?.forEach {
|
||||||
|
if (it.member.toString() == hookMethod.toString()) return@runCatching it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return YukiMemberHook.Unhook.wrapper(XposedBridge.hookMethod(hookMethod, callback.compat())).let {
|
||||||
|
YukiHookedMembers.hookedMembers.add(it)
|
||||||
|
Pair(it, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 当前 [hookClass] 所有 [methodName] 的方法
|
||||||
|
*
|
||||||
|
* 对接 [XposedBridge.hookAllMethods]
|
||||||
|
* @param hookClass 当前 Hook 的 [Class]
|
||||||
|
* @param methodName 方法名
|
||||||
|
* @param callback 回调
|
||||||
|
* @return [Pair] - ([HashSet] 成功 Hook 的 [YukiMemberHook.Unhook] 数组,[Boolean] 是否已经 Hook)
|
||||||
|
*/
|
||||||
|
internal fun hookAllMethods(
|
||||||
|
hookClass: Class<*>?, methodName: String, callback: YukiHookCallback
|
||||||
|
): Pair<HashSet<YukiMemberHook.Unhook>, Boolean> {
|
||||||
|
var isAlreadyHook = false
|
||||||
|
val hookedMembers = HashSet<YukiMemberHook.Unhook>().also {
|
||||||
|
val allMethodsName = "$hookClass$methodName"
|
||||||
|
if (YukiHookedMembers.hookedQueueMethods.contains(allMethodsName)) {
|
||||||
|
isAlreadyHook = true
|
||||||
|
YukiHookedMembers.hookedQueueMethods[allMethodsName]?.forEach { e -> it.add(e) }
|
||||||
|
return@also
|
||||||
|
}
|
||||||
|
XposedBridge.hookAllMethods(hookClass, methodName, callback.compat()).takeIf { e -> e.isNotEmpty() }
|
||||||
|
?.forEach { e -> it.add(YukiMemberHook.Unhook.wrapper(e, allMethodsName)) }
|
||||||
|
YukiHookedMembers.hookedQueueMethods[allMethodsName] = it
|
||||||
|
}
|
||||||
|
return Pair(hookedMembers, isAlreadyHook)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 当前 [hookClass] 所有构造方法
|
||||||
|
*
|
||||||
|
* 对接 [XposedBridge.hookAllConstructors]
|
||||||
|
* @param hookClass 当前 Hook 的 [Class]
|
||||||
|
* @param callback 回调
|
||||||
|
* @return [Pair] - ([HashSet] 成功 Hook 的 [YukiMemberHook.Unhook] 数组,[Boolean] 是否已经 Hook)
|
||||||
|
*/
|
||||||
|
internal fun hookAllConstructors(hookClass: Class<*>?, callback: YukiHookCallback): Pair<HashSet<YukiMemberHook.Unhook>, Boolean> {
|
||||||
|
var isAlreadyHook = false
|
||||||
|
val hookedMembers = HashSet<YukiMemberHook.Unhook>().also {
|
||||||
|
val allConstructorsName = "$hookClass<init>"
|
||||||
|
if (YukiHookedMembers.hookedQueueConstructors.contains(allConstructorsName)) {
|
||||||
|
isAlreadyHook = true
|
||||||
|
YukiHookedMembers.hookedQueueConstructors[allConstructorsName]?.forEach { e -> it.add(e) }
|
||||||
|
return@also
|
||||||
|
}
|
||||||
|
XposedBridge.hookAllConstructors(hookClass, callback.compat()).takeIf { e -> e.isNotEmpty() }
|
||||||
|
?.forEach { e -> it.add(YukiMemberHook.Unhook.wrapper(e, allConstructorsName)) }
|
||||||
|
YukiHookedMembers.hookedQueueConstructors[allConstructorsName] = it
|
||||||
|
}
|
||||||
|
return Pair(hookedMembers, isAlreadyHook)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容对接 Hook 回调接口
|
||||||
|
* @return [XC_MethodHook] 原始接口
|
||||||
|
*/
|
||||||
|
private fun YukiHookCallback.compat() = object : XC_MethodHook(priority) {
|
||||||
|
|
||||||
|
/** 创建 Hook 前 [HookParamWrapper] */
|
||||||
|
private val beforeHookWrapper = HookParamWrapper()
|
||||||
|
|
||||||
|
/** 创建 Hook 后 [HookParamWrapper] */
|
||||||
|
private val afterHookWrapper = HookParamWrapper()
|
||||||
|
|
||||||
|
override fun beforeHookedMethod(param: MethodHookParam?) {
|
||||||
|
if (param == null) return
|
||||||
|
if (this@compat !is YukiMemberHook) error("Invalid YukiHookCallback type")
|
||||||
|
if (this@compat is YukiMemberReplacement)
|
||||||
|
param.result = replaceHookedMember(beforeHookWrapper.assign(param))
|
||||||
|
else beforeHookedMember(beforeHookWrapper.assign(param))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterHookedMethod(param: MethodHookParam?) {
|
||||||
|
if (param == null) return
|
||||||
|
if (this@compat !is YukiMemberHook) error("Invalid YukiHookCallback type")
|
||||||
|
afterHookedMember(afterHookWrapper.assign(param))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 替换方法回调接口
|
||||||
|
* @param priority Hook 优先级- 默认 [YukiHookPriority.PRIORITY_DEFAULT]
|
||||||
|
*/
|
||||||
|
internal abstract class YukiMemberReplacement(override val priority: Int = YukiHookPriority.PRIORITY_DEFAULT) : YukiMemberHook(priority) {
|
||||||
|
|
||||||
|
override fun beforeHookedMember(wrapper: HookParamWrapper) {
|
||||||
|
wrapper.result = replaceHookedMember(wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterHookedMember(wrapper: HookParamWrapper) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截替换为指定结果
|
||||||
|
* @param wrapper 包装实例
|
||||||
|
* @return [Any] or null
|
||||||
|
*/
|
||||||
|
abstract fun replaceHookedMember(wrapper: HookParamWrapper): Any?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 方法回调接口
|
||||||
|
* @param priority Hook 优先级 - 默认 [YukiHookPriority.PRIORITY_DEFAULT]
|
||||||
|
*/
|
||||||
|
internal abstract class YukiMemberHook(override val priority: Int = YukiHookPriority.PRIORITY_DEFAULT) : YukiHookCallback(priority) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在方法执行之前注入
|
||||||
|
* @param wrapper 包装实例
|
||||||
|
*/
|
||||||
|
open fun beforeHookedMember(wrapper: HookParamWrapper) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在方法执行之后注入
|
||||||
|
* @param wrapper 包装实例
|
||||||
|
*/
|
||||||
|
open fun afterHookedMember(wrapper: HookParamWrapper) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已经 Hook 且可被解除 Hook 的 [Member] 实现类
|
||||||
|
* @param instance 对接 [XC_MethodHook.Unhook]
|
||||||
|
* @param tag 标识多个 [Member] Hook 的标签 - 例如 [YukiHookHelper.hookAllMethods]、[YukiHookHelper.hookAllConstructors]
|
||||||
|
*/
|
||||||
|
internal class Unhook private constructor(private val instance: XC_MethodHook.Unhook, private val tag: String) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 [XC_MethodHook.Unhook] 创建 [Unhook] 实例
|
||||||
|
* @param instance [XC_MethodHook.Unhook] 实例
|
||||||
|
* @param tag 标识多个 [Member] Hook 的标签 - 默认空
|
||||||
|
* @return [Unhook]
|
||||||
|
*/
|
||||||
|
internal fun wrapper(instance: XC_MethodHook.Unhook, tag: String = "") = Unhook(instance, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前被 Hook 的 [Member]
|
||||||
|
* @return [Member] or null
|
||||||
|
*/
|
||||||
|
internal val member: Member? get() = instance.hookedMethod
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解除 Hook 并从
|
||||||
|
* [YukiHookedMembers.hookedMembers]、
|
||||||
|
* [YukiHookedMembers.hookedQueueMethods]、
|
||||||
|
* [YukiHookedMembers.hookedQueueConstructors]
|
||||||
|
* 缓存数组中移除
|
||||||
|
*/
|
||||||
|
internal fun remove() {
|
||||||
|
if (tag.isNotBlank()) runCatching {
|
||||||
|
when {
|
||||||
|
YukiHookedMembers.hookedQueueMethods.contains(tag) -> {
|
||||||
|
YukiHookedMembers.hookedQueueMethods[tag]?.takeIf { it.isNotEmpty() }?.forEach { it.unhook(isNeedRemove = false) }
|
||||||
|
YukiHookedMembers.hookedQueueMethods.remove(tag)
|
||||||
|
}
|
||||||
|
YukiHookedMembers.hookedQueueConstructors.contains(tag) -> {
|
||||||
|
YukiHookedMembers.hookedQueueConstructors[tag]?.takeIf { it.isNotEmpty() }?.forEach { it.unhook(isNeedRemove = false) }
|
||||||
|
YukiHookedMembers.hookedQueueConstructors.remove(tag)
|
||||||
|
}
|
||||||
|
else -> unhook()
|
||||||
|
}
|
||||||
|
} else unhook()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解除 [instance] 的 Hook
|
||||||
|
* @param isNeedRemove 是否需要从 [YukiHookedMembers.hookedMembers] 中移除
|
||||||
|
*/
|
||||||
|
private fun unhook(isNeedRemove: Boolean = true) {
|
||||||
|
instance.unhook()
|
||||||
|
if (isNeedRemove) runCatching { YukiHookedMembers.hookedMembers.remove(this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook 回调接口父类
|
||||||
|
* @param priority Hook 优先级
|
||||||
|
*/
|
||||||
|
internal abstract class YukiHookCallback(open val priority: Int)
|
Reference in New Issue
Block a user