From 72ebc29a073561672ed4ae27c031a22cc1ac538d Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Fri, 18 Feb 2022 03:21:49 +0800 Subject: [PATCH] Modify almost code, update version to 1.0.2 --- .../yukihookapi/hook/core/YukiHookCreater.kt | 38 +++-- .../hook/core/finder/ConstructorFinder.kt | 129 +++++++++++---- .../hook/core/finder/FieldFinder.kt | 38 ++--- .../hook/core/finder/MethodFinder.kt | 154 +++++++++++++----- .../hook/core/finder/base/BaseFinder.kt | 110 +++++++++++++ .../hook/factory/ReflectionFactory.kt | 74 ++++----- .../yukihookapi/hook/param/PackageParam.kt | 24 ++- 7 files changed, 405 insertions(+), 162 deletions(-) create mode 100644 yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt index 484e9f87..88ca6ba4 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiHookCreater.kt @@ -70,7 +70,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl * @return [Class] * @throws IllegalStateException 如果当前 [Class] 未被正确装载 */ - val thisClass + val instanceClass get() = hookClass.instance ?: error("Cannot get hook class \"${hookClass.name}\" cause ${hookClass.throwable?.message}") /** @@ -138,7 +138,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl /** * 手动指定要 Hook 的方法、构造类 * - * 你可以调用 [thisClass] 来手动查询要 Hook 的方法 + * 你可以调用 [instanceClass] 来手动查询要 Hook 的方法 */ var member: Member? = null @@ -180,11 +180,11 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl if (hookClass.instance == null) return MethodFinder(hookInstance = this).failure(hookClass.throwable) hookAllMembers = HookAllMembers.HOOK_NONE isHookMemberSetup = true - return MethodFinder(hookInstance = this, hookClass.instance).apply(initiate).build() + return MethodFinder(hookInstance = this, hookClass.instance).apply(initiate).build(isBind = true) } /** - * 查找 [hookClass] 需要 Hook 的构造类 + * 查找 [hookClass] 需要 Hook 的构造方法 * * 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换 * @param initiate 方法体 @@ -194,17 +194,35 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl if (hookClass.instance == null) return ConstructorFinder(hookInstance = this).failure(hookClass.throwable) hookAllMembers = HookAllMembers.HOOK_NONE isHookMemberSetup = true - return ConstructorFinder(hookInstance = this, hookClass.instance).apply(initiate).build() + return ConstructorFinder(hookInstance = this, hookClass.instance).apply(initiate).build(isBind = true) } /** - * 查找 [Field] + * 使用当前 [hookClass] 查找并得到 [Field] * @param initiate 方法体 * @return [FieldFinder.Result] */ - fun field(initiate: FieldFinder.() -> Unit) = - if (hookClass.instance == null) FieldFinder(hookInstance = this).failure(hookClass.throwable) - else FieldFinder(hookInstance = this, hookClass.instance).apply(initiate).build() + fun HookParam.field(initiate: FieldFinder.() -> Unit) = + if (hookClass.instance == null) FieldFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable) + else FieldFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build() + + /** + * 使用当前 [hookClass] 查找并得到方法 + * @param initiate 方法体 + * @return [MethodFinder.Result] + */ + fun HookParam.method(initiate: MethodFinder.() -> Unit) = + if (hookClass.instance == null) MethodFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable) + else MethodFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build() + + /** + * 使用当前 [hookClass] 查找并得到构造方法 + * @param initiate 方法体 + * @return [ConstructorFinder.Result] + */ + fun HookParam.constructor(initiate: ConstructorFinder.() -> Unit) = + if (hookClass.instance == null) ConstructorFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable) + else ConstructorFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build() /** * 在方法执行完成前 Hook @@ -418,7 +436,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl * Hook 过程中开启了 [YukiHookAPI.Configs.isDebug] 输出调试信息 * @param msg 调试日志内容 */ - internal fun onHookLogMsg(msg: String) { + private fun onHookLogMsg(msg: String) { if (YukiHookAPI.Configs.isDebug) loggerI(msg = msg) } diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt index e7110b91..43cae472 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/ConstructorFinder.kt @@ -25,14 +25,13 @@ * * This file is Created by fankes on 2022/2/4. */ -@file:Suppress("unused", "EXPERIMENTAL_API_USAGE", "MemberVisibilityCanBePrivate") +@file:Suppress("unused", "EXPERIMENTAL_API_USAGE", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST") package com.highcapable.yukihookapi.hook.core.finder -import android.os.SystemClock import com.highcapable.yukihookapi.annotation.DoNotUseMethod import com.highcapable.yukihookapi.hook.core.YukiHookCreater -import com.highcapable.yukihookapi.hook.log.loggerE +import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder import com.highcapable.yukihookapi.hook.log.loggerW import com.highcapable.yukihookapi.hook.utils.ReflectionUtils import com.highcapable.yukihookapi.hook.utils.runBlocking @@ -42,17 +41,23 @@ import java.lang.reflect.Constructor * [Constructor] 查找类 * * 可通过指定类型查找指定构造方法 - * @param hookInstance 当前 Hook 实例 - * @param hookClass 当前被 Hook 的 [Class] + * @param hookInstance 当前 Hook 实例 - 填写后将自动设置 [YukiHookCreater.MemberHookCreater.member] + * @param classSet 当前需要查找的 [Class] 实例 */ -class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) { +class ConstructorFinder( + override val hookInstance: YukiHookCreater.MemberHookCreater? = null, + override val classSet: Class<*>? = null +) : BaseFinder(tag = "Constructor", hookInstance, classSet) { + + /** 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] */ + private var isBindToHooker = false + + /** 当前重查找结果回调 */ + private var remedyPlansCallback: (() -> Unit)? = null /** [Constructor] 参数数组 */ private var params: Array>? = null - /** 是否使用了 [RemedyPlan] */ - private var isUsingRemedyPlan = false - /** * [Constructor] 参数 * @@ -73,8 +78,18 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea */ private val result get() = if (params != null) - ReflectionUtils.findConstructorExact(hookClass, *params!!) - else ReflectionUtils.findConstructorExact(hookClass) + ReflectionUtils.findConstructorExact(classSet, *params!!) + else ReflectionUtils.findConstructorExact(classSet) + + /** + * 设置实例 + * @param isBind 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] + * @param constructor 当前找到的 [Constructor] + */ + private fun setInstance(isBind: Boolean, constructor: Constructor<*>) { + memberInstance = constructor + if (isBind) hookInstance?.member = constructor + } /** * 得到构造方法结果 @@ -83,11 +98,12 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea * @return [Result] */ @DoNotUseMethod - fun build() = try { + override fun build(isBind: Boolean) = try { runBlocking { - hookInstance.member = result + isBindToHooker = isBind + setInstance(isBind, result) }.result { - hookInstance.onHookLogMsg(msg = "Find Constructor [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]") + onHookLogMsg(msg = "Find Constructor [${memberInstance}] takes ${it}ms [${hookTag}]") } Result() } catch (e: Throwable) { @@ -103,22 +119,7 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea * @return [Result] */ @DoNotUseMethod - fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable) - - /** - * 发生错误时输出日志 - * @param msg 消息日志 - * @param throwable 错误 - * @param isAlwaysPrint 忽略条件每次都打印错误 - */ - private fun onFailureMsg(msg: String = "", throwable: Throwable? = null, isAlwaysPrint: Boolean = false) { - fun print() = loggerE(msg = "NoSuchConstructor happend in [$hookClass] $msg [${hookInstance.tag}]", e = throwable) - if (isAlwaysPrint) print() - else Thread { - SystemClock.sleep(10) - if (hookInstance.isNotIgnoredHookingFailure && !isUsingRemedyPlan) print() - }.start() - } + override fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable) /** * [Constructor] 重查找实现类 @@ -139,7 +140,7 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea * @param initiate 方法体 */ fun constructor(initiate: ConstructorFinder.() -> Unit) = - Result().apply { remedyPlans.add(Pair(ConstructorFinder(hookInstance, hookClass).apply(initiate), this)) } + Result().apply { remedyPlans.add(Pair(ConstructorFinder(hookInstance, classSet).apply(initiate), this)) } /** * 开始重查找 @@ -154,13 +155,14 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea remedyPlans.forEachIndexed { p, it -> runCatching { runBlocking { - hookInstance.member = it.first.result + setInstance(isBindToHooker, it.first.result) }.result { - hookInstance.onHookLogMsg(msg = "Find Constructor [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]") + onHookLogMsg(msg = "Find Constructor [${memberInstance}] takes ${it}ms [${hookTag}]") } isFindSuccess = true - it.second.onFindCallback?.invoke(hookInstance.member as Constructor<*>) - hookInstance.onHookLogMsg(msg = "Constructor [${hookInstance.member}] trying ${p + 1} times success by RemedyPlan [${hookInstance.tag}]") + it.second.onFindCallback?.invoke(memberInstance as Constructor<*>) + remedyPlansCallback?.invoke() + onHookLogMsg(msg = "Constructor [${memberInstance}] trying ${p + 1} times success by RemedyPlan [${hookTag}]") return@run }.onFailure { lastError = it @@ -175,7 +177,7 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea ) remedyPlans.clear() } - } else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookInstance.tag}]") + } else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookTag}]") } /** @@ -212,6 +214,27 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea */ fun result(initiate: Result.() -> Unit) = apply(initiate) + /** + * 获得 [Constructor] 实例处理类 + * + * - ❗在 [memberInstance] 结果为空时使用此方法将无法获得对象 + * - ❗若你设置了 [remedys] 请使用 [wait] 回调结果方法 + * @return [Instance] + */ + fun get() = Instance() + + /** + * 获得 [Constructor] 实例处理类 + * + * - ❗若你设置了 [remedys] 必须使用此方法才能获得结果 + * - ❗若你没有设置 [remedys] 此方法将不会被回调 + * @param initiate 回调 [Instance] + */ + fun wait(initiate: Instance.() -> Unit) { + if (memberInstance != null) initiate(get()) + else remedyPlansCallback = { initiate(get()) } + } + /** * 创建构造方法重查找功能 * @@ -238,5 +261,39 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea if (isNoSuch) initiate(e ?: Throwable()) return this } + + /** + * [Constructor] 实例处理类 + * + * 调用与创建目标实例类对象 + */ + inner class Instance { + + /** + * 执行构造方法创建目标实例 + * @param param 构造方法参数 + * @return [Any] or null + */ + private fun baseCall(vararg param: Any?) = + if (param.isNotEmpty()) + (memberInstance as? Constructor<*>?)?.newInstance(*param) + else (memberInstance as? Constructor<*>?)?.newInstance() + + /** + * 执行构造方法创建目标实例 - 不指定目标实例类型 + * @param param 构造方法参数 + * @return [Any] or null + */ + fun call(vararg param: Any?) = baseCall(*param) + + /** + * 执行构造方法创建目标实例 - 指定 [T] 目标实例类型 + * @param param 构造方法参数 + * @return [T] or null + */ + fun newInstance(vararg param: Any?) = baseCall(*param) as? T? + + override fun toString() = "[${(memberInstance as? Constructor<*>?)?.name ?: ""}]" + } } } \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt index 4bb89c98..1a9d4f87 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/FieldFinder.kt @@ -32,6 +32,7 @@ package com.highcapable.yukihookapi.hook.core.finder import android.os.SystemClock import com.highcapable.yukihookapi.annotation.DoNotUseMethod import com.highcapable.yukihookapi.hook.core.YukiHookCreater +import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder import com.highcapable.yukihookapi.hook.log.loggerE import com.highcapable.yukihookapi.hook.utils.ReflectionUtils import com.highcapable.yukihookapi.hook.utils.runBlocking @@ -42,19 +43,12 @@ import java.lang.reflect.Field * * 可通过执行类型查找指定变量 * @param hookInstance 当前 Hook 实例 - * @param hookClass 当前被 Hook 的 [Class] + * @param classSet 当前需要查找的 [Class] 实例 */ -class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) { - - /** 当前找到的 [Field] */ - private var fieldInstance: Field? = null - - /** - * [Field] 所在的 [Class] - * - * 不填默认为当前的 [hookClass] - */ - var classSet = hookClass +class FieldFinder( + override val hookInstance: YukiHookCreater.MemberHookCreater? = null, + override val classSet: Class<*>? = null +) : BaseFinder(tag = "Field", hookInstance, classSet) { /** * [Field] 名称 @@ -74,30 +68,30 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p * 得到变量处理结果 * * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法 + * @param isBind 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] * @return [Result] * @throws IllegalStateException 如果 [name] 没有被设置 */ @DoNotUseMethod - fun build() = when { + override fun build(isBind: Boolean) = when { name.isBlank() -> { - loggerE(msg = "Field name cannot be empty in Class [$classSet] [${hookInstance.tag}]") + loggerE(msg = "Field name cannot be empty in Class [$classSet] [${hookTag}]") Result(isNoSuch = true) } else -> try { runBlocking { - fieldInstance = + memberInstance = if (type != null) ReflectionUtils.findFieldIfExists(classSet, type?.name, name) else classSet?.getDeclaredField(name)?.apply { isAccessible = true } }.result { - hookInstance.onHookLogMsg(msg = "Find Field [${fieldInstance}] takes ${it}ms [${hookInstance.tag}]") + onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") } Result() } catch (e: Throwable) { Thread { SystemClock.sleep(10) - if (hookInstance.isNotIgnoredHookingFailure) - loggerE(msg = "NoSuchField happend in [$classSet] [${hookInstance.tag}]", e = e) + if (isNotIgnoredHookingFailure) loggerE(msg = "NoSuchField happend in [$classSet] [${hookTag}]", e = e) }.start() Result(isNoSuch = true, e) } @@ -111,12 +105,11 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p * @return [Result] */ @DoNotUseMethod - fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable) + override fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable) /** * [Field] 查找结果实现类 * - * 可在这里处理找到的 [fieldInstance] * @param isNoSuch 是否没有找到变量 - 默认否 * @param e 错误信息 */ @@ -147,7 +140,7 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p * 得到变量本身 * @return [Field] or null */ - fun give() = fieldInstance + fun give() = memberInstance as? Field? /** * 监听找不到变量时 @@ -189,7 +182,8 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p /** 设置变量实例为 null */ fun setNull() = set(null) - override fun toString() = "[${self?.javaClass?.name ?: ""}] in [${instance?.javaClass?.name ?: ""}] value \"$self\"" + override fun toString() = + "[${self?.javaClass?.name ?: ""}] in [${instance?.javaClass?.name ?: ""}] value \"$self\"" } } } \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt index c550bc9b..80cbdbae 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/MethodFinder.kt @@ -25,13 +25,13 @@ * * This file is Created by fankes on 2022/2/4. */ -@file:Suppress("unused", "MemberVisibilityCanBePrivate", "EXPERIMENTAL_API_USAGE") +@file:Suppress("unused", "MemberVisibilityCanBePrivate", "EXPERIMENTAL_API_USAGE", "UNCHECKED_CAST") package com.highcapable.yukihookapi.hook.core.finder -import android.os.SystemClock import com.highcapable.yukihookapi.annotation.DoNotUseMethod import com.highcapable.yukihookapi.hook.core.YukiHookCreater +import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder import com.highcapable.yukihookapi.hook.log.loggerE import com.highcapable.yukihookapi.hook.log.loggerW import com.highcapable.yukihookapi.hook.utils.ReflectionUtils @@ -42,17 +42,23 @@ import java.lang.reflect.Method * [Method] 查找类 * * 可通过指定类型查找指定方法 - * @param hookInstance 当前 Hook 实例 - * @param hookClass 当前 Hook 的 Class + * @param hookInstance 当前 Hook 实例 - 填写后将自动设置 [YukiHookCreater.MemberHookCreater.member] + * @param classSet 当前需要查找的 [Class] 实例 */ -class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) { +class MethodFinder( + override val hookInstance: YukiHookCreater.MemberHookCreater? = null, + override val classSet: Class<*>? = null +) : BaseFinder(tag = "Method", hookInstance, classSet) { + + /** 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] */ + private var isBindToHooker = false + + /** 当前重查找结果回调 */ + private var remedyPlansCallback: (() -> Unit)? = null /** [Method] 参数数组 */ private var params: Array>? = null - /** 是否使用了 [RemedyPlan] */ - private var isUsingRemedyPlan = false - /** * [Method] 名称 * @@ -88,29 +94,44 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, */ private val result get() = if (params != null) - ReflectionUtils.findMethodBestMatch(hookClass, returnType, name, *params!!) - else ReflectionUtils.findMethodNoParam(hookClass, returnType, name) + ReflectionUtils.findMethodBestMatch(classSet, returnType, name, *params!!) + else ReflectionUtils.findMethodNoParam(classSet, returnType, name) + + /** + * 设置实例 + * @param isBind 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] + * @param method 当前找到的 [Method] + */ + private fun setInstance(isBind: Boolean, method: Method) { + memberInstance = method + if (isBind) hookInstance?.member = method + } /** * 得到方法结果 * * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法 + * @param isBind 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] * @return [Result] */ @DoNotUseMethod - fun build() = if (name.isBlank()) { - loggerE(msg = "Method name cannot be empty in Class [$hookClass] [${hookInstance.tag}]") - Result(isNoSuch = true) - } else try { - runBlocking { - hookInstance.member = result - }.result { - hookInstance.onHookLogMsg(msg = "Find Method [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]") + override fun build(isBind: Boolean) = when { + name.isBlank() -> { + loggerE(msg = "Method name cannot be empty in Class [$classSet] [${hookTag}]") + Result(isNoSuch = true) + } + else -> try { + runBlocking { + isBindToHooker = isBind + setInstance(isBind, result) + }.result { + onHookLogMsg(msg = "Find Method [${memberInstance}] takes ${it}ms [${hookTag}]") + } + Result() + } catch (e: Throwable) { + onFailureMsg(throwable = e) + Result(isNoSuch = true, e) } - Result() - } catch (e: Throwable) { - onFailureMsg(throwable = e) - Result(isNoSuch = true, e) } /** @@ -121,22 +142,7 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, * @return [Result] */ @DoNotUseMethod - fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable) - - /** - * 发生错误时输出日志 - * @param msg 消息日志 - * @param throwable 错误 - * @param isAlwaysPrint 忽略条件每次都打印错误 - */ - private fun onFailureMsg(msg: String = "", throwable: Throwable? = null, isAlwaysPrint: Boolean = false) { - fun print() = loggerE(msg = "NoSuchMethod happend in [$hookClass] $msg [${hookInstance.tag}]", e = throwable) - if (isAlwaysPrint) print() - else Thread { - SystemClock.sleep(10) - if (hookInstance.isNotIgnoredHookingFailure && !isUsingRemedyPlan) print() - }.start() - } + override fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable) /** * [Method] 重查找实现类 @@ -158,7 +164,7 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, * @return [Result] 结果 */ fun method(initiate: MethodFinder.() -> Unit) = - Result().apply { remedyPlans.add(Pair(MethodFinder(hookInstance, hookClass).apply(initiate), this)) } + Result().apply { remedyPlans.add(Pair(MethodFinder(hookInstance, classSet).apply(initiate), this)) } /** * 开始重查找 @@ -173,13 +179,14 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, remedyPlans.forEachIndexed { p, it -> runCatching { runBlocking { - hookInstance.member = it.first.result + setInstance(isBindToHooker, it.first.result) }.result { - hookInstance.onHookLogMsg(msg = "Find Method [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]") + onHookLogMsg(msg = "Find Method [${memberInstance}] takes ${it}ms [${hookTag}]") } isFindSuccess = true - it.second.onFindCallback?.invoke(hookInstance.member as Method) - hookInstance.onHookLogMsg(msg = "Method [${hookInstance.member}] trying ${p + 1} times success by RemedyPlan [${hookInstance.tag}]") + it.second.onFindCallback?.invoke(memberInstance as Method) + remedyPlansCallback?.invoke() + onHookLogMsg(msg = "Method [${memberInstance}] trying ${p + 1} times success by RemedyPlan [${hookTag}]") return@run }.onFailure { lastError = it @@ -194,7 +201,7 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, ) remedyPlans.clear() } - } else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookInstance.tag}]") + } else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookTag}]") } /** @@ -231,6 +238,29 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, */ fun result(initiate: Result.() -> Unit) = apply(initiate) + /** + * 获得 [Method] 实例处理类 + * + * - ❗在 [memberInstance] 结果为空时使用此方法将无法获得对象 + * - ❗若你设置了 [remedys] 请使用 [wait] 回调结果方法 + * @param instance 所在实例 + * @return [Instance] + */ + fun get(instance: Any? = null) = Instance(instance) + + /** + * 获得 [Method] 实例处理类 + * + * - ❗若你设置了 [remedys] 必须使用此方法才能获得结果 + * - ❗若你没有设置 [remedys] 此方法将不会被回调 + * @param instance 所在实例 + * @param initiate 回调 [Instance] + */ + fun wait(instance: Any? = null, initiate: Instance.() -> Unit) { + if (memberInstance != null) initiate(get(instance)) + else remedyPlansCallback = { initiate(get(instance)) } + } + /** * 创建方法重查找功能 * @@ -256,8 +286,42 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, * @return [Result] 可继续向下监听 */ fun onNoSuchMethod(initiate: (Throwable) -> Unit): Result { - if (isNoSuch) initiate(e ?: Throwable()) + if (isNoSuch) initiate(e ?: Throwable("Initialization Error")) return this } + + /** + * [Method] 实例处理类 + * @param instance 当前 [Method] 所在类的实例对象 + */ + inner class Instance(private val instance: Any?) { + + /** + * 执行方法 + * @param param 方法参数 + * @return [Any] or null + */ + private fun baseCall(vararg param: Any?) = + if (param.isNotEmpty()) + (memberInstance as? Method?)?.invoke(instance, *param) + else (memberInstance as? Method?)?.invoke(instance) + + /** + * 执行方法 - 不指定返回值类型 + * @param param 方法参数 + * @return [Any] or null + */ + fun call(vararg param: Any?) = baseCall(*param) + + /** + * 执行方法 - 指定 [T] 返回值类型 + * @param param 方法参数 + * @return [T] or null + */ + fun invoke(vararg param: Any?) = baseCall(*param) as? T? + + override fun toString() = + "[${(memberInstance as? Method?)?.name ?: ""}] in [${instance?.javaClass?.name ?: ""}]" + } } } \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt new file mode 100644 index 00000000..0d1acef7 --- /dev/null +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt @@ -0,0 +1,110 @@ +/* + * 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/2/18. + */ +package com.highcapable.yukihookapi.hook.core.finder.base + +import android.os.SystemClock +import com.highcapable.yukihookapi.YukiHookAPI +import com.highcapable.yukihookapi.annotation.DoNotUseMethod +import com.highcapable.yukihookapi.hook.core.YukiHookCreater +import com.highcapable.yukihookapi.hook.log.loggerE +import com.highcapable.yukihookapi.hook.log.loggerI +import java.lang.reflect.Member + +/** + * 这是查找类功能的基本类实现 + * @param tag 当前查找类的标识 + * @param hookInstance 当前 Hook 实例 + * @param classSet 当前需要查找的 [Class] 实例 + */ +abstract class BaseFinder( + private val tag: String, + open val hookInstance: YukiHookCreater.MemberHookCreater? = null, + open val classSet: Class<*>? = null +) { + + /** 是否使用了重查找功能 */ + internal var isUsingRemedyPlan = false + + /** 当前找到的 [Member] */ + internal var memberInstance: Member? = null + + /** + * 获取当前使用的 TAG + * @return [String] 使用的 TAG + */ + internal val hookTag get() = hookInstance?.tag ?: "FinderMode" + + /** + * 判断是否没有设置 Hook 过程中的任何异常拦截 + * @return [Boolean] 没有设置任何异常拦截 + */ + internal val isNotIgnoredHookingFailure get() = hookInstance?.isNotIgnoredHookingFailure ?: true + + /** + * 发生错误时输出日志 + * @param msg 消息日志 + * @param throwable 错误 + * @param isAlwaysPrint 忽略条件每次都打印错误 + */ + internal fun onFailureMsg(msg: String = "", throwable: Throwable? = null, isAlwaysPrint: Boolean = false) { + fun print() = loggerE(msg = "NoSuch$tag happend in [$classSet] $msg [${hookTag}]", e = throwable) + if (isAlwaysPrint) print() + else Thread { + SystemClock.sleep(10) + if (isNotIgnoredHookingFailure && !isUsingRemedyPlan) print() + }.start() + } + + /** + * Hook 过程中开启了 [YukiHookAPI.Configs.isDebug] 输出调试信息 + * @param msg 调试日志内容 + */ + internal fun onHookLogMsg(msg: String) { + if (YukiHookAPI.Configs.isDebug) loggerI(msg = msg) + } + + /** + * 得到结果 + * + * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法 + * @param isBind 是否将结果设置到目标 [YukiHookCreater.MemberHookCreater] + * @return [Any] + */ + @DoNotUseMethod + abstract fun build(isBind: Boolean = false): Any + + /** + * 创建一个异常结果 + * + * - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法 + * @param throwable 异常 + * @return [Any] + */ + @DoNotUseMethod + abstract fun failure(throwable: Throwable?): Any +} \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt index 01ee2c3f..6be652ea 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt @@ -30,9 +30,10 @@ package com.highcapable.yukihookapi.hook.factory import com.highcapable.yukihookapi.hook.bean.HookClass +import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder +import com.highcapable.yukihookapi.hook.core.finder.FieldFinder +import com.highcapable.yukihookapi.hook.core.finder.MethodFinder import com.highcapable.yukihookapi.hook.utils.ReflectionUtils -import java.lang.reflect.Constructor -import java.lang.reflect.Method /** * [Class] 转换为 [HookClass] @@ -86,53 +87,46 @@ fun String.hasClass(loader: ClassLoader?) = try { */ fun Class<*>.hasMethod(name: String, vararg paramType: Class<*>, returnType: Class<*>? = null): Boolean = try { - method(name, *paramType, returnType = returnType) + if (paramType.isNotEmpty()) + ReflectionUtils.findMethodBestMatch(this, returnType, name, *paramType) + else ReflectionUtils.findMethodNoParam(this, returnType, name) true } catch (_: Throwable) { false } /** - * 查找并得到方法 - * @param name 方法名称 + * 查找构造方法是否存在 * @param paramType params - * @param returnType 返回类型 - 不填默认模糊 - * @return [Method] or null - * @throws NoSuchMethodError + * @return [Boolean] 是否存在 */ -fun Class<*>.method(name: String, vararg paramType: Class<*>, returnType: Class<*>? = null): Method? = - if (paramType.isNotEmpty()) - ReflectionUtils.findMethodBestMatch(this, returnType, name, *paramType) - else ReflectionUtils.findMethodNoParam(this, returnType, name) +fun Class<*>.hasConstructor(vararg paramType: Class<*>): Boolean = + try { + if (paramType.isNotEmpty()) + ReflectionUtils.findConstructorExact(this, *paramType) + else ReflectionUtils.findConstructorExact(this) + true + } catch (_: Throwable) { + false + } + +/** + * 查找并得到变量 + * @param initiate 查找方法体 + * @return [FieldFinder.Result] + */ +fun Class<*>.field(initiate: FieldFinder.() -> Unit) = FieldFinder(classSet = this).apply(initiate).build() + +/** + * 查找并得到方法 + * @param initiate 查找方法体 + * @return [MethodFinder.Result] + */ +fun Class<*>.method(initiate: MethodFinder.() -> Unit) = MethodFinder(classSet = this).apply(initiate).build() /** * 查找并得到构造类 - * @param paramType params - * @return [Constructor] or null - * @throws NoSuchMethodError + * @param initiate 查找方法体 + * @return [ConstructorFinder.Result] */ -fun Class<*>.constructor(vararg paramType: Class<*>): Constructor? = - if (paramType.isNotEmpty()) - ReflectionUtils.findConstructorExact(this, *paramType) - else ReflectionUtils.findConstructorExact(this) - -/** - * 执行静态方法 - * @param param 方法参数 - * @return [T] or null - */ -inline fun Method.callStatic(vararg param: Any?) = - if (param.isNotEmpty()) - invoke(null, *param) as? T? - else invoke(null) as? T? - -/** - * 执行方法 - * @param instance 目标对象 - * @param param 方法参数 - * @return [T] or null - */ -inline fun Method.call(instance: Any?, vararg param: Any?) = - if (param.isNotEmpty()) - invoke(instance, *param) as? T? - else invoke(instance) as? T? +fun Class<*>.constructor(initiate: ConstructorFinder.() -> Unit) = ConstructorFinder(classSet = this).apply(initiate).build() diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt index 13ed1703..e77ae8fc 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt @@ -192,10 +192,23 @@ open class PackageParam(private var wrapper: PackageParamWrapper? = null) { /** * Hook 方法、构造类 + * + * - ❗为防止任何字符串都被当做 [Class] 进行 Hook - 推荐优先使用 [findClass] * @param initiate 方法体 */ - fun Class<*>.hook(initiate: YukiHookCreater.() -> Unit) = - YukiHookCreater(packageParam = thisParam, hookClass = hookClass.bind()).apply(initiate).hook() + fun String.hook(initiate: YukiHookCreater.() -> Unit) = findClass(name = this).hook(initiate) + + /** + * Hook 方法、构造类 + * @param initiate 方法体 + */ + fun Class<*>.hook(initiate: YukiHookCreater.() -> Unit) = hookClass.hook(initiate) + + /** + * Hook 方法、构造类 + * @param initiate 方法体 + */ + fun VariousClass.hook(initiate: YukiHookCreater.() -> Unit) = hookClass.hook(initiate) /** * Hook 方法、构造类 @@ -204,13 +217,6 @@ open class PackageParam(private var wrapper: PackageParamWrapper? = null) { fun HookClass.hook(initiate: YukiHookCreater.() -> Unit) = YukiHookCreater(packageParam = thisParam, hookClass = bind()).apply(initiate).hook() - /** - * Hook 方法、构造类 - * @param initiate 方法体 - */ - fun VariousClass.hook(initiate: YukiHookCreater.() -> Unit) = - YukiHookCreater(packageParam = thisParam, hookClass = hookClass).apply(initiate).hook() - /** * [VariousClass] 转换为 [HookClass] 并绑定到 [appClassLoader] * @return [HookClass]