From 2c389dd49af8c9b73c421ef57011ede359d2a078 Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Sun, 31 Jul 2022 01:26:04 +0800 Subject: [PATCH] Modify auto matched Class<*> instance in PackageParam and changed some function --- docs/api/public/HookClass.md | 6 +- docs/api/public/PackageParam.md | 63 +++++++++------- docs/api/public/ReflectionFactory.md | 71 ++++++++++--------- docs/guide/special-feature.md | 23 ++++++ .../yukihookapi/hook/bean/HookClass.kt | 6 +- .../hook/factory/ReflectionFactory.kt | 25 +------ .../yukihookapi/hook/param/PackageParam.kt | 62 ++++++++-------- .../hook/xposed/bridge/YukiHookBridge.kt | 2 +- 8 files changed, 143 insertions(+), 115 deletions(-) diff --git a/docs/api/public/HookClass.md b/docs/api/public/HookClass.md index ebc29c09..e245f2d0 100644 --- a/docs/api/public/HookClass.md +++ b/docs/api/public/HookClass.md @@ -1,13 +1,17 @@ ## HookClass [class] ```kotlin -class HookClass internal constructor(var instance: Class<*>?, var name: String, var throwable: Throwable?) +class HookClass internal constructor(internal var instance: Class<*>?, internal var name: String, internal var throwable: Throwable?) ``` **变更记录** `v1.0` `添加` +`v1.0.93` `修改` + +`HookClass` 相关功能不再对外开放 + **功能描述** > 创建一个当前 Hook 的 `Class` 接管类。 diff --git a/docs/api/public/PackageParam.md b/docs/api/public/PackageParam.md index 0303239d..67ee0cc7 100644 --- a/docs/api/public/PackageParam.md +++ b/docs/api/public/PackageParam.md @@ -402,6 +402,8 @@ val VariousClass.clazz: Class<*> > 字符串、`VariousClass` 转换为实体类。 +使用当前 `appClassLoader` 装载目标 `Class`。 + **功能示例** 你可以轻松地将 `String` 类型的 `Class` 包名转为 `Class` 实例。 @@ -459,11 +461,11 @@ if("com.example.demo.DemoClass".hasClass) { ### findClass [method] ```kotlin -fun findClass(name: String): HookClass +fun findClass(name: String, loader: ClassLoader?): HookClass ``` ```kotlin -fun findClass(vararg name: String): VariousClass +fun findClass(vararg name: String, loader: ClassLoader?): VariousClass ``` **变更记录** @@ -474,10 +476,16 @@ fun findClass(vararg name: String): VariousClass 移除了 ~~`findClass(various: VariousClass)`~~ 方法 +`v1.0.93` `修改` + +新增 `loader` 参数 + **功能描述** > 通过完整包名+名称查找需要被 Hook 的 `Class`。 +!> 使用此方法会得到一个 `HookClass` 仅用于 Hook,若想查找 `Class` 请使用 `classOf`、`clazz` 功能。 + **功能示例** 你可以使用三种方式查找你需要 Hook 的目标 `Class`。 @@ -506,22 +514,40 @@ findClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2", "com.exa val variousClass = VariousClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2", "com.example.demo.DemoClass3") ``` +若你当前需要查找的 `Class` 不属于 `appClassLoader`,你可以使用 `loader` 参数指定你要装载的 `ClassLoader`。 + +> 示例如下 + +```kotlin +val outsideLoader: ClassLoader? = ... // 假设这就是你的 ClassLoader +findClass(name = "com.example.demo.OutsideClass", loader = outsideLoader) +``` + +同样地,在不确定多个版本的 `Class` 以及不同名称时,也可以使用 `loader` 参数指定你要装载的 `ClassLoader`。 + +> 示例如下 + +```kotlin +val outsideLoader: ClassLoader? = ... // 假设这就是你的 ClassLoader +findClass("com.example.demo.OutsideClass1", "com.example.demo.OutsideClass2", "com.example.demo.OutsideClass3", loader = outsideLoader) +``` + ### hook [method] ```kotlin -inline fun String.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result +inline fun String.hook(initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result ``` ```kotlin -inline fun Class<*>.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result +inline fun Class<*>.hook(initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result ``` ```kotlin -inline fun VariousClass.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result +inline fun VariousClass.hook(initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result ``` ```kotlin -inline fun HookClass.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result +inline fun HookClass.hook(initiate: YukiMemberHookCreater.() -> Unit): YukiMemberHookCreater.Result ``` **变更记录** @@ -548,6 +574,10 @@ inline fun HookClass.hook(isUseAppClassLoader: Boolean, initiate: YukiMemberHook 将方法体进行 inline +`v1.0.93` `修改` + +移除了 ~~`isUseAppClassLoader`~~ 参数 + **功能描述** > 这是一切 Hook 的入口创建方法,Hook 方法、构造方法。 @@ -578,10 +608,12 @@ findClass(name = "com.example.demo.DemoClass").hook { 使用 `stub` 或直接拿到 `Class` 实例进行创建。 +默认情况下 API 会将 `Class` 实例转换为类名并绑定到 `appClassLoader`,若失败,则会使用原始 `Class` 实例直接进行 Hook。 + > 示例如下 ```kotlin -Activity::class.java.hook { +Stub::class.java.hook { // Your code here. } ``` @@ -606,23 +638,6 @@ findClass("com.example.demo.DemoClass1", "com.example.demo.DemoClass2").hook { } ``` -!> 以下是关于 Hook 目标 Class 的一个特殊情况说明。 - -若你 Hook 的 `Class` 实例的 `ClassLoader` 并不是当前的 `appClassLoader`,那么你需要做一下小的调整。 - -在 `hook` 方法中加入 `isUseAppClassLoader = false`,这样,你的 `Class` 就不会被重新绑定到 `appClassLoader` 了。 - -此方案适用于目标 `Class` 无法在当前 `appClassLoader` 中被得到但可以得到 `Class` 实例的情况。 - -> 示例如下 - -```kotlin -// 这里的做法标识了 hook 不会再将 YourClass 重新与当前 appClassLoader 绑定 -YourClass.hook(isUseAppClassLoader = false) { - // Your code here. -} -``` - ### hook [method] ```kotlin diff --git a/docs/api/public/ReflectionFactory.md b/docs/api/public/ReflectionFactory.md index 7f47f62d..f82d12bf 100644 --- a/docs/api/public/ReflectionFactory.md +++ b/docs/api/public/ReflectionFactory.md @@ -8,61 +8,35 @@ > 这是自定义 `Member` 和 `Class` 相关功能的查找匹配以及 `invoke` 的封装类。 -### hookClass [field] - -```kotlin -val Class<*>.hookClass: HookClass -``` +### ~~hookClass [field]~~ **变更记录** `v1.0` `添加` -**功能描述** +`v1.0.93` `移除` -> 将 `Class` 转换为 `HookClass`。 +`HookClass` 相关功能不再对外开放 -### normalClass [field] - -```kotlin -val HookClass.normalClass: Class<*>? -``` +### ~~normalClass [field]~~ **变更记录** `v1.0` `添加` -**功能描述** +`v1.0.93` `移除` -> 将 `HookClass` 转换为 `Class`。 +`HookClass` 相关功能不再对外开放 -### hasClass [field] - -```kotlin -val String.hasClass: Boolean -``` +### ~~hasClass [field]~~ **变更记录** `v1.0` `添加` -**功能描述** +`v1.0.93` `移除` -> 通过字符串查找类是否存在。 - -**功能示例** - -你可以轻松的使用此方法判断字符串中的类是否存在。 - -!> 此查找仅限使用当前的 `ClassLoader`,若要指定 `ClassLoader` 请使用下方的 `hasClass` 同名方法。 - -> 示例如下 - -```kotlin -if("com.example.demo.DemoClass".hasClass) { - // Your code here. -} -``` +请直接使用 `hasClass()` 无参方法 ### hasExtends [field] @@ -120,10 +94,37 @@ fun String.hasClass(loader: ClassLoader?): Boolean `v1.0` `添加` +`v1.0.93` `修改` + +支持直接使用空参数方法使用默认 `ClassLoader` 进行判断 + **功能描述** > 通过字符串使用指定的 `ClassLoader` 查找类是否存在。 +**功能示例** + +你可以轻松的使用此方法判断字符串中的类是否存在,效果等同于直接使用 `Class.forName`。 + +> 示例如下 + +```kotlin +if("com.example.demo.DemoClass".hasClass()) { + // Your code here. +} +``` + +填入方法中的 `loader` 参数可判断指定的 `ClassLoader` 中的 `Class` 是否存在。 + +> 示例如下 + +```kotlin +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +if("com.example.demo.DemoClass".hasClass(customClassloader)) { + // Your code here. +} +``` + ### hasField [method] ```kotlin diff --git a/docs/guide/special-feature.md b/docs/guide/special-feature.md index 510ba2aa..8a01c837 100644 --- a/docs/guide/special-feature.md +++ b/docs/guide/special-feature.md @@ -682,6 +682,29 @@ VariousClass("com.demo.ATest", "com.demo.BTest").get().method { }.get().call() ``` +若当前 `Class` 在指定的 `ClassLoader` 中存在,你可以在 `get` 中填入你的 `ClassLoader`。 + +> 示例如下 + +```kotlin +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +VariousClass("com.demo.ATest", "com.demo.BTest").get(customClassLoader).method { + name = "doTask" + emptyParam() +}.get().call() +``` + +若你正在 `PackageParam` 中操作 (Xposed) 宿主环境的 `Class`,可以直接使用 `clazz` 进行设置。 + +> 示例如下 + +```kotlin +VariousClass("com.demo.ATest", "com.demo.BTest").clazz.method { + name = "doTask" + emptyParam() +}.get().call() +``` + 更多用法可参考 [VariousClass](api/document?id=variousclass-class)。 若在创建 Hook 的时候使用,可以更加方便,还可以自动拦截找不到 `Class` 的异常。 diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt index 6c602319..bacdf718 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/bean/HookClass.kt @@ -33,7 +33,11 @@ package com.highcapable.yukihookapi.hook.bean * @param name 完整名称 * @param throwable 异常 */ -class HookClass internal constructor(var instance: Class<*>? = null, var name: String, var throwable: Throwable? = null) { +class HookClass internal constructor( + @PublishedApi internal var instance: Class<*>? = null, + @PublishedApi internal var name: String, + @PublishedApi internal var throwable: Throwable? = null +) { override fun toString() = "[class] $name [throwable] $throwable [instance] $instance" } \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt index 3db7c37b..b3f08755 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt @@ -30,7 +30,6 @@ package com.highcapable.yukihookapi.hook.factory import com.highcapable.yukihookapi.hook.bean.CurrentClass -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 @@ -43,26 +42,6 @@ import java.lang.reflect.Field import java.lang.reflect.Member import java.lang.reflect.Method -/** - * [Class] 转换为 [HookClass] - * @return [HookClass] - */ -val Class<*>.hookClass get() = HookClass(instance = this, name) - -/** - * [HookClass] 转换为 [Class] - * @return [Class] or null - */ -val HookClass.normalClass get() = instance - -/** - * 通过字符串查找类是否存在 - * - * - ❗仅限使用当前的 [ClassLoader] - * @return [Boolean] 是否存在 - */ -val String.hasClass get() = hasClass(loader = null) - /** * 当前 [Class] 是否有继承关系 - 父类是 [Any] 将被认为没有继承关系 * @return [Boolean] @@ -94,10 +73,10 @@ fun classOf(name: String, loader: ClassLoader? = null): Class<*> { /** * 通过字符串查找类是否存在 - * @param loader [Class] 所在的 [ClassLoader] + * @param loader [Class] 所在的 [ClassLoader] - 不填使用默认 [ClassLoader] * @return [Boolean] 是否存在 */ -fun String.hasClass(loader: ClassLoader?) = try { +fun String.hasClass(loader: ClassLoader? = null) = try { classOf(name = this, loader) true } catch (_: Throwable) { 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 1a73a9d2..5be06073 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 @@ -45,7 +45,6 @@ import com.highcapable.yukihookapi.hook.core.YukiResourcesHookCreater import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.factory.classOf import com.highcapable.yukihookapi.hook.factory.hasClass -import com.highcapable.yukihookapi.hook.factory.hookClass import com.highcapable.yukihookapi.hook.param.type.HookEntryType import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper import com.highcapable.yukihookapi.hook.utils.value @@ -318,68 +317,76 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: /** * 通过字符串查找类是否存在 * - * - 默认使用当前 [appClassLoader] 装载目标 [Class] + * - 使用当前 [appClassLoader] 装载目标 [Class] * @return [Boolean] 是否存在 */ val String.hasClass get() = hasClass(appClassLoader) /** - * 默认使用当前 [appClassLoader] 查询并装载 [Class] + * 查找并装载 [Class] + * + * - ❗使用此方法会得到一个 [HookClass] 仅用于 Hook - 若想查找 [Class] 请使用 [classOf]、[clazz] 功能 * @param name 类名 + * @param loader 当前 [ClassLoader] - 默认使用 [appClassLoader] - 设为 null 使用默认 [ClassLoader] * @return [HookClass] */ - fun findClass(name: String) = try { - name.clazz.hookClass + fun findClass(name: String, loader: ClassLoader? = appClassLoader) = try { + classOf(name, loader).hookClass } catch (e: Throwable) { HookClass(name = name, throwable = e) } /** - * 默认使用当前 [appClassLoader] 查询并装载 [Class] + * 查找并装载 [Class] * - * 使用此方法查询将会取 [name] 其中命中存在的第一个 [Class] 作为结果 + * 使用此方法查找将会取 [name] 其中命中存在的第一个 [Class] 作为结果 + * + * - ❗使用此方法会得到一个 [HookClass] 仅用于 Hook - 若想查找 [Class] 请使用 [classOf]、[clazz] 功能 * @param name 可填入多个类名 - 自动匹配 - * @return [VariousClass] + * @param loader 当前 [ClassLoader] - 默认使用 [appClassLoader] - 设为 null 使用默认 [ClassLoader] + * @return [HookClass] */ - fun findClass(vararg name: String) = VariousClass(*name) + fun findClass(vararg name: String, loader: ClassLoader? = appClassLoader) = VariousClass(*name).hookClass(loader) /** * Hook 方法、构造方法 * + * - 使用当前 [appClassLoader] 装载目标 [Class] + * * - ❗为防止任何字符串都被当做 [Class] 进行 Hook - 推荐优先使用 [findClass] - * @param isUseAppClassLoader 是否使用 [appClassLoader] 重新绑定当前 [Class] - 默认启用 * @param initiate 方法体 * @return [YukiMemberHookCreater.Result] */ - inline fun String.hook(isUseAppClassLoader: Boolean = true, initiate: YukiMemberHookCreater.() -> Unit) = - findClass(name = this).hook(isUseAppClassLoader, initiate) + inline fun String.hook(initiate: YukiMemberHookCreater.() -> Unit) = findClass(name = this).hook(initiate) /** * Hook 方法、构造方法 - * @param isUseAppClassLoader 是否使用 [appClassLoader] 重新绑定当前 [Class] - 默认启用 + * + * - 自动选择与当前 [Class] 相匹配的 [ClassLoader] - 优先使用 [appClassLoader] * @param initiate 方法体 * @return [YukiMemberHookCreater.Result] */ - inline fun Class<*>.hook(isUseAppClassLoader: Boolean = true, initiate: YukiMemberHookCreater.() -> Unit) = - hookClass.hook(isUseAppClassLoader, initiate) + inline fun Class<*>.hook(initiate: YukiMemberHookCreater.() -> Unit) = when { + name.hasClass(appClassLoader) -> findClass(name) + else -> hookClass + }.hook(initiate) /** * Hook 方法、构造方法 - * @param isUseAppClassLoader 是否使用 [appClassLoader] 重新绑定当前 [Class] - 默认启用 + * + * - 使用当前 [appClassLoader] 装载目标 [Class] * @param initiate 方法体 * @return [YukiMemberHookCreater.Result] */ - inline fun VariousClass.hook(isUseAppClassLoader: Boolean = true, initiate: YukiMemberHookCreater.() -> Unit) = - hookClass(if (isUseAppClassLoader) appClassLoader else null).hook(isUseAppClassLoader, initiate) + inline fun VariousClass.hook(initiate: YukiMemberHookCreater.() -> Unit) = hookClass(appClassLoader).hook(initiate) /** * Hook 方法、构造方法 - * @param isUseAppClassLoader 是否使用 [appClassLoader] 重新绑定当前 [Class] - 默认启用 * @param initiate 方法体 * @return [YukiMemberHookCreater.Result] */ - inline fun HookClass.hook(isUseAppClassLoader: Boolean = true, initiate: YukiMemberHookCreater.() -> Unit) = - YukiMemberHookCreater(packageParam = this@PackageParam, hookClass = if (isUseAppClassLoader) bind() else this).apply(initiate).hook() + inline fun HookClass.hook(initiate: YukiMemberHookCreater.() -> Unit) = + YukiMemberHookCreater(packageParam = this@PackageParam, hookClass = this).apply(initiate).hook() /** * Hook APP 的 Resources @@ -391,7 +398,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: YukiResourcesHookCreater(packageParam = this@PackageParam, hookResources = this).apply(initiate).hook() /** - * [VariousClass] 转换为 [HookClass] 并绑定到 [appClassLoader] + * [VariousClass] 转换为 [HookClass] * @param loader 当前 [ClassLoader] - 若留空使用默认 [ClassLoader] * @return [HookClass] */ @@ -403,17 +410,12 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: } /** - * 将目标 [Class] 绑定到 [appClassLoader] - * - * - ❗请注意未绑定到 [appClassLoader] 的 [Class] 是不安全的 - 调用 [hook] 方法会根据设定自动绑定 + * [Class] 转换为 [HookClass] * @return [HookClass] */ @PublishedApi - internal fun HookClass.bind() = try { - name.clazz.hookClass - } catch (e: Throwable) { - HookClass(name = name, throwable = throwable ?: e) - } + internal val Class<*>.hookClass + get() = HookClass(instance = this, name) /** * 当前 Hook APP 的生命周期实例处理类 diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt index 651ccd99..d90688e8 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt @@ -180,7 +180,7 @@ object YukiHookBridge { * @return [Boolean] 是否存在 */ private fun isMiuiCatcherPatch(packageName: String?) = - (packageName == "com.miui.contentcatcher" || packageName == "com.miui.catcherpatch") && ("android.miui.R").hasClass + (packageName == "com.miui.contentcatcher" || packageName == "com.miui.catcherpatch") && ("android.miui.R").hasClass() /** * 当前包名是否已在指定的 [HookEntryType] 被装载