diff --git a/docs/api/public/PackageParam.md b/docs/api/public/PackageParam.md index b9b8cbf9..326e402f 100644 --- a/docs/api/public/PackageParam.md +++ b/docs/api/public/PackageParam.md @@ -619,69 +619,6 @@ val outsideLoader: ClassLoader? = ... // 假设这就是你的 ClassLoader findClass("com.example.demo.OutsideClass1", "com.example.demo.OutsideClass2", "com.example.demo.OutsideClass3", loader = outsideLoader) ``` -### ClassLoader.fetching *- i-ext-method* - -```kotlin -fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit) -``` - -**变更记录** - -`v1.0.93` `新增` - -**功能描述** - -> 监听并 Hook 当前 `ClassLoader` 的 `ClassLoader.loadClass` 方法。 - -!> 请注意只有当前 `ClassLoader` 有主动使用 `ClassLoader.loadClass` 事件时才能被捕获。 - -!> 这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。 - -**功能示例** - -针对一些使用特定 `ClassLoader` 装载 `Class` 的宿主应用,你可以使用此方法来监听 `Class` 加载情况。 - -!> 为了防止发生问题,你需要**得到一个存在的 `ClassLoader` 实例**来使用此功能。 - -比如我们使用 `appClassLoader`。 - -> 示例如下 - -```kotlin -appClassLoader.fetching { clazz, resolve -> - // 得到 clazz 即加载对象 - clazz... // 这里进行你需要的操作 - // resolve 为 loadClass 的第二位参数,可参考官方文档的说明,一般情况下用不到 - resolve // 类型为 Boolean -} -``` - -或使用你得到的存在的 `ClassLoader` 实例,可以通过 Hook 获取。 - -> 示例如下 - -```kotlin -val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader -customClassLoader?.fetching { clazz, resolve -> - // ... -} -``` - -在判断到这个 `Class` 被装载成功时,开始执行你的 Hook 功能。 - -> 示例如下 - -```kotlin -val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader -customClassLoader?.fetching { clazz, resolve -> - if(clazz.name == /** 你需要的 Class 名称 */) { - clazz.hook { - // ... - } - } -} -``` - ### String+Class+VariousClass+HookClass.hook *- i-ext-method* ```kotlin diff --git a/docs/api/public/ReflectionFactory.md b/docs/api/public/ReflectionFactory.md index 892eca56..8ff09c55 100644 --- a/docs/api/public/ReflectionFactory.md +++ b/docs/api/public/ReflectionFactory.md @@ -64,6 +64,69 @@ CONSTRUCTOR > 全部 `Constructor`。 +### ClassLoader.onLoadClass *- ext-method* + +```kotlin +fun ClassLoader.onLoadClass(result: (Class<*>) -> Unit) +``` + +**变更记录** + +`v1.0.93` `新增` + +**功能描述** + +> 监听当前 `ClassLoader` 的 `ClassLoader.loadClass` 方法装载。 + +!> 请注意只有当前 `ClassLoader` 有主动使用 `ClassLoader.loadClass` 事件时才能被捕获。 + +!> 这是一个实验性功能,一般情况下不会用到此方法,不保证不会发生错误。 + +!> 只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。 + +**功能示例** + +针对一些使用特定 `ClassLoader` 装载 `Class` 的宿主应用,你可以使用此方法来监听 `Class` 加载情况。 + +!> 为了防止发生问题,你需要**得到一个存在的 `ClassLoader` 实例**来使用此功能。 + +比如我们在 `PackageParam` 中使用 `appClassLoader`。 + +> 示例如下 + +```kotlin +appClassLoader.onLoadClass { clazz -> + // 得到 clazz 即加载对象 + clazz... // 这里进行你需要的操作 +} +``` + +或使用你得到的存在的 `ClassLoader` 实例,可以通过 Hook 获取。 + +> 示例如下 + +```kotlin +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +customClassLoader?.onLoadClass { clazz -> + // ... +} +``` + +在判断到这个 `Class` 被装载成功时,开始执行你的 Hook 功能。 + +> 示例如下 + +```kotlin +val customClassLoader: ClassLoader? = ... // 假设这个就是你的 ClassLoader +customClassLoader?.onLoadClass { clazz -> + if(clazz.name == /** 你需要的 Class 名称 */) { + clazz.hook { + // ... + } + } +} +``` + ### ~~hookClass *- field*~~ **变更记录** diff --git a/docs/api/public/YukiMemberHookCreator.md b/docs/api/public/YukiMemberHookCreator.md index 95ebe44b..d2dd89ef 100644 --- a/docs/api/public/YukiMemberHookCreator.md +++ b/docs/api/public/YukiMemberHookCreator.md @@ -152,7 +152,7 @@ fun useDangerousOperation(option: String) 你还需要在整个作用域中声明注解 `CauseProblemsApi` 以消除警告。 -若你只需要 Hook `ClassLoader` 的 `loadClass` 方法,请参考 [ClassLoader.fetching](api/document?id=classloaderfetching-i-ext-method)。 +若你只需要 Hook `ClassLoader` 的 `loadClass` 方法,请参考 [ClassLoader.onLoadClass](api/document?id=classloaderonloadclass-ext-method)。 !> 若你不知道允许此功能会带来何种后果,请勿使用。 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 d0552ea4..b9fdc60b 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 @@ -37,6 +37,7 @@ import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus +import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics import java.lang.reflect.Constructor import java.lang.reflect.Field import java.lang.reflect.Member @@ -65,6 +66,18 @@ enum class MembersType { CONSTRUCTOR } +/** + * 监听当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法装载 + * + * - ❗请注意只有当前 [ClassLoader] 有主动使用 [ClassLoader.loadClass] 事件时才能被捕获 + * + * - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误 + * + * - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息 + * @param result 回调 - ([Class] 实例对象) + */ +fun ClassLoader.onLoadClass(result: (Class<*>) -> Unit) = AppParasitics.hookClassLoader(loader = this, result) + /** * 当前 [Class] 是否有继承关系 - 父类是 [Any] 将被认为没有继承关系 * @return [Boolean] 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 2948691f..8294f301 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 @@ -378,16 +378,6 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: */ fun findClass(vararg name: String, loader: ClassLoader? = appClassLoader) = VariousClass(*name).toHookClass(loader) - /** - * 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法 - * - * - ❗请注意只有当前 [ClassLoader] 有主动使用 [ClassLoader.loadClass] 事件时才能被捕获 - * - * - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误 - * @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve) - */ - fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit) = AppParasitics.hookClassLoader(loader = this, result) - /** * Hook 方法、构造方法 * diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt index 6efc0d6c..5e8b8723 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt @@ -71,6 +71,12 @@ internal object AppParasitics { /** [Activity] 代理是否已经注册 */ private var isActivityProxyRegister = false + /** [ClassLoader] 是否已被 Hook */ + private var isClassLoaderHooked = false + + /** [ClassLoader] 监听回调数组 */ + private var classLoaderCallbacks = HashMap) -> Unit>() + /** * 当前 Hook APP (宿主) 的全局生命周期 [Application] * @@ -234,16 +240,22 @@ internal object AppParasitics { /** * 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法 * @param loader 当前 [ClassLoader] - * @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve) + * @param result 回调 - ([Class] 实例对象) */ - internal fun hookClassLoader(loader: ClassLoader?, result: (clazz: Class<*>, resolve: Boolean) -> Unit) { + internal fun hookClassLoader(loader: ClassLoader?, result: (Class<*>) -> Unit) { + if (loader == null) return + if (YukiHookBridge.hasXposedBridge.not()) return yLoggerW(msg = "You can only use hook ClassLoader method in Xposed Environment") + classLoaderCallbacks[loader.hashCode()] = result + if (isClassLoaderHooked) return runCatching { YukiHookHelper.hook(JavaClassLoader.method { name = "loadClass"; param(StringType, BooleanType) }, object : YukiMemberHook() { override fun afterHookedMember(param: Param) { - if (param.instance?.javaClass?.name == loader?.javaClass?.name) - (param.result as? Class<*>?)?.also { result(it, param.args?.get(1) as? Boolean ?: false) } + param.instance?.also { loader -> + (param.result as? Class<*>?)?.also { classLoaderCallbacks[loader.hashCode()]?.invoke(it) } + } } }) + isClassLoaderHooked = true }.onFailure { yLoggerW(msg = "Try to hook ClassLoader failed: $it") } }