mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-06 02:35:40 +08:00
Added unhook function in YukiHookBridge and YukiMemberHookCreater
This commit is contained in:
@@ -139,11 +139,12 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
* @param packageName 当前 Hook 的 APP 包名
|
||||
*/
|
||||
inner class MemberHookCreater @PublishedApi internal constructor(
|
||||
private val priority: Int,
|
||||
internal val tag: String,
|
||||
internal val packageName: String
|
||||
private val priority: Int, internal val tag: String, internal val packageName: String
|
||||
) {
|
||||
|
||||
/** Hook 结果实例 */
|
||||
private var result: Result? = null
|
||||
|
||||
/** 是否已经执行 Hook */
|
||||
private var isHooked = false
|
||||
|
||||
@@ -206,6 +207,9 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
/** 全部方法的名称 */
|
||||
private var allMethodsName = ""
|
||||
|
||||
/** 当前被 Hook 的方法、构造方法实例 */
|
||||
private var hookedMember: YukiHookBridge.Hooker.YukiHookedMember? = null
|
||||
|
||||
/**
|
||||
* 手动指定要 Hook 的方法、构造方法
|
||||
*
|
||||
@@ -421,12 +425,20 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
replaceHookResult = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除当前注入的 Hook 方法、构造方法 (解除 Hook)
|
||||
*
|
||||
* - ❗你只能在 Hook 回调方法中使用此功能
|
||||
* @param result 回调是否成功
|
||||
*/
|
||||
fun removeSelf(result: (Boolean) -> Unit = {}) = this.result?.remove(result) ?: result(false)
|
||||
|
||||
/**
|
||||
* Hook 创建入口
|
||||
* @return [Result]
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build() = Result()
|
||||
internal fun build() = Result().apply { result = this }
|
||||
|
||||
/** Hook 执行入口 */
|
||||
@PublishedApi
|
||||
@@ -508,9 +520,12 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
(if (isReplaceHookMode) YukiHookBridge.Hooker.hookMethod(member, replaceMent)
|
||||
else YukiHookBridge.Hooker.hookMethod(member, beforeAfterHook)).also {
|
||||
when {
|
||||
it.first == null -> error("Hook Member [$member] failed")
|
||||
it.second -> onAlreadyHookedCallback?.invoke(it.first!!)
|
||||
else -> onHookedCallback?.invoke(it.first!!)
|
||||
it.first.member == null -> error("Hook Member [$member] failed")
|
||||
it.second -> onAlreadyHookedCallback?.invoke(it.first.member!!)
|
||||
else -> {
|
||||
hookedMember = it.first
|
||||
onHookedCallback?.invoke(it.first.member!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
@@ -537,8 +552,11 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
else YukiHookBridge.Hooker.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook)).also {
|
||||
when {
|
||||
it.first.isEmpty() -> throw NoSuchMethodError("No Method name \"$allMethodsName\" matched")
|
||||
it.second -> it.first.forEach { e -> onAlreadyHookedCallback?.invoke(e) }
|
||||
else -> it.first.forEach { e -> onHookedCallback?.invoke(e) }
|
||||
it.second -> it.first.forEach { e -> if (e.member != null) onAlreadyHookedCallback?.invoke(e.member!!) }
|
||||
else -> {
|
||||
hookedMember = it.first.first()
|
||||
it.first.forEach { e -> if (e.member != null) onHookedCallback?.invoke(e.member!!) }
|
||||
}
|
||||
}
|
||||
}
|
||||
HookMemberMode.HOOK_ALL_CONSTRUCTORS ->
|
||||
@@ -546,8 +564,11 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
else YukiHookBridge.Hooker.hookAllConstructors(hookClass.instance, beforeAfterHook)).also {
|
||||
when {
|
||||
it.first.isEmpty() -> throw NoSuchMethodError("No Constructor matched")
|
||||
it.second -> it.first.forEach { e -> onAlreadyHookedCallback?.invoke(e) }
|
||||
else -> it.first.forEach { e -> onHookedCallback?.invoke(e) }
|
||||
it.second -> it.first.forEach { e -> if (e.member != null) onAlreadyHookedCallback?.invoke(e.member!!) }
|
||||
else -> {
|
||||
hookedMember = it.first.first()
|
||||
it.first.forEach { e -> if (e.member != null) onHookedCallback?.invoke(e.member!!) }
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> error("Hooked got a no error possible")
|
||||
@@ -707,6 +728,19 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun ignoredAllFailure() = onAllFailure {}
|
||||
|
||||
/**
|
||||
* 移除当前注入的 Hook 方法、构造方法 (解除 Hook)
|
||||
*
|
||||
* - ❗你只能在 Hook 成功后才能解除 Hook - 可监听 [onHooked] 事件
|
||||
* @param result 回调是否成功
|
||||
*/
|
||||
fun remove(result: (Boolean) -> Unit = {}) {
|
||||
hookedMember?.unhook()
|
||||
runCatching { preHookMembers.remove(this@MemberHookCreater.toString()) }
|
||||
result(hookedMember != null)
|
||||
hookedMember = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -39,8 +39,6 @@ import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.annotation.YukiGenerateApi
|
||||
import com.highcapable.yukihookapi.hook.factory.allConstructors
|
||||
import com.highcapable.yukihookapi.hook.factory.allMethods
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
|
||||
@@ -441,13 +439,13 @@ object YukiHookBridge {
|
||||
internal object Hooker {
|
||||
|
||||
/** 已经 Hook 的 [Member] 数组 */
|
||||
private val hookedMembers = HashSet<String>()
|
||||
private val hookedMembers = HashSet<YukiHookedMember>()
|
||||
|
||||
/** 已经 Hook 的全部 [Method] 数组 */
|
||||
private val hookedAllMethods = HashSet<String>()
|
||||
private val hookedAllMethods = HashMap<String, HashSet<YukiHookedMember>>()
|
||||
|
||||
/** 已经 Hook 的全部 [Constructor] 数组 */
|
||||
private val hookedAllConstructors = HashSet<String>()
|
||||
private val hookedAllConstructors = HashMap<String, HashSet<YukiHookedMember>>()
|
||||
|
||||
/** 默认 Hook 回调优先级 */
|
||||
internal const val PRIORITY_DEFAULT = 50
|
||||
@@ -494,12 +492,18 @@ object YukiHookBridge {
|
||||
* 对接 [XposedBridge.hookMethod]
|
||||
* @param hookMethod 需要 Hook 的方法、构造方法
|
||||
* @param callback 回调
|
||||
* @return [Pair] - ([Member] or null,[Boolean] 是否已经 Hook)
|
||||
* @return [Pair] - ([YukiHookedMember],[Boolean] 是否已经 Hook)
|
||||
*/
|
||||
internal fun hookMethod(hookMethod: Member?, callback: YukiHookCallback): Pair<Member?, Boolean> {
|
||||
if (hookedMembers.contains(hookMethod.toString())) return Pair(hookMethod, true)
|
||||
hookedMembers.add(hookMethod.toString())
|
||||
return Pair(XposedBridge.hookMethod(hookMethod, compatCallback(callback))?.hookedMethod, false)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,20 +513,22 @@ object YukiHookBridge {
|
||||
* @param hookClass 当前 Hook 的 [Class]
|
||||
* @param methodName 方法名
|
||||
* @param callback 回调
|
||||
* @return [Pair] - ([HashSet] 成功 Hook 的方法数组,[Boolean] 是否已经 Hook)
|
||||
* @return [Pair] - ([HashSet] 成功 Hook 的 [YukiHookedMember] 数组,[Boolean] 是否已经 Hook)
|
||||
*/
|
||||
internal fun hookAllMethods(hookClass: Class<*>?, methodName: String, callback: YukiHookCallback): Pair<HashSet<Member>, Boolean> {
|
||||
internal fun hookAllMethods(
|
||||
hookClass: Class<*>?, methodName: String, callback: YukiHookCallback
|
||||
): Pair<HashSet<YukiHookedMember>, Boolean> {
|
||||
var isAlreadyHook = false
|
||||
val hookedMembers = HashSet<Member>().also {
|
||||
val hookedMembers = HashSet<YukiHookedMember>().also {
|
||||
val allMethodsName = "$hookClass$methodName"
|
||||
if (hookedAllMethods.contains(allMethodsName)) {
|
||||
isAlreadyHook = true
|
||||
hookClass?.allMethods { _, method -> if (method.name == methodName) it.add(method) }
|
||||
hookedAllMethods[allMethodsName]?.forEach { e -> it.add(e) }
|
||||
return@also
|
||||
}
|
||||
hookedAllMethods.add(allMethodsName)
|
||||
XposedBridge.hookAllMethods(hookClass, methodName, compatCallback(callback)).takeIf { it.isNotEmpty() }
|
||||
?.forEach { e -> it.add(e.hookedMethod) }
|
||||
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)
|
||||
}
|
||||
@@ -533,20 +539,20 @@ object YukiHookBridge {
|
||||
* 对接 [XposedBridge.hookAllConstructors]
|
||||
* @param hookClass 当前 Hook 的 [Class]
|
||||
* @param callback 回调
|
||||
* @return [Pair] - ([HashSet] 成功 Hook 的构造方法数组,[Boolean] 是否已经 Hook)
|
||||
* @return [Pair] - ([HashSet] 成功 Hook 的 [YukiHookedMember] 数组,[Boolean] 是否已经 Hook)
|
||||
*/
|
||||
internal fun hookAllConstructors(hookClass: Class<*>?, callback: YukiHookCallback): Pair<HashSet<Member>, Boolean> {
|
||||
internal fun hookAllConstructors(hookClass: Class<*>?, callback: YukiHookCallback): Pair<HashSet<YukiHookedMember>, Boolean> {
|
||||
var isAlreadyHook = false
|
||||
val hookedMembers = HashSet<Member>().also {
|
||||
val hookedMembers = HashSet<YukiHookedMember>().also {
|
||||
val allConstructorsName = "$hookClass<init>"
|
||||
if (hookedAllConstructors.contains(allConstructorsName)) {
|
||||
isAlreadyHook = true
|
||||
hookClass?.allConstructors { _, constructor -> it.add(constructor) }
|
||||
hookedAllConstructors[allConstructorsName]?.forEach { e -> it.add(e) }
|
||||
return@also
|
||||
}
|
||||
hookedAllConstructors.add(allConstructorsName)
|
||||
XposedBridge.hookAllConstructors(hookClass, compatCallback(callback)).takeIf { it.isNotEmpty() }
|
||||
?.forEach { e -> it.add(e.hookedMethod) }
|
||||
XposedBridge.hookAllConstructors(hookClass, compatCallback(callback)).takeIf { e -> e.isNotEmpty() }
|
||||
?.forEach { e -> it.add(YukiHookedMember.wrapper(e, allConstructorsName)) }
|
||||
hookedAllConstructors[allConstructorsName] = it
|
||||
}
|
||||
return Pair(hookedMembers, isAlreadyHook)
|
||||
}
|
||||
@@ -626,5 +632,41 @@ object YukiHookBridge {
|
||||
* @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() {
|
||||
instance.unhook()
|
||||
runCatching {
|
||||
if (tag.isNotBlank()) {
|
||||
hookedAllMethods.remove(tag)
|
||||
hookedAllConstructors.remove(tag)
|
||||
} else hookedMembers.remove(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user