From 6efb90ca9df3336bf5895035d6ff5d2fcee31c31 Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Fri, 1 Apr 2022 02:55:41 +0800 Subject: [PATCH] Added new function and fix a finding big --- .../hook/core/finder/ConstructorFinder.kt | 25 ++++- .../hook/core/finder/FieldFinder.kt | 54 +++++++---- .../hook/core/finder/MethodFinder.kt | 52 ++++++---- .../yukihookapi/hook/utils/ReflectionTool.kt | 97 +++++++++++-------- 4 files changed, 152 insertions(+), 76 deletions(-) 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 cf231167..4a777e8a 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 @@ -65,6 +65,19 @@ class ConstructorFinder( /** [ModifierRules] 实例 */ private var modifiers: ModifierRules? = null + /** + * [Constructor] 在当前类中的位置 + * + * - 设置后将筛选 [Class.getDeclaredConstructors] 的数组下标 + * + * - ❗受到字节码顺序影响 - 请勿完全依赖于此功能 + * + * 若 index 小于零则忽略此条件 (等于 -2 为取最后一个) + * + * 可使用 [firstIndex] 和 [lastIndex] 设置首位和末位筛选条件 + */ + var index = -1 + /** * [Constructor] 参数个数 * @@ -74,6 +87,16 @@ class ConstructorFinder( */ var paramCount = -1 + /** 设置 [Constructor] 在当前类中的位置为首位 */ + fun firstIndex() { + index = 0 + } + + /** 设置 [Constructor] 在当前类中的位置为末位 */ + fun lastIndex() { + index = -2 + } + /** * [Constructor] 筛选条件 * @@ -105,7 +128,7 @@ class ConstructorFinder( * @throws IllegalStateException 如果 [classSet] 为 null * @throws NoSuchMethodError 如果找不到构造方法 */ - private val result get() = ReflectionTool.findConstructor(classSet, modifiers, paramCount, paramTypes) + private val result get() = ReflectionTool.findConstructor(classSet, index, modifiers, paramCount, paramTypes) /** * 设置实例 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 77d35123..531256c3 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 @@ -34,7 +34,6 @@ 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.core.finder.type.ModifierRules -import com.highcapable.yukihookapi.hook.log.yLoggerE import com.highcapable.yukihookapi.hook.utils.ReflectionTool import com.highcapable.yukihookapi.hook.utils.runBlocking import java.lang.reflect.Field @@ -54,10 +53,23 @@ class FieldFinder( /** [ModifierRules] 实例 */ private var modifiers: ModifierRules? = null + /** + * [Field] 在当前类中的位置 + * + * - 设置后将筛选 [Class.getDeclaredFields] 的数组下标 + * + * - ❗受到字节码顺序影响 - 请勿完全依赖于此功能 + * + * 若 index 小于零则忽略此条件 (等于 -2 为取最后一个) + * + * 可使用 [firstIndex] 和 [lastIndex] 设置首位和末位筛选条件 + */ + var index = -1 + /** * [Field] 名称 * - * - ❗必须设置 + * - ❗若不填写名称则必须存在一个其它条件 - 默认模糊查找并取第一个匹配的 [Field] */ var name = "" @@ -68,6 +80,16 @@ class FieldFinder( */ var type: Class<*>? = null + /** 设置 [Field] 在当前类中的位置为首位 */ + fun firstIndex() { + index = 0 + } + + /** 设置 [Field] 在当前类中的位置为末位 */ + fun lastIndex() { + index = -2 + } + /** * [Field] 筛选条件 * @@ -87,23 +109,17 @@ class FieldFinder( * @throws IllegalStateException 如果 [name] 没有被设置 */ @DoNotUseMethod - override fun build(isBind: Boolean) = when { - name.isBlank() -> { - yLoggerE(msg = "Field name cannot be empty in Class [$classSet] [${hookTag}]") - Result(isNoSuch = true) - } - else -> try { - runBlocking { - memberInstance = ReflectionTool.findField(classSet, name, modifiers, type) - }.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") } - Result() - } catch (e: Throwable) { - Thread { - SystemClock.sleep(10) - onFailureMsg(msg = "NoSuchField happend in [$classSet] [${hookTag}]", throwable = e) - }.start() - Result(isNoSuch = true, e) - } + override fun build(isBind: Boolean) = try { + runBlocking { + memberInstance = ReflectionTool.findField(classSet, index, name, modifiers, type) + }.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") } + Result() + } catch (e: Throwable) { + Thread { + SystemClock.sleep(10) + onFailureMsg(msg = "NoSuchField happend in [$classSet] [${hookTag}]", throwable = e) + }.start() + Result(isNoSuch = true, e) } /** 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 ad516c16..0f337ca3 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 @@ -36,7 +36,6 @@ 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.core.finder.type.ModifierRules -import com.highcapable.yukihookapi.hook.log.yLoggerE import com.highcapable.yukihookapi.hook.log.yLoggerW import com.highcapable.yukihookapi.hook.utils.ReflectionTool import com.highcapable.yukihookapi.hook.utils.runBlocking @@ -66,10 +65,23 @@ class MethodFinder( /** [ModifierRules] 实例 */ private var modifiers: ModifierRules? = null + /** + * [Method] 在当前类中的位置 + * + * - 设置后将筛选 [Class.getDeclaredMethods] 的数组下标 + * + * - ❗受到字节码顺序影响 - 请勿完全依赖于此功能 + * + * 若 index 小于零则忽略此条件 (等于 -2 为取最后一个) + * + * 可使用 [firstIndex] 和 [lastIndex] 设置首位和末位筛选条件 + */ + var index = -1 + /** * [Method] 名称 * - * - ❗必须设置 + * - ❗若不填写名称则必须存在一个其它条件 - 默认模糊查找并取第一个匹配的 [Method] */ var name = "" @@ -89,6 +101,16 @@ class MethodFinder( */ var returnType: Class<*>? = null + /** 设置 [Method] 在当前类中的位置为首位 */ + fun firstIndex() { + index = 0 + } + + /** 设置 [Method] 在当前类中的位置为末位 */ + fun lastIndex() { + index = -2 + } + /** * [Method] 筛选条件 * @@ -120,7 +142,7 @@ class MethodFinder( * @throws IllegalStateException 如果 [classSet] 为 null * @throws NoSuchMethodError 如果找不到方法 */ - private val result get() = ReflectionTool.findMethod(classSet, name, modifiers, returnType, paramCount, paramTypes) + private val result get() = ReflectionTool.findMethod(classSet, index, name, modifiers, returnType, paramCount, paramTypes) /** * 设置实例 @@ -140,21 +162,15 @@ class MethodFinder( * @return [Result] */ @DoNotUseMethod - override fun build(isBind: Boolean) = when { - name.isBlank() -> { - yLoggerE(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) - } + override fun build(isBind: Boolean) = 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) } /** diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/utils/ReflectionTool.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/utils/ReflectionTool.kt index 7be0ecc9..d1c4d65f 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/utils/ReflectionTool.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/utils/ReflectionTool.kt @@ -45,6 +45,7 @@ internal object ReflectionTool { /** * 查找任意变量 * @param classSet 变量所在类 + * @param index 下标 * @param name 变量名称 * @param modifiers 变量描述 * @param type 变量类型 @@ -52,26 +53,31 @@ internal object ReflectionTool { * @throws IllegalStateException 如果 [classSet] 为 null * @throws NoSuchFieldError 如果找不到变量 */ - internal fun findField(classSet: Class<*>?, name: String, modifiers: ModifierRules?, type: Class<*>?): Field { - val hashCode = ("[$name][$type][$modifiers][$classSet]").hashCode() + internal fun findField(classSet: Class<*>?, index: Int, name: String, modifiers: ModifierRules?, type: Class<*>?): Field { + val hashCode = ("[$index][$name][$type][$modifiers][$classSet]").hashCode() return MemberCacheStore.findField(hashCode) ?: let { var field: Field? = null - run { - classSet?.declaredFields?.forEach { - var conditions = name == it.name - if (type != null) conditions = conditions && it.type == type - if (modifiers != null) conditions = conditions && modifiers.contains(it) - if (conditions) { + classSet?.declaredFields?.apply { + forEachIndexed { p, it -> + var isMatched = false + var conditions = true + if (name.isNotBlank()) conditions = (name == it.name).also { isMatched = true } + if (type != null) conditions = (conditions && it.type == type).also { isMatched = true } + if (modifiers != null) conditions = (conditions && modifiers.contains(it)).also { isMatched = true } + if (index == -2) conditions = (conditions && p == lastIndex).also { isMatched = true } + if (index >= 0) conditions = (conditions && p == index).also { isMatched = true } + if (conditions && isMatched) { field = it.apply { isAccessible = true } - return@run + return@apply } - } ?: error("Can't find this Field [$name] because classSet is null") - } + } + } ?: error("Can't find this Field [$name] because classSet is null") field?.also { MemberCacheStore.putField(hashCode, field) } ?: throw NoSuchFieldError( "Can't find this Field --> " + - "name:[$name] " + - "type:[$type] " + + "index:[${index.takeIf { it >= 0 } ?: "unspecified"}] " + + "name:[${name.takeIf { it.isNotBlank() } ?: "unspecified"}] " + + "type:[${type ?: "unspecified"}] " + "modifiers:${modifiers ?: "[]"} " + "in Class [$classSet] " + "by $TAG" @@ -82,6 +88,7 @@ internal object ReflectionTool { /** * 查找任意方法 * @param classSet 方法所在类 + * @param index 下标 * @param name 方法名称 * @param modifiers 方法描述 * @param returnType 方法返回值 @@ -93,35 +100,42 @@ internal object ReflectionTool { */ internal fun findMethod( classSet: Class<*>?, + index: Int, name: String, modifiers: ModifierRules?, returnType: Class<*>?, paramCount: Int, paramTypes: Array>? ): Method { - val hashCode = ("[$name][$paramCount][${paramTypes.typeOfString()}][$returnType][$modifiers][$classSet]").hashCode() + val hashCode = ("[$index][$name][$paramCount][${paramTypes.typeOfString()}][$returnType][$modifiers][$classSet]").hashCode() return MemberCacheStore.findMethod(hashCode) ?: let { var method: Method? = null - run { - classSet?.declaredMethods?.forEach { - var conditions = name == it.name - if (returnType != null) conditions = conditions && it.returnType == returnType - if (paramCount >= 0) conditions = conditions && it.parameterTypes.size == paramCount - if (paramTypes != null) conditions = conditions && arrayContentsEq(paramTypes, it.parameterTypes) - if (modifiers != null) conditions = conditions && modifiers.contains(it) - if (conditions) { + classSet?.declaredMethods?.apply { + forEachIndexed { p, it -> + var isMatched = false + var conditions = true + if (name.isNotBlank()) conditions = (name == it.name).also { isMatched = true } + if (returnType != null) conditions = (conditions && it.returnType == returnType).also { isMatched = true } + if (paramCount >= 0) conditions = (conditions && it.parameterTypes.size == paramCount).also { isMatched = true } + if (paramTypes != null) conditions = + (conditions && arrayContentsEq(paramTypes, it.parameterTypes)).also { isMatched = true } + if (modifiers != null) conditions = (conditions && modifiers.contains(it)).also { isMatched = true } + if (index == -2) conditions = (conditions && p == lastIndex).also { isMatched = true } + if (index >= 0) conditions = (conditions && p == index).also { isMatched = true } + if (conditions && isMatched) { method = it.apply { isAccessible = true } - return@run + return@apply } - } ?: error("Can't find this Method [$name] because classSet is null") - } + } + } ?: error("Can't find this Method [$name] because classSet is null") method?.also { MemberCacheStore.putMethod(hashCode, method) } ?: throw NoSuchMethodError( "Can't find this Method --> " + - "name:[$name] " + + "index:[${index.takeIf { it >= 0 } ?: "unspecified"}] " + + "name:[${name.takeIf { it.isNotBlank() } ?: "unspecified"}] " + "paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " + "paramTypes:[${paramTypes.typeOfString()}] " + - "returnType:[$returnType] " + + "returnType:[${returnType ?: "unspecified"}] " + "modifiers:${modifiers ?: "[]"} " + "in Class [$classSet] " + "by $TAG" @@ -132,6 +146,7 @@ internal object ReflectionTool { /** * 查找任意构造方法 * @param classSet 构造方法所在类 + * @param index 下标 * @param modifiers 构造方法描述 * @param paramCount 构造方法参数个数 * @param paramTypes 构造方法参数类型 @@ -141,28 +156,34 @@ internal object ReflectionTool { */ internal fun findConstructor( classSet: Class<*>?, + index: Int, modifiers: ModifierRules?, paramCount: Int, paramTypes: Array>? ): Constructor<*> { - val hashCode = ("[$paramCount][${paramTypes.typeOfString()}][$modifiers][$classSet]").hashCode() + val hashCode = ("[$index][$paramCount][${paramTypes.typeOfString()}][$modifiers][$classSet]").hashCode() return MemberCacheStore.findConstructor(hashCode) ?: let { var constructor: Constructor<*>? = null - run { - classSet?.declaredConstructors?.forEach { - var conditions = false - if (paramCount >= 0) conditions = it.parameterTypes.size == paramCount - if (paramTypes != null) conditions = arrayContentsEq(paramTypes, it.parameterTypes) - if (modifiers != null) conditions = conditions && modifiers.contains(it) - if (conditions) { + classSet?.declaredConstructors?.apply { + forEachIndexed { p, it -> + var isMatched = false + var conditions = true + if (paramCount >= 0) conditions = (it.parameterTypes.size == paramCount).also { isMatched = true } + if (paramTypes != null) conditions = + (conditions && arrayContentsEq(paramTypes, it.parameterTypes)).also { isMatched = true } + if (modifiers != null) conditions = (conditions && modifiers.contains(it)).also { isMatched = true } + if (index == -2) conditions = (conditions && p == lastIndex).also { isMatched = true } + if (index >= 0) conditions = (conditions && p == index).also { isMatched = true } + if (conditions && isMatched) { constructor = it.apply { isAccessible = true } - return@run + return@apply } - } ?: error("Can't find this Constructor because classSet is null") - } + } + } ?: error("Can't find this Constructor because classSet is null") return constructor?.also { MemberCacheStore.putConstructor(hashCode, constructor) } ?: throw NoSuchMethodError( "Can't find this Constructor --> " + + "index:[${index.takeIf { it >= 0 } ?: "unspecified"}] " + "paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " + "paramTypes:[${paramTypes.typeOfString()}] " + "modifiers:${modifiers ?: "[]"} " +