Moved YukiHookBridge some apps and host function into AppParasitics

This commit is contained in:
2022-08-14 23:57:40 +08:00
parent 8683045790
commit cf614eee15
5 changed files with 320 additions and 269 deletions

View File

@@ -39,8 +39,8 @@ import android.widget.ImageView
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.param.PackageParam import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
import java.io.BufferedReader import java.io.BufferedReader
@@ -124,7 +124,7 @@ fun Context.injectModuleAppResources() = resources?.injectModuleAppResources()
* *
* - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息 * - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息
*/ */
fun Resources.injectModuleAppResources() = YukiHookBridge.injectModuleAppResources(hostResources = this) fun Resources.injectModuleAppResources() = AppParasitics.injectModuleAppResources(hostResources = this)
/** /**
* 仅判断模块是否在太极、无极中激活 * 仅判断模块是否在太极、无极中激活

View File

@@ -32,6 +32,7 @@ package com.highcapable.yukihookapi.hook.log
import android.util.Log import android.util.Log
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
/** /**
@@ -91,7 +92,7 @@ private fun baseLogger(format: String, type: LoggerType, tag: String, msg: Strin
/** 打印到 [XposedBridge.log] */ /** 打印到 [XposedBridge.log] */
fun loggerInXposed() = runCatching { fun loggerInXposed() = runCatching {
YukiHookBridge.hostProcessName.also { YukiHookBridge.hostProcessName.also {
val appUserId = YukiHookBridge.findUserId(it) val appUserId = AppParasitics.findUserId(it)
XposedBridge.log("[$tag][$format]${if (isShowProcessName) (if (appUserId != 0) "[$it][$appUserId]" else "[$it]") else ""}--> $msg") XposedBridge.log("[$tag][$format]${if (isShowProcessName) (if (appUserId != 0) "[$it][$appUserId]" else "[$it]") else ""}--> $msg")
e?.also { e -> XposedBridge.log(e) } e?.also { e -> XposedBridge.log(e) }
} }

View File

@@ -48,11 +48,11 @@ import com.highcapable.yukihookapi.hook.factory.hasClass
import com.highcapable.yukihookapi.hook.param.type.HookEntryType import com.highcapable.yukihookapi.hook.param.type.HookEntryType
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
import com.highcapable.yukihookapi.hook.utils.value 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.YukiModuleResources
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
/** /**
@@ -82,7 +82,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* 机主为 0 - 应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同 * 机主为 0 - 应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同
* @return [Int] * @return [Int]
*/ */
val appUserId get() = YukiHookBridge.findUserId(packageName) val appUserId get() = AppParasitics.findUserId(packageName)
/** /**
* 获取当前 Hook APP 的 [Application] 实例 * 获取当前 Hook APP 的 [Application] 实例
@@ -91,7 +91,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @return [Application] * @return [Application]
* @throws IllegalStateException 如果 [Application] 是空的 * @throws IllegalStateException 如果 [Application] 是空的
*/ */
val appContext get() = YukiHookBridge.hostApplication ?: YukiHookAppHelper.currentApplication() ?: error("PackageParam got null appContext") val appContext get() = AppParasitics.hostApplication ?: YukiHookAppHelper.currentApplication() ?: error("PackageParam got null appContext")
/** /**
* 获取当前 Hook APP 的 Resources * 获取当前 Hook APP 的 Resources
@@ -107,7 +107,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @return [Context] ContextImpl 实例对象 * @return [Context] ContextImpl 实例对象
* @throws IllegalStateException 如果获取不到系统框架的 [Context] * @throws IllegalStateException 如果获取不到系统框架的 [Context]
*/ */
val systemContext get() = YukiHookBridge.systemContext val systemContext get() = AppParasitics.systemContext
/** /**
* 获取当前 Hook APP 的进程名称 * 获取当前 Hook APP 的进程名称
@@ -143,7 +143,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* - ❗作为 Hook API 装载时无法使用 - 会获取到空字符串 * - ❗作为 Hook API 装载时无法使用 - 会获取到空字符串
* @return [String] * @return [String]
*/ */
val moduleAppFilePath get() = YukiHookBridge.moduleAppFilePath val moduleAppFilePath get() = AppParasitics.moduleAppFilePath
/** /**
* 获取当前 Xposed 模块自身 [Resources] * 获取当前 Xposed 模块自身 [Resources]
@@ -153,8 +153,8 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @throws IllegalStateException 如果当前 Hook Framework 不支持此功能 * @throws IllegalStateException 如果当前 Hook Framework 不支持此功能
*/ */
val moduleAppResources val moduleAppResources
get() = (if (YukiHookAPI.Configs.isEnableModuleAppResourcesCache) YukiHookBridge.moduleAppResources get() = (if (YukiHookAPI.Configs.isEnableModuleAppResourcesCache) AppParasitics.moduleAppResources
else YukiHookBridge.dynamicModuleAppResources) ?: error("Current Hook Framework not support moduleAppResources") else AppParasitics.dynamicModuleAppResources) ?: error("Current Hook Framework not support moduleAppResources")
/** /**
* 获得当前使用的存取数据对象缓存实例 * 获得当前使用的存取数据对象缓存实例
@@ -202,7 +202,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
fun resources() = HookResources(wrapper?.appResources) fun resources() = HookResources(wrapper?.appResources)
/** 刷新当前 Xposed 模块自身 [Resources] */ /** 刷新当前 Xposed 模块自身 [Resources] */
fun refreshModuleAppResources() = YukiHookBridge.refreshModuleAppResources() fun refreshModuleAppResources() = AppParasitics.refreshModuleAppResources()
/** /**
* 监听当前 Hook APP 生命周期装载事件 * 监听当前 Hook APP 生命周期装载事件
@@ -244,13 +244,13 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* 装载并 Hook 系统框架 * 装载并 Hook 系统框架
* @param initiate 方法体 * @param initiate 方法体
*/ */
inline fun loadSystem(initiate: PackageParam.() -> Unit) = loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, initiate) inline fun loadSystem(initiate: PackageParam.() -> Unit) = loadApp(AppParasitics.SYSTEM_FRAMEWORK_NAME, initiate)
/** /**
* 装载并 Hook 系统框架 * 装载并 Hook 系统框架
* @param hooker Hook 子类 * @param hooker Hook 子类
*/ */
fun loadSystem(hooker: YukiBaseHooker) = loadApp(YukiHookBridge.SYSTEM_FRAMEWORK_NAME, hooker) fun loadSystem(hooker: YukiBaseHooker) = loadApp(AppParasitics.SYSTEM_FRAMEWORK_NAME, hooker)
/** /**
* 装载 APP Zygote 事件 * 装载 APP Zygote 事件
@@ -356,7 +356,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误 * - ❗这是一个实验性功能 - 一般情况下不会用到此方法 - 不保证不会发生错误
* @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve) * @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve)
*/ */
fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit) = YukiHookBridge.hookClassLoader(loader = this, result) fun ClassLoader.fetching(result: (clazz: Class<*>, resolve: Boolean) -> Unit) = AppParasitics.hookClassLoader(loader = this, result)
/** /**
* Hook 方法、构造方法 * Hook 方法、构造方法
@@ -439,7 +439,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param result 回调 - ([Context] baseContext,[Boolean] 是否已执行 super) * @param result 回调 - ([Context] baseContext,[Boolean] 是否已执行 super)
*/ */
fun attachBaseContext(result: (baseContext: Context, hasCalledSuper: Boolean) -> Unit) { fun attachBaseContext(result: (baseContext: Context, hasCalledSuper: Boolean) -> Unit) {
YukiHookBridge.AppLifecycleCallback.attachBaseContextCallback = result AppParasitics.AppLifecycleCallback.attachBaseContextCallback = result
} }
/** /**
@@ -447,7 +447,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param initiate 方法体 * @param initiate 方法体
*/ */
fun onCreate(initiate: Application.() -> Unit) { fun onCreate(initiate: Application.() -> Unit) {
YukiHookBridge.AppLifecycleCallback.onCreateCallback = initiate AppParasitics.AppLifecycleCallback.onCreateCallback = initiate
} }
/** /**
@@ -455,7 +455,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param initiate 方法体 * @param initiate 方法体
*/ */
fun onTerminate(initiate: Application.() -> Unit) { fun onTerminate(initiate: Application.() -> Unit) {
YukiHookBridge.AppLifecycleCallback.onTerminateCallback = initiate AppParasitics.AppLifecycleCallback.onTerminateCallback = initiate
} }
/** /**
@@ -463,7 +463,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param initiate 方法体 * @param initiate 方法体
*/ */
fun onLowMemory(initiate: Application.() -> Unit) { fun onLowMemory(initiate: Application.() -> Unit) {
YukiHookBridge.AppLifecycleCallback.onLowMemoryCallback = initiate AppParasitics.AppLifecycleCallback.onLowMemoryCallback = initiate
} }
/** /**
@@ -471,7 +471,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param result 回调 - ([Application] 当前实例,[Int] 类型) * @param result 回调 - ([Application] 当前实例,[Int] 类型)
*/ */
fun onTrimMemory(result: (self: Application, level: Int) -> Unit) { fun onTrimMemory(result: (self: Application, level: Int) -> Unit) {
YukiHookBridge.AppLifecycleCallback.onTrimMemoryCallback = result AppParasitics.AppLifecycleCallback.onTrimMemoryCallback = result
} }
/** /**
@@ -479,7 +479,7 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param result 回调 - ([Application] 当前实例,[Configuration] 配置实例) * @param result 回调 - ([Application] 当前实例,[Configuration] 配置实例)
*/ */
fun onConfigurationChanged(result: (self: Application, config: Configuration) -> Unit) { fun onConfigurationChanged(result: (self: Application, config: Configuration) -> Unit) {
YukiHookBridge.AppLifecycleCallback.onConfigurationChangedCallback = result AppParasitics.AppLifecycleCallback.onConfigurationChangedCallback = result
} }
/** /**
@@ -488,13 +488,13 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* @param result 回调 - ([Context] 当前上下文,[Intent] 当前 Intent) * @param result 回调 - ([Context] 当前上下文,[Intent] 当前 Intent)
*/ */
fun registerReceiver(vararg action: String, result: (context: Context, intent: Intent) -> Unit) { fun registerReceiver(vararg action: String, result: (context: Context, intent: Intent) -> Unit) {
if (action.isNotEmpty()) YukiHookBridge.AppLifecycleCallback.onReceiversCallback[action.value()] = Pair(action, result) if (action.isNotEmpty()) AppParasitics.AppLifecycleCallback.onReceiversCallback[action.value()] = Pair(action, result)
} }
/** 设置创建生命周期监听回调 */ /** 设置创建生命周期监听回调 */
@PublishedApi @PublishedApi
internal fun build() { internal fun build() {
YukiHookBridge.AppLifecycleCallback.isCallbackSetUp = true AppParasitics.AppLifecycleCallback.isCallbackSetUp = true
} }
} }

View File

@@ -29,38 +29,24 @@
package com.highcapable.yukihookapi.hook.xposed.bridge package com.highcapable.yukihookapi.hook.xposed.bridge
import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.YukiGenerateApi import com.highcapable.yukihookapi.annotation.YukiGenerateApi
import com.highcapable.yukihookapi.hook.factory.* import com.highcapable.yukihookapi.hook.factory.classOf
import com.highcapable.yukihookapi.hook.log.yLoggerE import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.log.yLoggerW 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.PackageParam
import com.highcapable.yukihookapi.hook.param.type.HookEntryType import com.highcapable.yukihookapi.hook.param.type.HookEntryType
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
import com.highcapable.yukihookapi.hook.type.android.*
import com.highcapable.yukihookapi.hook.type.java.BooleanType
import com.highcapable.yukihookapi.hook.type.java.IntType
import com.highcapable.yukihookapi.hook.type.java.JavaClassLoader
import com.highcapable.yukihookapi.hook.type.java.StringType
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.dummy.YukiResources
import com.highcapable.yukihookapi.hook.xposed.bridge.factory.YukiHookHelper 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.factory.YukiMemberReplacement
import com.highcapable.yukihookapi.hook.xposed.bridge.inject.YukiHookBridge_Injector 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.bridge.status.YukiHookModuleStatus
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper import com.highcapable.yukihookapi.hook.xposed.helper.YukiHookAppHelper
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
import dalvik.system.PathClassLoader import dalvik.system.PathClassLoader
import de.robv.android.xposed.IXposedHookInitPackageResources import de.robv.android.xposed.IXposedHookInitPackageResources
import de.robv.android.xposed.IXposedHookLoadPackage import de.robv.android.xposed.IXposedHookLoadPackage
@@ -79,16 +65,9 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage
@YukiGenerateApi @YukiGenerateApi
object YukiHookBridge { object YukiHookBridge {
/** Android 系统框架名称 */
@PublishedApi
internal const val SYSTEM_FRAMEWORK_NAME = "android"
/** Xposed 是否装载完成 */ /** Xposed 是否装载完成 */
private var isXposedInitialized = false private var isXposedInitialized = false
/** [YukiHookDataChannel] 是否已经注册 */
private var isDataChannelRegister = false
/** 当前 Hook 进程是否正处于 [IXposedHookZygoteInit.initZygote] */ /** 当前 Hook 进程是否正处于 [IXposedHookZygoteInit.initZygote] */
private var isInitializingZygote = false private var isInitializingZygote = false
@@ -98,49 +77,12 @@ object YukiHookBridge {
/** 当前 [PackageParamWrapper] 实例数组 */ /** 当前 [PackageParamWrapper] 实例数组 */
private val packageParamWrappers = HashMap<String, PackageParamWrapper>() private val packageParamWrappers = HashMap<String, PackageParamWrapper>()
/** 已被注入到宿主 [Resources] 中的当前 Xposed 模块资源 HashCode 数组 */
private val injectedHostResourcesHashCodes = HashSet<Int>()
/** 当前 [PackageParam] 方法体回调 */ /** 当前 [PackageParam] 方法体回调 */
internal var packageParamCallback: (PackageParam.() -> Unit)? = null internal var packageParamCallback: (PackageParam.() -> Unit)? = null
/** 当前 Hook Framework 是否支持 Resources Hook */ /** 当前 Hook Framework 是否支持 Resources Hook */
internal var isSupportResourcesHook = false internal var isSupportResourcesHook = false
/**
* 当前 Hook APP (宿主) 的全局生命周期 [Application]
*
* 需要 [YukiHookAPI.Configs.isEnableDataChannel] 或 [AppLifecycleCallback.isCallbackSetUp] 才会生效
*/
internal var hostApplication: Application? = null
/** 当前 Xposed 模块自身 APK 路径 */
internal var moduleAppFilePath = ""
/** 当前 Xposed 模块自身 [Resources] */
internal var moduleAppResources: YukiModuleResources? = null
/**
* 当前环境中使用的 [ClassLoader]
*
* 装载位于 (Xposed) 宿主环境与模块环境时均使用当前 DEX 内的 [ClassLoader]
* @return [ClassLoader]
* @throws IllegalStateException 如果 [ClassLoader] 为空
*/
internal val baseClassLoader get() = classOf<YukiHookAPI>().classLoader ?: error("Operating system not supported")
/**
* 获取当前 Xposed 模块自身动态 [Resources]
* @return [YukiModuleResources] or null
*/
internal val dynamicModuleAppResources get() = runCatching { YukiModuleResources.wrapper(moduleAppFilePath) }.getOrNull()
/**
* 自动生成的 Xposed 模块构建版本号
* @return [String]
*/
internal val moduleGeneratedVersion get() = YukiHookBridge_Injector.getModuleGeneratedVersion()
/** /**
* 当前宿主正在进行的 Hook 进程标识名称 * 当前宿主正在进行的 Hook 进程标识名称
* @return [String] * @return [String]
@@ -148,14 +90,18 @@ object YukiHookBridge {
internal val hostProcessName get() = if (isInitializingZygote) "android-zygote" else YukiHookAppHelper.currentPackageName() ?: "unknown" internal val hostProcessName get() = if (isInitializingZygote) "android-zygote" else YukiHookAppHelper.currentPackageName() ?: "unknown"
/** /**
* 获取当前系统框架的 [Context] * 自动生成的 Xposed 模块构建版本号
* @return [Context] ContextImpl 实例对象 * @return [String]
* @throws IllegalStateException 如果获取不到系统框架的 [Context]
*/ */
internal val systemContext internal val moduleGeneratedVersion get() = YukiHookBridge_Injector.getModuleGeneratedVersion()
get() = ActivityThreadClass.method { name = "currentActivityThread" }.ignored().get().call()?.let {
ActivityThreadClass.method { name = "getSystemContext" }.ignored().get(it).invoke<Context?>() /**
} ?: error("Failed to got SystemContext") * 预设的 Xposed 模块包名
*
* - ❗装载代码将自动生成 - 请勿手动修改 - 会引发未知异常
*/
@YukiGenerateApi
var modulePackageName = ""
/** /**
* 模块是否装载了 Xposed 回调方法 * 模块是否装载了 Xposed 回调方法
@@ -167,14 +113,6 @@ object YukiHookBridge {
val isXposedCallbackSetUp val isXposedCallbackSetUp
get() = isXposedInitialized.not() && packageParamCallback != null get() = isXposedInitialized.not() && packageParamCallback != null
/**
* 预设的 Xposed 模块包名
*
* - ❗装载代码将自动生成 - 请勿手动修改 - 会引发未知异常
*/
@YukiGenerateApi
var modulePackageName = ""
/** /**
* 获取当前 Hook 框架的名称 * 获取当前 Hook 框架的名称
* *
@@ -201,19 +139,6 @@ object YukiHookBridge {
*/ */
internal val hasXposedBridge get() = executorVersion >= 0 internal val hasXposedBridge get() = executorVersion >= 0
/**
* 获取指定 [packageName] 的用户 ID
*
* 机主为 0 - 应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同
* @param packageName 当前包名
* @return [Int]
*/
internal fun findUserId(packageName: String) =
UserHandleClass.method {
name = "getUserId"
param(IntType)
}.ignored().get().int(systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid)
/** /**
* 自动忽略 MIUI 系统可能出现的日志收集注入实例 * 自动忽略 MIUI 系统可能出现的日志收集注入实例
* @param packageName 当前包名 * @param packageName 当前包名
@@ -259,12 +184,12 @@ object YukiHookBridge {
if (type == HookEntryType.ZYGOTE || appClassLoader != null) if (type == HookEntryType.ZYGOTE || appClassLoader != null)
PackageParamWrapper( PackageParamWrapper(
type = type, type = type,
packageName = packageName ?: SYSTEM_FRAMEWORK_NAME, packageName = packageName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME,
processName = processName ?: SYSTEM_FRAMEWORK_NAME, processName = processName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME,
appClassLoader = appClassLoader ?: XposedBridge.BOOTCLASSLOADER, appClassLoader = appClassLoader ?: XposedBridge.BOOTCLASSLOADER,
appInfo = appInfo, appInfo = appInfo,
appResources = appResources appResources = appResources
).also { packageParamWrappers[packageName ?: SYSTEM_FRAMEWORK_NAME] = it } ).also { packageParamWrappers[packageName ?: AppParasitics.SYSTEM_FRAMEWORK_NAME] = it }
else null else null
else packageParamWrappers[packageName]?.also { else packageParamWrappers[packageName]?.also {
it.type = type it.type = type
@@ -276,125 +201,6 @@ object YukiHookBridge {
} }
} }
/**
* 注入当前 Hook APP (宿主) 全局生命周期
* @param packageName 包名
*/
private fun registerToAppLifecycle(packageName: String) {
/** Hook [Application] 装载方法 */
runCatching {
if (AppLifecycleCallback.isCallbackSetUp) {
YukiHookHelper.hook(ApplicationClass.method { name = "attach"; param(ContextClass) }, object : YukiMemberHook() {
override fun beforeHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, false) }
}.onFailure { wrapper.throwable = it }
}
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, true) }
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onTerminate" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onTerminateCallback?.invoke(it) }
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onLowMemory" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onLowMemoryCallback?.invoke(it) }
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onTrimMemory"; param(IntType) }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
val self = wrapper.instance as? Application? ?: return
val type = wrapper.args?.get(0) as? Int? ?: return
AppLifecycleCallback.onTrimMemoryCallback?.invoke(self, type)
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onConfigurationChanged" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
val self = wrapper.instance as? Application? ?: return
val config = wrapper.args?.get(0) as? Configuration? ?: return
AppLifecycleCallback.onConfigurationChangedCallback?.invoke(self, config)
}.onFailure { wrapper.throwable = it }
}
})
}
if (YukiHookAPI.Configs.isEnableDataChannel || AppLifecycleCallback.isCallbackSetUp)
YukiHookHelper.hook(InstrumentationClass.method { name = "callApplicationOnCreate" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.args?.get(0) as? Application?)?.also {
hostApplication = it
AppLifecycleCallback.onCreateCallback?.invoke(it)
AppLifecycleCallback.onReceiversCallback.takeIf { e -> e.isNotEmpty() }?.forEach { (_, e) ->
if (e.first.isNotEmpty()) it.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (context == null || intent == null) return
if (e.first.any { e -> e == intent.action }) e.second(context, intent)
}
}, IntentFilter().apply { e.first.forEach { e -> addAction(e) } })
}
if (isDataChannelRegister) return
isDataChannelRegister = true
runCatching { YukiHookDataChannel.instance().register(it, packageName) }
}
}.onFailure { wrapper.throwable = it }
}
})
}
}
/**
* 向 Hook APP (宿主) 注入当前 Xposed 模块的资源
* @param hostResources 需要注入的宿主 [Resources]
*/
internal fun injectModuleAppResources(hostResources: Resources) {
if (injectedHostResourcesHashCodes.contains(hostResources.hashCode())) return
if (hasXposedBridge) runCatching {
hostResources.assets.current {
method {
name = "addAssetPath"
param(StringType)
}.call(moduleAppFilePath)
}
injectedHostResourcesHashCodes.add(hostResources.hashCode())
}.onFailure {
yLoggerE(msg = "Failed to inject module resources into [$hostResources]", e = it)
} else yLoggerW(msg = "You can only inject module resources in Xposed Environment")
}
/** 刷新当前 Xposed 模块自身 [Resources] */
internal fun refreshModuleAppResources() {
dynamicModuleAppResources?.let { moduleAppResources = it }
}
/**
* 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法
* @param loader 当前 [ClassLoader]
* @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve)
*/
internal fun hookClassLoader(loader: ClassLoader?, result: (clazz: Class<*>, resolve: Boolean) -> Unit) {
runCatching {
YukiHookHelper.hook(JavaClassLoader.method { name = "loadClass"; param(StringType, BooleanType) }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
if (wrapper.instance?.javaClass?.name == loader?.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 模块自身激活状态和 Resources Hook 支持状态 * Hook 模块自身激活状态和 Resources Hook 支持状态
* *
@@ -441,8 +247,8 @@ object YukiHookBridge {
*/ */
@YukiGenerateApi @YukiGenerateApi
fun callXposedZygoteLoaded(sparam: IXposedHookZygoteInit.StartupParam) { fun callXposedZygoteLoaded(sparam: IXposedHookZygoteInit.StartupParam) {
moduleAppFilePath = sparam.modulePath AppParasitics.moduleAppFilePath = sparam.modulePath
refreshModuleAppResources() AppParasitics.refreshModuleAppResources()
} }
/** /**
@@ -468,7 +274,7 @@ object YukiHookBridge {
resparam: XC_InitPackageResources.InitPackageResourcesParam? = null resparam: XC_InitPackageResources.InitPackageResourcesParam? = null
) { ) {
if (isMiuiCatcherPatch(packageName = lpparam?.packageName ?: resparam?.packageName).not()) when { if (isMiuiCatcherPatch(packageName = lpparam?.packageName ?: resparam?.packageName).not()) when {
isZygoteLoaded -> assignWrapper(HookEntryType.ZYGOTE, SYSTEM_FRAMEWORK_NAME, SYSTEM_FRAMEWORK_NAME) isZygoteLoaded -> assignWrapper(HookEntryType.ZYGOTE, AppParasitics.SYSTEM_FRAMEWORK_NAME, AppParasitics.SYSTEM_FRAMEWORK_NAME)
lpparam != null -> lpparam != null ->
if (isPackageLoaded(lpparam.packageName, HookEntryType.PACKAGE).not()) if (isPackageLoaded(lpparam.packageName, HookEntryType.PACKAGE).not())
assignWrapper(HookEntryType.PACKAGE, lpparam.packageName, lpparam.processName, lpparam.classLoader, lpparam.appInfo) assignWrapper(HookEntryType.PACKAGE, lpparam.packageName, lpparam.processName, lpparam.classLoader, lpparam.appInfo)
@@ -480,38 +286,8 @@ object YukiHookBridge {
else -> null else -> null
}?.also { }?.also {
YukiHookAPI.onXposedLoaded(it) YukiHookAPI.onXposedLoaded(it)
if (it.type == HookEntryType.PACKAGE) registerToAppLifecycle(it.packageName) if (it.type == HookEntryType.PACKAGE) AppParasitics.registerToAppLifecycle(it.packageName)
if (it.type == HookEntryType.RESOURCES) isSupportResourcesHook = true if (it.type == HookEntryType.RESOURCES) isSupportResourcesHook = true
} }
} }
/**
* 当前 Hook APP (宿主) 的生命周期回调处理类
*/
internal object AppLifecycleCallback {
/** 是否已设置回调 */
internal var isCallbackSetUp = false
/** [Application.attachBaseContext] 回调 */
internal var attachBaseContextCallback: ((Context, Boolean) -> Unit)? = null
/** [Application.onCreate] 回调 */
internal var onCreateCallback: (Application.() -> Unit)? = null
/** [Application.onTerminate] 回调 */
internal var onTerminateCallback: (Application.() -> Unit)? = null
/** [Application.onLowMemory] 回调 */
internal var onLowMemoryCallback: (Application.() -> Unit)? = null
/** [Application.onTrimMemory] 回调 */
internal var onTrimMemoryCallback: ((Application, Int) -> Unit)? = null
/** [Application.onConfigurationChanged] 回调 */
internal var onConfigurationChangedCallback: ((Application, Configuration) -> Unit)? = null
/** 系统广播监听回调 */
internal val onReceiversCallback = HashMap<String, Pair<Array<out String>, (Context, Intent) -> Unit>>()
}
} }

View File

@@ -0,0 +1,274 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/8/14.
*/
package com.highcapable.yukihookapi.hook.xposed.parasitic
import android.app.Activity
import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.classOf
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
import com.highcapable.yukihookapi.hook.type.android.*
import com.highcapable.yukihookapi.hook.type.java.BooleanType
import com.highcapable.yukihookapi.hook.type.java.IntType
import com.highcapable.yukihookapi.hook.type.java.JavaClassLoader
import com.highcapable.yukihookapi.hook.type.java.StringType
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.channel.YukiHookDataChannel
/**
* 这是一个管理 APP 寄生功能的控制类
*
* 通过这些功能即可轻松实现对 (Xposed) 宿主环境的 [Resources] 注入以及 [Activity] 代理
*/
@PublishedApi
internal object AppParasitics {
/** Android 系统框架名称 */
@PublishedApi
internal const val SYSTEM_FRAMEWORK_NAME = "android"
/** [YukiHookDataChannel] 是否已经注册 */
private var isDataChannelRegister = false
/** 已被注入到宿主 [Resources] 中的当前 Xposed 模块资源 HashCode 数组 */
private val injectedHostResourcesHashCodes = HashSet<Int>()
/**
* 当前 Hook APP (宿主) 的全局生命周期 [Application]
*
* 需要 [YukiHookAPI.Configs.isEnableDataChannel] 或 [AppLifecycleCallback.isCallbackSetUp] 才会生效
*/
internal var hostApplication: Application? = null
/** 当前 Xposed 模块自身 APK 路径 */
internal var moduleAppFilePath = ""
/** 当前 Xposed 模块自身 [Resources] */
internal var moduleAppResources: YukiModuleResources? = null
/**
* 当前环境中使用的 [ClassLoader]
*
* 装载位于 (Xposed) 宿主环境与模块环境时均使用当前 DEX 内的 [ClassLoader]
* @return [ClassLoader]
* @throws IllegalStateException 如果 [ClassLoader] 为空
*/
internal val baseClassLoader get() = classOf<YukiHookAPI>().classLoader ?: error("Operating system not supported")
/**
* 获取当前 Xposed 模块自身动态 [Resources]
* @return [YukiModuleResources] or null
*/
internal val dynamicModuleAppResources get() = runCatching { YukiModuleResources.wrapper(moduleAppFilePath) }.getOrNull()
/**
* 获取当前系统框架的 [Context]
* @return [Context] ContextImpl 实例对象
* @throws IllegalStateException 如果获取不到系统框架的 [Context]
*/
internal val systemContext
get() = ActivityThreadClass.method { name = "currentActivityThread" }.ignored().get().call()?.let {
ActivityThreadClass.method { name = "getSystemContext" }.ignored().get(it).invoke<Context?>()
} ?: error("Failed to got SystemContext")
/**
* 获取指定 [packageName] 的用户 ID
*
* 机主为 0 - 应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同
* @param packageName 当前包名
* @return [Int]
*/
internal fun findUserId(packageName: String) =
UserHandleClass.method {
name = "getUserId"
param(IntType)
}.ignored().get().int(systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid)
/**
* 注入当前 Hook APP (宿主) 全局生命周期
* @param packageName 包名
*/
internal fun registerToAppLifecycle(packageName: String) {
/** Hook [Application] 装载方法 */
runCatching {
if (AppLifecycleCallback.isCallbackSetUp) {
YukiHookHelper.hook(ApplicationClass.method { name = "attach"; param(ContextClass) }, object : YukiMemberHook() {
override fun beforeHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, false) }
}.onFailure { wrapper.throwable = it }
}
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, true) }
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onTerminate" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onTerminateCallback?.invoke(it) }
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onLowMemory" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onLowMemoryCallback?.invoke(it) }
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onTrimMemory"; param(IntType) }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
val self = wrapper.instance as? Application? ?: return
val type = wrapper.args?.get(0) as? Int? ?: return
AppLifecycleCallback.onTrimMemoryCallback?.invoke(self, type)
}.onFailure { wrapper.throwable = it }
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onConfigurationChanged" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
val self = wrapper.instance as? Application? ?: return
val config = wrapper.args?.get(0) as? Configuration? ?: return
AppLifecycleCallback.onConfigurationChangedCallback?.invoke(self, config)
}.onFailure { wrapper.throwable = it }
}
})
}
if (YukiHookAPI.Configs.isEnableDataChannel || AppLifecycleCallback.isCallbackSetUp)
YukiHookHelper.hook(InstrumentationClass.method { name = "callApplicationOnCreate" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
runCatching {
(wrapper.args?.get(0) as? Application?)?.also {
hostApplication = it
AppLifecycleCallback.onCreateCallback?.invoke(it)
AppLifecycleCallback.onReceiversCallback.takeIf { e -> e.isNotEmpty() }?.forEach { (_, e) ->
if (e.first.isNotEmpty()) it.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (context == null || intent == null) return
if (e.first.any { e -> e == intent.action }) e.second(context, intent)
}
}, IntentFilter().apply { e.first.forEach { e -> addAction(e) } })
}
if (isDataChannelRegister) return
isDataChannelRegister = true
runCatching { YukiHookDataChannel.instance().register(it, packageName) }
}
}.onFailure { wrapper.throwable = it }
}
})
}
}
/**
* 监听并 Hook 当前 [ClassLoader] 的 [ClassLoader.loadClass] 方法
* @param loader 当前 [ClassLoader]
* @param result 回调 - ([Class] 实例对象,[Boolean] 是否 resolve)
*/
internal fun hookClassLoader(loader: ClassLoader?, result: (clazz: Class<*>, resolve: Boolean) -> Unit) {
runCatching {
YukiHookHelper.hook(JavaClassLoader.method { name = "loadClass"; param(StringType, BooleanType) }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
if (wrapper.instance?.javaClass?.name == loader?.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 APP (宿主) 注入当前 Xposed 模块的资源
* @param hostResources 需要注入的宿主 [Resources]
*/
internal fun injectModuleAppResources(hostResources: Resources) {
if (injectedHostResourcesHashCodes.contains(hostResources.hashCode())) return
if (YukiHookBridge.hasXposedBridge) runCatching {
hostResources.assets.current {
method {
name = "addAssetPath"
param(StringType)
}.call(moduleAppFilePath)
}
injectedHostResourcesHashCodes.add(hostResources.hashCode())
}.onFailure {
yLoggerE(msg = "Failed to inject module resources into [$hostResources]", e = it)
} else yLoggerW(msg = "You can only inject module resources in Xposed Environment")
}
/** 刷新当前 Xposed 模块自身 [Resources] */
internal fun refreshModuleAppResources() {
dynamicModuleAppResources?.let { moduleAppResources = it }
}
/**
* 当前 Hook APP (宿主) 的生命周期回调处理类
*/
internal object AppLifecycleCallback {
/** 是否已设置回调 */
internal var isCallbackSetUp = false
/** [Application.attachBaseContext] 回调 */
internal var attachBaseContextCallback: ((Context, Boolean) -> Unit)? = null
/** [Application.onCreate] 回调 */
internal var onCreateCallback: (Application.() -> Unit)? = null
/** [Application.onTerminate] 回调 */
internal var onTerminateCallback: (Application.() -> Unit)? = null
/** [Application.onLowMemory] 回调 */
internal var onLowMemoryCallback: (Application.() -> Unit)? = null
/** [Application.onTrimMemory] 回调 */
internal var onTrimMemoryCallback: ((Application, Int) -> Unit)? = null
/** [Application.onConfigurationChanged] 回调 */
internal var onConfigurationChangedCallback: ((Application, Configuration) -> Unit)? = null
/** 系统广播监听回调 */
internal val onReceiversCallback = HashMap<String, Pair<Array<out String>, (Context, Intent) -> Unit>>()
}
}