Modify almost code, update version to 1.0.2

This commit is contained in:
2022-02-18 03:21:49 +08:00
parent a1bbf0e204
commit 72ebc29a07
7 changed files with 405 additions and 162 deletions

View File

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

View File

@@ -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<out Class<*>>? = 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 <T> newInstance(vararg param: Any?) = baseCall(*param) as? T?
override fun toString() = "[${(memberInstance as? Constructor<*>?)?.name ?: "<empty>"}]"
}
}
}

View File

@@ -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 ?: "<empty>"}] in [${instance?.javaClass?.name ?: "<empty>"}] value \"$self\""
}
}
}

View File

@@ -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<out Class<*>>? = 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 <T> invoke(vararg param: Any?) = baseCall(*param) as? T?
override fun toString() =
"[${(memberInstance as? Method?)?.name ?: "<empty>"}] in [${instance?.javaClass?.name ?: "<empty>"}]"
}
}
}

View File

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

View File

@@ -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<out Any>? =
if (paramType.isNotEmpty())
ReflectionUtils.findConstructorExact(this, *paramType)
else ReflectionUtils.findConstructorExact(this)
/**
* 执行静态方法
* @param param 方法参数
* @return [T] or null
*/
inline fun <reified T> 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 <reified T> 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()

View File

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