From 3746c445a2f252a233a88240b1a511cd5b0efb43 Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Tue, 2 Aug 2022 01:40:28 +0800 Subject: [PATCH] Added ClassLoader.fetching function in PackageParam --- docs/api/public/PackageParam.md | 63 +++++++++++++++++++ .../yukihookapi/hook/param/PackageParam.kt | 28 +++++++++ 2 files changed, 91 insertions(+) diff --git a/docs/api/public/PackageParam.md b/docs/api/public/PackageParam.md index d0918ba4..975c062c 100644 --- a/docs/api/public/PackageParam.md +++ b/docs/api/public/PackageParam.md @@ -548,6 +548,69 @@ val outsideLoader: ClassLoader? = ... // 假设这就是你的 ClassLoader findClass("com.example.demo.OutsideClass1", "com.example.demo.OutsideClass2", "com.example.demo.OutsideClass3", loader = outsideLoader) ``` +### fetching [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 { + // ... + } + } +} +``` + ### hook [method] ```kotlin 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 8fa13cf0..95f48733 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,12 +45,19 @@ 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.log.yLoggerW import com.highcapable.yukihookapi.hook.param.type.HookEntryType +import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper +import com.highcapable.yukihookapi.hook.type.java.BooleanType +import com.highcapable.yukihookapi.hook.type.java.JavaClassLoader +import com.highcapable.yukihookapi.hook.type.java.StringType import com.highcapable.yukihookapi.hook.utils.value import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiModuleResources import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources +import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper +import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberHook import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs @@ -356,6 +363,27 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: */ fun findClass(vararg name: String, loader: ClassLoader? = appClassLoader) = VariousClass(*name).hookClass(loader) + /** + * 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法 + * + * - ❗请注意只有当前 [ClassLoader] 有主动使用 [ClassLoader.loadClass] 事件时才能被捕获 + * + * - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误 + * @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve) + */ + fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit) { + runCatching { + YukiHookHelper.hookMethod( + YukiHookHelper.findMethod(JavaClassLoader, name = "loadClass", StringType, BooleanType), + object : YukiMemberHook() { + override fun afterHookedMember(wrapper: HookParamWrapper) { + if (wrapper.instance?.javaClass?.name == this@fetching.javaClass.name) + (wrapper.result as? Class<*>?)?.also { result(it, wrapper.args?.get(1) as? Boolean ?: false) } + } + }) + }.onFailure { yLoggerW(msg = "Try to hook ClassLoader failed: $it") } + } + /** * Hook 方法、构造方法 *