Added any type finding function

This commit is contained in:
2022-04-04 00:39:55 +08:00
parent f1112741bf
commit d4e154384c
8 changed files with 128 additions and 48 deletions

View File

@@ -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()) {

View File

@@ -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<Class<*>>().apply { paramType.forEach { add(it.compat() ?: UndefinedType) } }.toTypedArray()
return IndexTypeCondition(IndexConfigType.MATCH)
}

View File

@@ -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)
}

View File

@@ -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<Class<*>>().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)
/**
* 设置实例

View File

@@ -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 消息日志

View File

@@ -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 方法、构造类

View File

@@ -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

View File

@@ -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<out Class<*>>?
): 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<out Class<*>>?
): 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()