diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt index 4293e6a2..c3384254 100644 --- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt @@ -168,11 +168,10 @@ object CodeSourceFileTemplate { " private const val modulePackageName = " + (if (customMPackageName.isNotBlank()) "\"$customMPackageName\"" else "BuildConfig.APPLICATION_ID") + "\n" + "\n" + - " private val hookEntry = $entryClassName()\n" + - "\n" + - " private var moduleClassLoader: ClassLoader? = null\n" + " private var isZygoteBinded = false\n" + "\n" + + " private val hookEntry = $entryClassName()\n" + + "\n" + " private fun callXposedLoaded(\n" + " isZygoteLoaded: Boolean = false,\n" + " lpparam: XC_LoadPackage.LoadPackageParam? = null,\n" + @@ -192,11 +191,6 @@ object CodeSourceFileTemplate { " YukiHookBridge.callXposedLoaded(isZygoteLoaded, lpparam, resparam)\n" + " }\n" + "\n" + - " private fun hookModuleAppStatus(loader: ClassLoader? = null, isHookResourcesStatus: Boolean = false) {\n" + - " loader?.let { moduleClassLoader = it }\n" + - " runCatching { YukiHookBridge.hookModuleAppStatus(moduleClassLoader, isHookResourcesStatus) }\n" + - " }\n" + - "\n" + " @YukiGenerateApi\n" + " fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" + " if (sparam == null) return\n" + @@ -209,16 +203,12 @@ object CodeSourceFileTemplate { "\n" + " @YukiGenerateApi\n" + " fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + - " if (lpparam == null) return\n" + - " if (lpparam.packageName == modulePackageName) hookModuleAppStatus(lpparam.classLoader)\n" + - " callXposedLoaded(lpparam = lpparam)\n" + + " if (lpparam != null) callXposedLoaded(lpparam = lpparam)\n" + " }\n" + "\n" + " @YukiGenerateApi\n" + " fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + - " if (resparam == null) return\n" + - " if (resparam.packageName == modulePackageName) hookModuleAppStatus(isHookResourcesStatus = true)\n" + - " callXposedLoaded(resparam = resparam)\n" + + " if (resparam != null) callXposedLoaded(resparam = resparam)\n" + " }\n" + "}").toByteArray() } \ No newline at end of file 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 cfbc4b22..9c4a7972 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 @@ -48,6 +48,7 @@ import com.highcapable.yukihookapi.hook.factory.hasClass import com.highcapable.yukihookapi.hook.param.type.HookEntryType import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper 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.channel.YukiHookDataChannel @@ -244,13 +245,13 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: * 装载并 Hook 系统框架 * @param initiate 方法体 */ - inline fun loadSystem(initiate: PackageParam.() -> Unit) = loadApp(AppParasitics.SYSTEM_FRAMEWORK_NAME, initiate) + inline fun loadSystem(initiate: PackageParam.() -> Unit) = loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, initiate) /** * 装载并 Hook 系统框架 * @param hooker Hook 子类 */ - fun loadSystem(hooker: YukiBaseHooker) = loadApp(AppParasitics.SYSTEM_FRAMEWORK_NAME, hooker) + fun loadSystem(hooker: YukiBaseHooker) = loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, hooker) /** * 装载 APP Zygote 事件 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 69d075d8..9d0c7c7b 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 @@ -35,18 +35,11 @@ import com.highcapable.yukihookapi.annotation.YukiGenerateApi import com.highcapable.yukihookapi.hook.factory.classOf import com.highcapable.yukihookapi.hook.factory.field import com.highcapable.yukihookapi.hook.factory.hasClass -import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.param.PackageParam 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.android.ContextImplClass 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.bridge.factory.YukiMemberReplacement import com.highcapable.yukihookapi.hook.xposed.bridge.inject.YukiHookBridge_Injector -import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics import dalvik.system.PathClassLoader @@ -67,6 +60,10 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage @YukiGenerateApi object YukiHookBridge { + /** Android 系统框架名称 */ + @PublishedApi + internal const val SYSTEM_FRAMEWORK_NAME = "android" + /** Xposed 是否装载完成 */ private var isXposedInitialized = false @@ -186,12 +183,12 @@ object YukiHookBridge { if (type == HookEntryType.ZYGOTE || appClassLoader != null) PackageParamWrapper( type = type, - packageName = packageName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME, - processName = processName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME, + packageName = packageName ?: SYSTEM_FRAMEWORK_NAME, + processName = processName ?: SYSTEM_FRAMEWORK_NAME, appClassLoader = appClassLoader ?: XposedBridge.BOOTCLASSLOADER, appInfo = appInfo, appResources = appResources - ).also { packageParamWrappers[packageName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME] = it } + ).also { packageParamWrappers[packageName ?: SYSTEM_FRAMEWORK_NAME] = it } else null else packageParamWrappers[packageName]?.also { it.type = type @@ -203,39 +200,6 @@ object YukiHookBridge { } } - /** - * Hook 模块自身激活状态和 Resources Hook 支持状态 - * - * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件 - * @param loader 模块的 [ClassLoader] - * @param isHookResourcesStatus 是否 Hook Resources 支持状态 - */ - @YukiGenerateApi - fun hookModuleAppStatus(loader: ClassLoader?, isHookResourcesStatus: Boolean = false) { - if (YukiHookAPI.Configs.isEnableHookSharedPreferences) - YukiHookHelper.hook(ContextImplClass.method { name = "setFilePermissionsFromMode" }, object : YukiMemberHook() { - override fun beforeHookedMember(wrapper: HookParamWrapper) { - if ((wrapper.args?.get(0) as? String?)?.endsWith(suffix = "preferences.xml") == true) wrapper.args?.set(1, 1) - } - }) - if (YukiHookAPI.Configs.isEnableHookModuleStatus) classOf(loader).apply { - if (isHookResourcesStatus.not()) { - YukiHookHelper.hook(method { name = YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME }, object : YukiMemberReplacement() { - override fun replaceHookedMember(wrapper: HookParamWrapper) = true - }) - YukiHookHelper.hook(method { name = YukiHookModuleStatus.GET_XPOSED_TAG_METHOD_NAME }, object : YukiMemberReplacement() { - override fun replaceHookedMember(wrapper: HookParamWrapper) = executorName - }) - YukiHookHelper.hook(method { name = YukiHookModuleStatus.GET_XPOSED_VERSION_METHOD_NAME }, object : YukiMemberReplacement() { - override fun replaceHookedMember(wrapper: HookParamWrapper) = executorVersion - }) - } else - YukiHookHelper.hook(method { name = YukiHookModuleStatus.HAS_RESOURCES_HOOK_METHOD_NAME }, object : YukiMemberReplacement() { - override fun replaceHookedMember(wrapper: HookParamWrapper) = true - }) - } - } - /** * 标识 Xposed API 装载完成 * @@ -281,7 +245,7 @@ object YukiHookBridge { resparam: XC_InitPackageResources.InitPackageResourcesParam? = null ) { if (isMiuiCatcherPatch(packageName = lpparam?.packageName ?: resparam?.packageName).not()) when { - isZygoteLoaded -> assignWrapper(HookEntryType.ZYGOTE, AppParasitics.SYSTEM_FRAMEWORK_NAME, AppParasitics.SYSTEM_FRAMEWORK_NAME) + isZygoteLoaded -> assignWrapper(HookEntryType.ZYGOTE, SYSTEM_FRAMEWORK_NAME, SYSTEM_FRAMEWORK_NAME) lpparam != null -> if (isPackageLoaded(lpparam.packageName, HookEntryType.PACKAGE).not()) assignWrapper(HookEntryType.PACKAGE, lpparam.packageName, lpparam.processName, lpparam.classLoader, lpparam.appInfo) @@ -293,8 +257,9 @@ object YukiHookBridge { else -> null }?.also { YukiHookAPI.onXposedLoaded(it) + if (it.type != HookEntryType.ZYGOTE && it.packageName == modulePackageName) + AppParasitics.hookModuleAppRelated(it.appClassLoader, it.type) if (it.type == HookEntryType.PACKAGE) AppParasitics.registerToAppLifecycle(it.packageName) - if (it.type == HookEntryType.RESOURCES) isSupportResourcesHook = true } } } \ No newline at end of file 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 1b078433..d85aaa4d 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 @@ -34,10 +34,7 @@ import android.app.Activity import android.app.ActivityManager import android.app.Application import android.app.Instrumentation -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter +import android.content.* import android.content.pm.PackageManager import android.content.res.Configuration import android.content.res.Resources @@ -46,6 +43,7 @@ import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.hook.factory.* import com.highcapable.yukihookapi.hook.log.yLoggerE 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.type.android.* import com.highcapable.yukihookapi.hook.type.java.BooleanType @@ -56,6 +54,8 @@ import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiModuleResources import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberHook +import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiMemberReplacement +import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.config.ActivityProxyConfig import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate.HandlerDelegate @@ -67,13 +67,8 @@ import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.delegate.Instr * * 通过这些功能即可轻松实现对 (Xposed) 宿主环境的 [Resources] 注入以及 [Activity] 代理 */ -@PublishedApi internal object AppParasitics { - /** Android 系统框架名称 */ - @PublishedApi - internal const val SYSTEM_FRAMEWORK_NAME = "android" - /** [YukiHookDataChannel] 是否已经注册 */ private var isDataChannelRegister = false @@ -134,6 +129,38 @@ internal object AppParasitics { param(IntType) }.ignored().get().int(systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid) + /** + * Hook 模块 APP 相关功能 - 包括自身激活状态、Resources Hook 支持状态以及 [SharedPreferences] + * + * - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件 + * @param loader 模块的 [ClassLoader] + * @param type 当前正在进行的 Hook 类型 + */ + internal fun hookModuleAppRelated(loader: ClassLoader?, type: HookEntryType) { + if (YukiHookAPI.Configs.isEnableHookSharedPreferences && type == HookEntryType.PACKAGE) + YukiHookHelper.hook(ContextImplClass.method { name = "setFilePermissionsFromMode" }, object : YukiMemberHook() { + override fun beforeHookedMember(wrapper: HookParamWrapper) { + if ((wrapper.args?.get(0) as? String?)?.endsWith(suffix = "preferences.xml") == true) wrapper.args?.set(1, 1) + } + }) + if (YukiHookAPI.Configs.isEnableHookModuleStatus) classOf(loader).apply { + if (type != HookEntryType.RESOURCES) { + YukiHookHelper.hook(method { name = YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME }, object : YukiMemberReplacement() { + override fun replaceHookedMember(wrapper: HookParamWrapper) = true + }) + YukiHookHelper.hook(method { name = YukiHookModuleStatus.GET_XPOSED_TAG_METHOD_NAME }, object : YukiMemberReplacement() { + override fun replaceHookedMember(wrapper: HookParamWrapper) = YukiHookBridge.executorName + }) + YukiHookHelper.hook(method { name = YukiHookModuleStatus.GET_XPOSED_VERSION_METHOD_NAME }, object : YukiMemberReplacement() { + override fun replaceHookedMember(wrapper: HookParamWrapper) = YukiHookBridge.executorVersion + }) + } else + YukiHookHelper.hook(method { name = YukiHookModuleStatus.HAS_RESOURCES_HOOK_METHOD_NAME }, object : YukiMemberReplacement() { + override fun replaceHookedMember(wrapper: HookParamWrapper) = true + }) + } + } + /** * 注入当前 Hook APP (宿主) 全局生命周期 * @param packageName 包名