diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/VariousClass.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/VariousClass.kt index a8bbc4c4..d09afab1 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/VariousClass.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/VariousClass.kt @@ -27,12 +27,35 @@ */ package com.highcapable.yukihookapi.hook.bean +import com.highcapable.yukihookapi.hook.factory.classOf + /** * 这是一个不确定性 [Class] 类名装载器 * @param name 可指定多个类名 - 将会自动匹配存在的第一个类名 */ class VariousClass(vararg var name: String) { + /** + * 获取匹配的实体类 + * + * - 使用当前 [loader] 装载目标 [Class] + * @param loader 当前 [ClassLoader] - 若留空使用默认 [ClassLoader] + * @return [Class] + * @throws IllegalStateException 如果任何 [Class] 都没有匹配到 + */ + fun get(loader: ClassLoader? = null): Class<*> { + var finalClass: Class<*>? = null + if (name.isNotEmpty()) run { + name.forEach { + runCatching { + finalClass = classOf(it, loader) + return@run + } + } + } + return finalClass ?: error("VariousClass match failed of those $this") + } + override fun toString(): String { var result = "" return if (name.isNotEmpty()) { 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 a502a316..92d1d1b9 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 @@ -30,10 +30,12 @@ package com.highcapable.yukihookapi.hook.core.finder import com.highcapable.yukihookapi.annotation.YukiPrivateApi +import com.highcapable.yukihookapi.hook.bean.VariousClass 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.yLoggerW +import com.highcapable.yukihookapi.hook.type.defined.UndefinedType import com.highcapable.yukihookapi.hook.utils.ReflectionTool import com.highcapable.yukihookapi.hook.utils.runBlocking import java.lang.reflect.Constructor @@ -93,12 +95,12 @@ class ConstructorFinder( * - ❗有参 [Constructor] 必须使用此方法设定参数或使用 [paramCount] 指定个数 * * - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个 - * @param paramType 参数类型数组 + * @param paramType 参数类型数组 - ❗只能是 [Class]、[String]、[VariousClass] * @return [BaseFinder.IndexTypeCondition] */ - fun param(vararg paramType: Class<*>): IndexTypeCondition { + fun param(vararg paramType: Any): IndexTypeCondition { if (paramType.isEmpty()) error("paramTypes is empty, please delete param() method") - paramTypes = paramType + paramTypes = ArrayList>().apply { paramType.forEach { add(it.compat() ?: UndefinedType) } }.toTypedArray() return IndexTypeCondition(IndexConfigType.MATCH) } 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 155d686b..a05c0845 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 @@ -31,6 +31,7 @@ package com.highcapable.yukihookapi.hook.core.finder import android.os.SystemClock import com.highcapable.yukihookapi.annotation.YukiPrivateApi +import com.highcapable.yukihookapi.hook.bean.VariousClass 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 @@ -63,9 +64,25 @@ class FieldFinder( /** * [Field] 类型 * + * - ❗只能是 [Class]、[String]、[VariousClass] + * * - 可不填写类型 - 默认模糊查找并取第一个匹配的 [Field] */ - var type: Class<*>? = null + var type: Any? = null + + /** + * [Field] 筛选条件 + * + * 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Field] + * + * - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个 + * @param initiate 方法体 + * @return [BaseFinder.IndexTypeCondition] + */ + fun modifiers(initiate: ModifierRules.() -> Unit): IndexTypeCondition { + modifiers = ModifierRules().apply(initiate) + return IndexTypeCondition(IndexConfigType.MATCH) + } /** * 顺序筛选字节码的下标 @@ -93,28 +110,14 @@ class FieldFinder( * - 可不填写类型 - 默认模糊查找并取第一个匹配的 [Field] * * - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个 - * @param value 类型 + * @param value 类型 - ❗只能是 [Class]、[String]、[VariousClass] * @return [BaseFinder.IndexTypeCondition] */ - fun type(value: Class<*>): IndexTypeCondition { + fun type(value: Any): IndexTypeCondition { type = value return IndexTypeCondition(IndexConfigType.MATCH) } - /** - * [Field] 筛选条件 - * - * 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Field] - * - * - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个 - * @param initiate 方法体 - * @return [BaseFinder.IndexTypeCondition] - */ - fun modifiers(initiate: ModifierRules.() -> Unit): IndexTypeCondition { - modifiers = ModifierRules().apply(initiate) - return IndexTypeCondition(IndexConfigType.MATCH) - } - /** * 得到变量处理结果 * @@ -127,7 +130,7 @@ class FieldFinder( override fun build(isBind: Boolean) = try { if (classSet != null) { runBlocking { - memberInstance = ReflectionTool.findField(classSet, orderIndex, matchIndex, name, modifiers, type) + memberInstance = ReflectionTool.findField(classSet, orderIndex, matchIndex, name, modifiers, type.compat()) }.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") } Result() } else Result(isNoSuch = true, Throwable("classSet is null")) @@ -135,7 +138,7 @@ class FieldFinder( Thread { /** 延迟使得方法取到返回值 */ SystemClock.sleep(1) - onFailureMsg(msg = "NoSuchField happend in [$classSet] [${hookTag}]", throwable = e) + onFailureMsg(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 2f6ea11e..0f907d32 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 @@ -30,10 +30,12 @@ package com.highcapable.yukihookapi.hook.core.finder import com.highcapable.yukihookapi.annotation.YukiPrivateApi +import com.highcapable.yukihookapi.hook.bean.VariousClass 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.yLoggerW +import com.highcapable.yukihookapi.hook.type.defined.UndefinedType import com.highcapable.yukihookapi.hook.utils.ReflectionTool import com.highcapable.yukihookapi.hook.utils.runBlocking import java.lang.reflect.Method @@ -81,9 +83,11 @@ class MethodFinder( /** * [Method] 返回值 * - * 可不填写返回值 - 默认模糊查找并取第一个匹配的 [Method] + * - ❗只能是 [Class]、[String]、[VariousClass] + * + * - 可不填写返回值 - 默认模糊查找并取第一个匹配的 [Method] */ - var returnType: Class<*>? = null + var returnType: Any? = null /** * [Method] 筛选条件 @@ -109,12 +113,12 @@ class MethodFinder( * - ❗有参 [Method] 必须使用此方法设定参数或使用 [paramCount] 指定个数 * * - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个 - * @param paramType 参数类型数组 + * @param paramType 参数类型数组 - ❗只能是 [Class]、[String]、[VariousClass] * @return [BaseFinder.IndexTypeCondition] */ - fun param(vararg paramType: Class<*>): IndexTypeCondition { + fun param(vararg paramType: Any): IndexTypeCondition { if (paramType.isEmpty()) error("paramTypes is empty, please delete param() method") - paramTypes = paramType + paramTypes = ArrayList>().apply { paramType.forEach { add(it.compat() ?: UndefinedType) } }.toTypedArray() return IndexTypeCondition(IndexConfigType.MATCH) } @@ -163,7 +167,7 @@ class MethodFinder( * @param value 个数 * @return [BaseFinder.IndexTypeCondition] */ - fun returnType(value: Class<*>): IndexTypeCondition { + fun returnType(value: Any): IndexTypeCondition { returnType = value return IndexTypeCondition(IndexConfigType.MATCH) } @@ -173,7 +177,8 @@ class MethodFinder( * @return [Method] * @throws NoSuchMethodError 如果找不到方法 */ - private val result get() = ReflectionTool.findMethod(classSet, orderIndex, matchIndex, name, modifiers, returnType, paramCount, paramTypes) + private val result + get() = ReflectionTool.findMethod(classSet, orderIndex, matchIndex, name, modifiers, returnType.compat(), paramCount, paramTypes) /** * 设置实例 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 index f86d685c..3ae2fe6d 100644 --- 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 @@ -30,9 +30,12 @@ package com.highcapable.yukihookapi.hook.core.finder.base import android.os.SystemClock import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.annotation.YukiPrivateApi +import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.yukihookapi.hook.core.YukiHookCreater +import com.highcapable.yukihookapi.hook.factory.classOf import com.highcapable.yukihookapi.hook.log.yLoggerE import com.highcapable.yukihookapi.hook.log.yLoggerI +import com.highcapable.yukihookapi.hook.type.defined.UndefinedType import java.lang.reflect.Member import kotlin.math.abs @@ -133,6 +136,18 @@ abstract class BaseFinder( */ internal val isNotIgnoredNoSuchMemberFailure get() = hookInstance?.isNotIgnoredNoSuchMemberFailure ?: true + /** + * 将目标类型转换为可识别的兼容类型 + * @return [Class] or null + */ + internal fun Any?.compat() = when (this) { + null -> null + is Class<*> -> this + is String -> runCatching { classOf(name = this, classSet!!.classLoader) }.getOrNull() ?: UndefinedType + is VariousClass -> runCatching { get(classSet!!.classLoader) }.getOrNull() ?: UndefinedType + else -> error("$tag match type \"$javaClass\" not allowed") + } as Class<*>? + /** * 发生错误时输出日志 * @param msg 消息日志 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 59c7e171..4aabde7d 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 @@ -176,19 +176,7 @@ open class PackageParam(private var wrapper: PackageParamWrapper? = null) { * @return [Class] * @throws IllegalStateException 如果任何 [Class] 都没有匹配到 */ - val VariousClass.clazz - get() :Class<*> { - var finalClass: Class<*>? = null - if (name.isNotEmpty()) run { - name.forEach { - runCatching { - finalClass = it.clazz - return@run - } - } - } - return finalClass ?: error("VariousClass match failed of those $this") - } + val VariousClass.clazz get() = get(appClassLoader) /** * 通过字符串查找类是否存在 @@ -214,9 +202,9 @@ open class PackageParam(private var wrapper: PackageParamWrapper? = null) { * * 使用此方法查询将会取 [name] 其中命中存在的第一个 [Class] 作为结果 * @param name 可填入多个类名 - 自动匹配 - * @return [HookClass] + * @return [VariousClass] */ - fun findClass(vararg name: String) = VariousClass(*name).hookClass + fun findClass(vararg name: String) = VariousClass(*name) /** * Hook 方法、构造类 @@ -245,7 +233,7 @@ open class PackageParam(private var wrapper: PackageParamWrapper? = null) { * @return [YukiHookCreater.Result] */ fun VariousClass.hook(isUseAppClassLoader: Boolean = true, initiate: YukiHookCreater.() -> Unit) = - hookClass.hook(isUseAppClassLoader, initiate) + get(if (isUseAppClassLoader) appClassLoader else null).hookClass.hook(isUseAppClassLoader, initiate) /** * Hook 方法、构造类 diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.kt new file mode 100644 index 00000000..88b08aa2 --- /dev/null +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/type/defined/DefinedTypeFactory.kt @@ -0,0 +1,37 @@ +/* + * 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/4/3. + */ +package com.highcapable.yukihookapi.hook.type.defined + +/** 未定义类型实例 */ +internal class UndefinedClass + +/** + * 未定义类型 + * @return [UndefinedClass] + */ +internal val UndefinedType get() = UndefinedClass::class.java \ No newline at end of file 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 429bf3f4..e6b7c572 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 @@ -29,6 +29,7 @@ package com.highcapable.yukihookapi.hook.utils import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules import com.highcapable.yukihookapi.hook.store.MemberCacheStore +import com.highcapable.yukihookapi.hook.type.defined.UndefinedType import java.lang.reflect.Constructor import java.lang.reflect.Field import java.lang.reflect.Member @@ -52,7 +53,7 @@ internal object ReflectionTool { * @param modifiers 变量描述 * @param type 变量类型 * @return [Field] - * @throws IllegalStateException 如果 [classSet] 为 null 或未设置任何条件 + * @throws IllegalStateException 如果 [classSet] 为 null 或未设置任何条件或 [type] 目标类不存在 * @throws NoSuchFieldError 如果找不到变量 */ internal fun findField( @@ -63,6 +64,7 @@ internal object ReflectionTool { modifiers: ModifierRules?, type: Class<*>? ): Field { + if (type == UndefinedType) error("Field match type class is not found") if (orderIndex == null && matchIndex == null && name.isBlank() && modifiers == null && type == null) error("You must set a condition when finding a Field") val hashCode = ("[$orderIndex][$matchIndex][$name][$type][$modifiers][$classSet]").hashCode() @@ -155,7 +157,7 @@ internal object ReflectionTool { * @param paramCount 方法参数个数 * @param paramTypes 方法参数类型 * @return [Method] - * @throws IllegalStateException 如果 [classSet] 为 null 或未设置任何条件 + * @throws IllegalStateException 如果 [classSet] 为 null 或未设置任何条件或 [paramTypes] 以及 [returnType] 目标类不存在 * @throws NoSuchMethodError 如果找不到方法 */ internal fun findMethod( @@ -168,6 +170,9 @@ internal object ReflectionTool { paramCount: Int, paramTypes: Array>? ): Method { + if (returnType == UndefinedType) error("Method match returnType class is not found") + paramTypes?.takeIf { it.isNotEmpty() } + ?.forEachIndexed { p, it -> if (it == UndefinedType) error("Method match paramType[$p] class is not found") } if (orderIndex == null && matchIndex == null && name.isBlank() && modifiers == null && paramCount < 0 && paramTypes == null && returnType == null) error("You must set a condition when finding a Method") val hashCode = @@ -288,7 +293,7 @@ internal object ReflectionTool { * @param paramCount 构造方法参数个数 * @param paramTypes 构造方法参数类型 * @return [Constructor] - * @throws IllegalStateException 如果 [classSet] 为 null 或未设置任何条件 + * @throws IllegalStateException 如果 [classSet] 为 null 或未设置任何条件或 [paramTypes] 目标类不存在 * @throws NoSuchMethodError 如果找不到构造方法 */ internal fun findConstructor( @@ -299,6 +304,8 @@ internal object ReflectionTool { paramCount: Int, paramTypes: Array>? ): Constructor<*> { + paramTypes?.takeIf { it.isNotEmpty() } + ?.forEachIndexed { p, it -> if (it == UndefinedType) error("Constructor match paramType[$p] class is not found") } if (orderIndex == null && matchIndex == null && paramCount < 0 && paramTypes == null && modifiers == null) error("You must set a condition when finding a Constructor") val hashCode = ("[$orderIndex][$matchIndex][$paramCount][${paramTypes.typeOfString()}][$modifiers][$classSet]").hashCode()