mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 01:35:17 +08:00
...
This commit is contained in:
@@ -50,6 +50,7 @@ class MainInjecter : YukiHookXposedInitProxy {
|
||||
|
||||
override fun onHook() {
|
||||
// 设置模式
|
||||
YukiHookAPI.debugTag = "YukiSuki"
|
||||
YukiHookAPI.isDebug = true
|
||||
// 方案 1
|
||||
// encase(MainHooker(), SecondHooker())
|
||||
@@ -80,11 +81,11 @@ class MainInjecter : YukiHookXposedInitProxy {
|
||||
method {
|
||||
name = "a"
|
||||
param(StringType, StringType)
|
||||
returnType = StringType
|
||||
returnType = UnitType
|
||||
}
|
||||
beforeHook {
|
||||
args(index = 0).set("改了前面的")
|
||||
args(index = 1).set("改了后面的")
|
||||
args(index = 0).set("✌️改了前面的")
|
||||
args(index = 1).set("✌️改了后面的")
|
||||
}
|
||||
}
|
||||
injectMember {
|
||||
@@ -141,11 +142,9 @@ class MainInjecter : YukiHookXposedInitProxy {
|
||||
}.failures {
|
||||
onConductFailure { _, _ -> }
|
||||
onHookingFailure {}
|
||||
onNoSuchMemberFailure {}
|
||||
onAllFailure {}
|
||||
ignoredConductFailure()
|
||||
ignoredHookingFailure()
|
||||
ignoredNoSuchMemberFailure()
|
||||
ignoredAllFailure()
|
||||
}
|
||||
}
|
||||
|
@@ -49,15 +49,23 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||
@Keep
|
||||
object YukiHookAPI {
|
||||
|
||||
/** 全局标识 */
|
||||
const val TAG = "YukiHookAPI"
|
||||
/**
|
||||
* 这是一个调试日志的全局标识
|
||||
*
|
||||
* 默认文案为 YukiHookAPI
|
||||
*
|
||||
* 你可以修改为你自己的文案
|
||||
*/
|
||||
var debugTag = "YukiHookAPI"
|
||||
|
||||
/**
|
||||
* 是否开启调试模式 - 默认启用
|
||||
*
|
||||
* 启用后将交由日志输出管理器打印详细 Hook 日志到控制台
|
||||
*
|
||||
* 请过滤 [TAG] (YukiHookAPI) 即可找到每条日志
|
||||
* 关闭后将只输出 Error 级别的日志
|
||||
*
|
||||
* 请过滤 [debugTag] 即可找到每条日志
|
||||
*/
|
||||
var isDebug = true
|
||||
|
||||
|
@@ -38,7 +38,6 @@ import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.log.loggerI
|
||||
import com.highcapable.yukihookapi.hook.param.HookParam
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import de.robv.android.xposed.XC_MethodReplacement
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
@@ -59,15 +58,17 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
|
||||
/**
|
||||
* 注入要 Hook 的方法、构造类
|
||||
* @param tag 可设置标签 - 在发生错误时方便进行调试
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun injectMember(initiate: MemberHookCreater.() -> Unit) =
|
||||
MemberHookCreater().apply(initiate).apply {
|
||||
fun injectMember(tag: String = "Default", initiate: MemberHookCreater.() -> Unit) =
|
||||
MemberHookCreater(tag).apply(initiate).apply {
|
||||
hookMembers[toString()] = this
|
||||
}.create()
|
||||
}.build()
|
||||
|
||||
/**
|
||||
* Hook 执行入口 - 不可在外部调用
|
||||
* Hook 执行入口
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @throws IllegalStateException 如果必要参数没有被设置
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
@@ -80,8 +81,9 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* 智能全局方法、构造类查找类实现方法
|
||||
*
|
||||
* 处理需要 Hook 的方法
|
||||
* @param tag 当前设置的标签
|
||||
*/
|
||||
inner class MemberHookCreater {
|
||||
inner class MemberHookCreater(var tag: String) {
|
||||
|
||||
/** [beforeHook] 回调 */
|
||||
private var beforeHookCallback: (HookParam.() -> Unit)? = null
|
||||
@@ -98,17 +100,14 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
/** Hook 开始时出现错误回调 */
|
||||
private var onHookingFailureCallback: ((Throwable) -> Unit)? = null
|
||||
|
||||
/** 当找不到方法、变量时错误回调 */
|
||||
private var onNoSuchMemberCallback: ((Throwable) -> Unit)? = null
|
||||
|
||||
/** 全部错误回调 */
|
||||
private var onAllFailureCallback: ((Throwable) -> Unit)? = null
|
||||
|
||||
/** 是否为替换 Hook 模式 */
|
||||
private var isReplaceHookMode = false
|
||||
|
||||
/** 是否停止 Hook */
|
||||
private var isStopHookMode = false
|
||||
/** 标识是否已经设置了要 Hook 的 [member] */
|
||||
private var isHookMemberSetup = false
|
||||
|
||||
/**
|
||||
* 手动指定要 Hook 的方法、构造类
|
||||
@@ -122,17 +121,12 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
*
|
||||
* 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换
|
||||
* @param initiate 方法体
|
||||
* @return [MethodFinder.Result]
|
||||
*/
|
||||
fun method(initiate: MethodFinder.() -> Unit) = runBlocking {
|
||||
runCatching {
|
||||
member = MethodFinder(hookClass).apply(initiate).find()
|
||||
}.onFailure {
|
||||
isStopHookMode = true
|
||||
onNoSuchMemberCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
}
|
||||
}.result { onHookLogMsg(msg = "Find Method [$member] takes ${it}ms") }
|
||||
fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result {
|
||||
isHookMemberSetup = true
|
||||
return MethodFinder(hookInstance = this, hookClass).apply(initiate).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找需要 Hook 的构造类
|
||||
@@ -140,16 +134,10 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun constructor(initiate: ConstructorFinder.() -> Unit) = runBlocking {
|
||||
runCatching {
|
||||
member = ConstructorFinder(hookClass).apply(initiate).find()
|
||||
}.onFailure {
|
||||
isStopHookMode = true
|
||||
onNoSuchMemberCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
}
|
||||
}.result { onHookLogMsg(msg = "Find Constructor [$member] takes ${it}ms") }
|
||||
fun constructor(initiate: ConstructorFinder.() -> Unit): ConstructorFinder.Result {
|
||||
isHookMemberSetup = true
|
||||
return ConstructorFinder(hookInstance = this, hookClass).apply(initiate).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找 [Field]
|
||||
@@ -157,19 +145,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* @return [FieldFinder.Result]
|
||||
*/
|
||||
fun HookParam.field(initiate: FieldFinder.() -> Unit) =
|
||||
try {
|
||||
var result: FieldFinder.Result? = null
|
||||
runBlocking {
|
||||
result = FieldFinder(hookClass).apply(initiate).find()
|
||||
}.result { onHookLogMsg(msg = "Find Field [${result?.give()}] takes ${it}ms") }
|
||||
result!!
|
||||
} catch (e: Throwable) {
|
||||
isStopHookMode = true
|
||||
onNoSuchMemberCallback?.invoke(e)
|
||||
onAllFailureCallback?.invoke(e)
|
||||
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(e)
|
||||
FieldFinder(hookClass).Result()
|
||||
}
|
||||
FieldFinder(hookInstance = this@MemberHookCreater, hookClass).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 在方法执行完成前 Hook
|
||||
@@ -263,80 +239,99 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 创建入口 - 不可在外部调用
|
||||
* Hook 创建入口
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun create() = Result()
|
||||
fun build() = Result()
|
||||
|
||||
/**
|
||||
* Hook 执行入口 - 不可在外部调用
|
||||
* @throws IllegalStateException 如果必要参数没有被设置
|
||||
* Hook 执行入口
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun hook() {
|
||||
if (isStopHookMode) return
|
||||
member?.also { member ->
|
||||
runCatching {
|
||||
if (isReplaceHookMode)
|
||||
XposedBridge.hookMethod(member, object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(baseParam: MethodHookParam?): Any? {
|
||||
if (baseParam == null) return null
|
||||
return HookParam(baseParam).let { param ->
|
||||
try {
|
||||
if (replaceHookCallback != null)
|
||||
onHookLogMsg(msg = "Replace Hook Member [${member}] done")
|
||||
replaceHookCallback?.invoke(param)
|
||||
} catch (e: Throwable) {
|
||||
onConductFailureCallback?.invoke(param, e)
|
||||
onAllFailureCallback?.invoke(e)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(e)
|
||||
null
|
||||
if (member != null)
|
||||
member.also { member ->
|
||||
runCatching {
|
||||
if (isReplaceHookMode)
|
||||
XposedBridge.hookMethod(member, object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(baseParam: MethodHookParam?): Any? {
|
||||
if (baseParam == null) return null
|
||||
return HookParam(baseParam).let { param ->
|
||||
try {
|
||||
if (replaceHookCallback != null)
|
||||
onHookLogMsg(msg = "Replace Hook Member [${member}] done [$tag]")
|
||||
replaceHookCallback?.invoke(param)
|
||||
} catch (e: Throwable) {
|
||||
onConductFailureCallback?.invoke(param, e)
|
||||
onAllFailureCallback?.invoke(e)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
else
|
||||
XposedBridge.hookMethod(member, object : XC_MethodHook() {
|
||||
override fun beforeHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
runCatching {
|
||||
beforeHookCallback?.invoke(param)
|
||||
if (beforeHookCallback != null)
|
||||
onHookLogMsg(msg = "Before Hook Member [${member}] done")
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
})
|
||||
else
|
||||
XposedBridge.hookMethod(member, object : XC_MethodHook() {
|
||||
override fun beforeHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
runCatching {
|
||||
beforeHookCallback?.invoke(param)
|
||||
if (beforeHookCallback != null)
|
||||
onHookLogMsg(msg = "Before Hook Member [${member}] done [$tag]")
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
runCatching {
|
||||
afterHookCallback?.invoke(param)
|
||||
if (afterHookCallback != null)
|
||||
onHookLogMsg(msg = "After Hook Member [${member}] done")
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
override fun afterHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
runCatching {
|
||||
afterHookCallback?.invoke(param)
|
||||
if (afterHookCallback != null)
|
||||
onHookLogMsg(msg = "After Hook Member [${member}] done [$tag]")
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}.onFailure {
|
||||
onHookingFailureCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onHookingFailureCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
})
|
||||
}.onFailure {
|
||||
onHookingFailureCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onHookingFailureCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
} ?: error("Hook Member cannot be null")
|
||||
else {
|
||||
onHookingFailureCallback?.invoke(Throwable())
|
||||
onAllFailureCallback?.invoke(Throwable())
|
||||
if (onHookingFailureCallback == null && onAllFailureCallback == null)
|
||||
loggerE(
|
||||
msg = if (isHookMemberSetup)
|
||||
"Hooked Member with a finding error in Class [$hookClass] [$tag]"
|
||||
else "Hooked Member cannot be non-null in Class [$hookClass] [$tag]"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 过程中开启了 [YukiHookAPI.isDebug] 输出调试信息
|
||||
* @param msg 调试日志内容
|
||||
*/
|
||||
internal fun onHookLogMsg(msg: String) {
|
||||
if (YukiHookAPI.isDebug) loggerI(msg = msg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,17 +339,9 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* @param throwable 异常信息
|
||||
*/
|
||||
private fun onHookFailureMsg(throwable: Throwable) =
|
||||
loggerE(msg = "Try to hook $hookClass[$member] got an Exception", e = throwable)
|
||||
loggerE(msg = "Try to hook $hookClass[$member] got an Exception [$tag]", e = throwable)
|
||||
|
||||
/**
|
||||
* Hook 过程中开启了 [YukiHookAPI.isDebug] 输出调试信息
|
||||
* @param msg 调试日志内容
|
||||
*/
|
||||
private fun onHookLogMsg(msg: String) {
|
||||
if (YukiHookAPI.isDebug) loggerI(msg = msg)
|
||||
}
|
||||
|
||||
override fun toString() = "$member#YukiHook"
|
||||
override fun toString() = "$member$tag#YukiHook"
|
||||
|
||||
/**
|
||||
* 监听 Hook 结果实现类
|
||||
@@ -388,7 +375,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
|
||||
/**
|
||||
* 监听 Hook 开始时发生错误的回调方法
|
||||
* @param initiate 回调错误 - ([Throwable] 异常)
|
||||
* @param initiate 回调错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onHookingFailure(initiate: (Throwable) -> Unit): Result {
|
||||
@@ -402,25 +389,9 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
*/
|
||||
fun ignoredHookingFailure() = onHookingFailure {}
|
||||
|
||||
/**
|
||||
* 监听 Hook 过程发生找不到方法、变量错误的回调方法
|
||||
* @param initiate 回调错误 - ([Throwable] 异常)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onNoSuchMemberFailure(initiate: (Throwable) -> Unit): Result {
|
||||
onNoSuchMemberCallback = initiate
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略 Hook 过程发生找不到方法、变量的错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun ignoredNoSuchMemberFailure() = onNoSuchMemberFailure {}
|
||||
|
||||
/**
|
||||
* 监听全部 Hook 过程发生错误的回调方法
|
||||
* @param initiate 回调错误 - ([Throwable] 异常)
|
||||
* @param initiate 回调错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onAllFailure(initiate: (Throwable) -> Unit): Result {
|
||||
|
@@ -25,27 +25,35 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/4.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
@file:Suppress("unused", "EXPERIMENTAL_API_USAGE", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder
|
||||
|
||||
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.loggerW
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import java.lang.reflect.Constructor
|
||||
|
||||
/**
|
||||
* [Constructor] 查找类
|
||||
*
|
||||
* 可通过指定类型查找指定构造类
|
||||
* 可通过指定类型查找指定构造方法
|
||||
* @param hookInstance 当前 Hook 实例
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class ConstructorFinder(private val hookClass: Class<*>) {
|
||||
class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
|
||||
|
||||
/** 方法参数 */
|
||||
/** 失败尝试次数数组 */
|
||||
private val remedyPlan = HashMap<Long, ConstructorFinder>()
|
||||
|
||||
/** 构造方法参数 */
|
||||
private var params: Array<out Class<*>>? = null
|
||||
|
||||
/**
|
||||
* 方法参数
|
||||
* 构造方法参数
|
||||
* @param param 参数数组
|
||||
*/
|
||||
fun param(vararg param: Class<*>) {
|
||||
@@ -53,13 +61,135 @@ class ConstructorFinder(private val hookClass: Class<*>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到构造类 - 不能在外部调用
|
||||
* 得到构造方法
|
||||
* @return [Constructor]
|
||||
* @throws NoSuchMethodError 如果找不到构造类
|
||||
* @throws NoSuchMethodError 如果找不到构造方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun find(): Constructor<*> =
|
||||
if (params != null)
|
||||
private val result
|
||||
get() = if (params != null)
|
||||
ReflectionUtils.findConstructorExact(hookClass, *params!!)
|
||||
else ReflectionUtils.findConstructorExact(hookClass)
|
||||
|
||||
/**
|
||||
* 得到构造方法结果
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun build() = try {
|
||||
runBlocking {
|
||||
hookInstance.member = result
|
||||
}.result {
|
||||
hookInstance.onHookLogMsg(msg = "Find Constructor [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]")
|
||||
}
|
||||
Result()
|
||||
} catch (e: Throwable) {
|
||||
onFailureMsg(throwable = e)
|
||||
Result(isNoSuch = true, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生错误时输出日志
|
||||
* @param msg 消息日志
|
||||
* @param throwable 错误
|
||||
*/
|
||||
private fun onFailureMsg(msg: String = "", throwable: Throwable? = null) =
|
||||
loggerE(msg = "NoSuchConstructor happend in [$hookClass] $msg [${hookInstance.tag}]", e = throwable)
|
||||
|
||||
/**
|
||||
* [Constructor] 重查找实现类
|
||||
*
|
||||
* 可累计失败次数直到查找成功
|
||||
*/
|
||||
inner class RemedyPlan {
|
||||
|
||||
/** 失败尝试次数数组 */
|
||||
private val remedyPlan = HashSet<ConstructorFinder>()
|
||||
|
||||
/**
|
||||
* 创建需要重新查找的 [Constructor]
|
||||
*
|
||||
* 你可以添加多个备选构造方法 - 直到成功为止
|
||||
*
|
||||
* 若最后依然失败 - 将停止查找并输出错误日志
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun constructor(initiate: ConstructorFinder.() -> Unit) =
|
||||
remedyPlan.add(ConstructorFinder(hookInstance, hookClass).apply(initiate))
|
||||
|
||||
/**
|
||||
* 开始重查找
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun build() {
|
||||
if (remedyPlan.isNotEmpty()) run {
|
||||
var isFindSuccess = false
|
||||
var lastError: Throwable? = null
|
||||
remedyPlan.forEachIndexed { p, it ->
|
||||
runCatching {
|
||||
runBlocking {
|
||||
hookInstance.member = it.result
|
||||
}.result {
|
||||
hookInstance.onHookLogMsg(msg = "Find Constructor [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]")
|
||||
}
|
||||
isFindSuccess = true
|
||||
hookInstance.onHookLogMsg(msg = "Constructor [${hookInstance.member}] trying ${p + 1} times success by RemedyPlan [${hookInstance.tag}]")
|
||||
return@run
|
||||
}.onFailure {
|
||||
lastError = it
|
||||
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it")
|
||||
}
|
||||
}
|
||||
if (!isFindSuccess) {
|
||||
onFailureMsg(
|
||||
msg = "trying ${remedyPlan.size} times and all failure by RemedyPlan",
|
||||
throwable = lastError
|
||||
)
|
||||
remedyPlan.clear()
|
||||
}
|
||||
} else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookInstance.tag}]")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Constructor] 查找结果实现类
|
||||
* @param isNoSuch 是否没有找到构造方法 - 默认否
|
||||
* @param e 错误信息
|
||||
*/
|
||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun result(initiate: Result.() -> Unit) = apply(initiate)
|
||||
|
||||
/**
|
||||
* 创建构造方法重查找功能
|
||||
*
|
||||
* 当你遇到一种构造方法可能存在不同形式的存在时
|
||||
*
|
||||
* 可以使用 [RemedyPlan] 重新查找它 - 而没有必要使用 [onNoSuchConstructor] 捕获异常二次查找构造方法
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun remedys(initiate: RemedyPlan.() -> Unit): Result {
|
||||
if (isNoSuch) RemedyPlan().apply(initiate).build()
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听找不到构造方法时
|
||||
*
|
||||
* 只会返回第一次的错误信息 - 不会返回 [RemedyPlan] 的错误信息
|
||||
* @param initiate 回调错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onNoSuchConstructor(initiate: (Throwable) -> Unit): Result {
|
||||
if (isNoSuch) initiate(e ?: Throwable())
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
@@ -30,16 +30,20 @@
|
||||
package com.highcapable.yukihookapi.hook.core.finder
|
||||
|
||||
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.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import java.lang.reflect.Field
|
||||
|
||||
/**
|
||||
* Field 查找结果实现类
|
||||
*
|
||||
* 可在这里处理找到的 [fieldInstance]
|
||||
* @param hookInstance 当前 Hook 实例
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class FieldFinder(private val hookClass: Class<*>) {
|
||||
class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
|
||||
|
||||
/** 当前找到的 [Field] */
|
||||
private var fieldInstance: Field? = null
|
||||
@@ -51,25 +55,42 @@ class FieldFinder(private val hookClass: Class<*>) {
|
||||
var type: Class<*>? = null
|
||||
|
||||
/**
|
||||
* 得到变量处理结果 - 不能在外部调用
|
||||
* 得到变量处理结果
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @return [Result]
|
||||
* @throws NoSuchFieldError 如果找不到变量
|
||||
* @throws IllegalStateException 如果 [name] 没有被设置
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun find(): Result {
|
||||
fieldInstance = when {
|
||||
name.isBlank() -> error("Field name cannot be empty")
|
||||
else -> ReflectionUtils.findFieldIfExists(hookClass, type?.name, name)
|
||||
fun build() = if (name.isBlank()) {
|
||||
loggerE(msg = "Field name cannot be empty in Class [$hookClass] [${hookInstance.tag}]")
|
||||
Result(isNoSuch = true)
|
||||
} else try {
|
||||
runBlocking {
|
||||
fieldInstance = ReflectionUtils.findFieldIfExists(hookClass, type?.name, name)
|
||||
}.result {
|
||||
hookInstance.onHookLogMsg(msg = "Find Field [${fieldInstance}] takes ${it}ms [${hookInstance.tag}]")
|
||||
}
|
||||
return Result()
|
||||
Result()
|
||||
} catch (e: Throwable) {
|
||||
loggerE(msg = "NoSuchField happend in [$hookClass] [${hookInstance.tag}]", e = e)
|
||||
Result(isNoSuch = true, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Field 查找结果实现类
|
||||
*
|
||||
* 可在这里处理找到的 [fieldInstance]
|
||||
* @param isNoSuch 是否没有找到变量 - 默认否
|
||||
* @param e 错误信息
|
||||
*/
|
||||
inner class Result {
|
||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun result(initiate: Result.() -> Unit) = apply(initiate)
|
||||
|
||||
/**
|
||||
* 设置变量实例
|
||||
@@ -90,5 +111,17 @@ class FieldFinder(private val hookClass: Class<*>) {
|
||||
* @return [Field] or null
|
||||
*/
|
||||
fun give() = fieldInstance
|
||||
|
||||
/**
|
||||
* 监听找不到变量时
|
||||
*
|
||||
* 只会返回第一次和最后一次的错误信息
|
||||
* @param initiate 回调错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onNoSuchField(initiate: (Throwable) -> Unit): Result {
|
||||
if (isNoSuch) initiate(e ?: Throwable())
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
@@ -25,21 +25,26 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/4.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder
|
||||
|
||||
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.loggerW
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* [Method] 查找类
|
||||
*
|
||||
* 可通过指定类型查找指定方法
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
* @param hookInstance 当前 Hook 实例
|
||||
* @param hookClass 当前 Hook 的 Class
|
||||
*/
|
||||
class MethodFinder(private val hookClass: Class<*>) {
|
||||
class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
|
||||
|
||||
/** 方法参数 */
|
||||
private var params: Array<out Class<*>>? = null
|
||||
@@ -59,17 +64,140 @@ class MethodFinder(private val hookClass: Class<*>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到方法 - 不能在外部调用
|
||||
* 得到方法
|
||||
* @return [Method]
|
||||
* @throws IllegalStateException 如果 [name] 未设置
|
||||
* @throws NoSuchMethodError 如果找不到方法
|
||||
*/
|
||||
private val result
|
||||
get() = if (params != null)
|
||||
ReflectionUtils.findMethodBestMatch(hookClass, returnType, name, *params!!)
|
||||
else ReflectionUtils.findMethodNoParam(hookClass, returnType, name)
|
||||
|
||||
/**
|
||||
* 得到方法结果
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun find(): Method =
|
||||
when {
|
||||
name.isBlank() -> error("Method name cannot be empty")
|
||||
else ->
|
||||
if (params != null)
|
||||
ReflectionUtils.findMethodBestMatch(hookClass, returnType, name, *params!!)
|
||||
else ReflectionUtils.findMethodNoParam(hookClass, returnType, name)
|
||||
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}]")
|
||||
}
|
||||
Result()
|
||||
} catch (e: Throwable) {
|
||||
onFailureMsg(throwable = e)
|
||||
Result(isNoSuch = true, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生错误时输出日志
|
||||
* @param msg 消息日志
|
||||
* @param throwable 错误
|
||||
*/
|
||||
private fun onFailureMsg(msg: String = "", throwable: Throwable? = null) =
|
||||
loggerE(msg = "NoSuchMethod happend in [$hookClass] $msg [${hookInstance.tag}]", e = throwable)
|
||||
|
||||
/**
|
||||
* [Method] 重查找实现类
|
||||
*
|
||||
* 可累计失败次数直到查找成功
|
||||
*/
|
||||
inner class RemedyPlan {
|
||||
|
||||
/** 失败尝试次数数组 */
|
||||
private val remedyPlan = HashSet<MethodFinder>()
|
||||
|
||||
/**
|
||||
* 创建需要重新查找的 [Method]
|
||||
*
|
||||
* 你可以添加多个备选方法 - 直到成功为止
|
||||
*
|
||||
* 若最后依然失败 - 将停止查找并输出错误日志
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun method(initiate: MethodFinder.() -> Unit) = remedyPlan.add(MethodFinder(hookInstance, hookClass).apply(initiate))
|
||||
|
||||
/**
|
||||
* 开始重查找
|
||||
* - 此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun build() {
|
||||
if (remedyPlan.isNotEmpty()) run {
|
||||
var isFindSuccess = false
|
||||
var lastError: Throwable? = null
|
||||
remedyPlan.forEachIndexed { p, it ->
|
||||
runCatching {
|
||||
runBlocking {
|
||||
hookInstance.member = it.result
|
||||
}.result {
|
||||
hookInstance.onHookLogMsg(msg = "Find Method [${hookInstance.member}] takes ${it}ms [${hookInstance.tag}]")
|
||||
}
|
||||
isFindSuccess = true
|
||||
hookInstance.onHookLogMsg(msg = "Method [${hookInstance.member}] trying ${p + 1} times success by RemedyPlan [${hookInstance.tag}]")
|
||||
return@run
|
||||
}.onFailure {
|
||||
lastError = it
|
||||
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it")
|
||||
}
|
||||
}
|
||||
if (!isFindSuccess) {
|
||||
onFailureMsg(
|
||||
msg = "trying ${remedyPlan.size} times and all failure by RemedyPlan",
|
||||
throwable = lastError
|
||||
)
|
||||
remedyPlan.clear()
|
||||
}
|
||||
} else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookInstance.tag}]")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Method] 查找结果实现类
|
||||
* @param isNoSuch 是否没有找到方法 - 默认否
|
||||
* @param e 错误信息
|
||||
*/
|
||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||
|
||||
/**
|
||||
* 创建监听结果事件方法体
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun result(initiate: Result.() -> Unit) = apply(initiate)
|
||||
|
||||
/**
|
||||
* 创建方法重查找功能
|
||||
*
|
||||
* 当你遇到一种方法可能存在不同形式的存在时
|
||||
*
|
||||
* 可以使用 [RemedyPlan] 重新查找它 - 而没有必要使用 [onNoSuchMethod] 捕获异常二次查找方法
|
||||
*
|
||||
* 若第一次查找失败了 - 你还可以在这里继续添加此方法体直到成功为止
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun remedys(initiate: RemedyPlan.() -> Unit): Result {
|
||||
if (isNoSuch) RemedyPlan().apply(initiate).build()
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听找不到方法时
|
||||
*
|
||||
* 只会返回第一次的错误信息 - 不会返回 [RemedyPlan] 的错误信息
|
||||
* @param initiate 回调错误
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onNoSuchMethod(initiate: (Throwable) -> Unit): Result {
|
||||
if (isNoSuch) initiate(e ?: Throwable())
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
@@ -75,6 +75,7 @@ abstract class YukiBaseHooker : PackageParam() {
|
||||
/**
|
||||
* 赋值并克隆一个 [PackageParam]
|
||||
* @param packageParam 需要使用的 [PackageParam]
|
||||
* - 此方法为私有功能性 API - 你不应该手动调用此方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun assignInstance(packageParam: PackageParam) {
|
||||
|
@@ -36,13 +36,11 @@ import de.robv.android.xposed.XposedBridge
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - D
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.debugTag]
|
||||
* @param msg 日志打印的内容
|
||||
*/
|
||||
fun loggerD(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
fun loggerD(tag: String = YukiHookAPI.debugTag, msg: String) = runCatching {
|
||||
Log.d(tag, msg)
|
||||
XposedBridge.log("[$tag][D]--> $msg")
|
||||
}
|
||||
@@ -50,13 +48,11 @@ fun loggerD(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - I
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.debugTag]
|
||||
* @param msg 日志打印的内容
|
||||
*/
|
||||
fun loggerI(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
fun loggerI(tag: String = YukiHookAPI.debugTag, msg: String) = runCatching {
|
||||
Log.i(tag, msg)
|
||||
XposedBridge.log("[$tag][I]--> $msg")
|
||||
}
|
||||
@@ -64,13 +60,11 @@ fun loggerI(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - W
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.debugTag]
|
||||
* @param msg 日志打印的内容
|
||||
*/
|
||||
fun loggerW(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
fun loggerW(tag: String = YukiHookAPI.debugTag, msg: String) = runCatching {
|
||||
Log.w(tag, msg)
|
||||
XposedBridge.log("[$tag][W]--> $msg")
|
||||
}
|
||||
@@ -78,14 +72,12 @@ fun loggerW(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - E
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.debugTag]
|
||||
* @param msg 日志打印的内容
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
*/
|
||||
fun loggerE(tag: String = YukiHookAPI.TAG, msg: String, e: Throwable? = null) = runCatching {
|
||||
fun loggerE(tag: String = YukiHookAPI.debugTag, msg: String, e: Throwable? = null) = runCatching {
|
||||
Log.e(tag, msg, e)
|
||||
XposedBridge.log("[$tag][E]--> $msg")
|
||||
e?.also { XposedBridge.log(it) }
|
||||
|
@@ -89,6 +89,7 @@ open class PackageParam(
|
||||
/**
|
||||
* 赋值并克隆另一个 [PackageParam]
|
||||
* @param another 另一个 [PackageParam]
|
||||
* - 此方法为私有功能性 API - 你不应该手动调用此方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun baseAssignInstance(another: PackageParam) {
|
||||
|
@@ -35,7 +35,7 @@ import java.io.Serializable
|
||||
* 获得 [Any] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val AnyType get() = Any::class.java
|
||||
val AnyType get() = Any::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Unit] 类型
|
||||
@@ -47,7 +47,7 @@ val UnitType get() = Unit::class.javaPrimitiveType
|
||||
* 获得 [Boolean] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val BooleanType get() = Boolean::class.javaPrimitiveType
|
||||
val BooleanType get() = Boolean::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Int] 类型
|
||||
|
@@ -107,18 +107,8 @@ public class ReflectionUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Field findField(Class<?> clazz, String typeName, String fieldName) {
|
||||
try {
|
||||
return findFieldIfExists(clazz, typeName, fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new IllegalArgumentException("Can't find field <" + clazz.getName() + "#" + typeName + "#" + fieldName + ">");
|
||||
}
|
||||
}
|
||||
|
||||
public static Field findFieldIfExists(Class<?> clazz, String typeName, String fieldName)
|
||||
throws NoSuchFieldException {
|
||||
String fullFieldName = clazz.getName() + "#" + fieldName + "#" + typeName;
|
||||
|
||||
public static Field findFieldIfExists(Class<?> clazz, String typeName, String fieldName) throws NoSuchFieldException {
|
||||
String fullFieldName = "name:[" + fieldName + "] type:[" + typeName + "] in Class [" + clazz.getName() + "] by YukiHook#finder";
|
||||
if (!fieldCache.containsKey(fullFieldName)) {
|
||||
if (clazz != null && !TextUtils.isEmpty(typeName) && !TextUtils.isEmpty(fieldName)) {
|
||||
Class<?> clz = clazz;
|
||||
@@ -134,7 +124,7 @@ public class ReflectionUtils {
|
||||
}
|
||||
}
|
||||
} while ((clz = clz.getSuperclass()) != null);
|
||||
throw new NoSuchFieldException(clazz.getName() + "#" + typeName + " " + fieldName);
|
||||
throw new NoSuchFieldException("Can't find this field --> " + fullFieldName);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user