Merge findMethod/findField/findClass function and hookMember function to self api

This commit is contained in:
2022-08-09 02:29:48 +08:00
parent 4a3d5b093e
commit ff05e3cd5e
2 changed files with 109 additions and 120 deletions

View File

@@ -40,7 +40,10 @@ import android.content.res.Configuration
import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI
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.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.param.PackageParam
@@ -144,10 +147,9 @@ object YukiHookBridge {
* @throws IllegalStateException 如果获取不到系统框架的 [Context]
*/
internal val systemContext
get() = runCatching {
YukiHookHelper.findMethod(ActivityThreadClass, name = "getSystemContext")
.invoke(YukiHookHelper.findMethod(ActivityThreadClass, name = "currentActivityThread").invoke(null)) as? Context?
}.getOrNull() ?: error("Failed to got SystemContext")
get() = ActivityThreadClass.method { name = "currentActivityThread" }.ignored().get().call()?.let {
ActivityThreadClass.method { name = "getSystemContext" }.ignored().get(it).invoke<Context?>()
} ?: error("Failed to got SystemContext")
/**
* 模块是否装载了 Xposed 回调方法
@@ -175,7 +177,7 @@ object YukiHookBridge {
*/
internal val executorName
get() = runCatching {
(YukiHookHelper.findField(XposedBridge::class.java, name = "TAG").get(null) as? String?)
classOf<XposedBridge>().field { name = "TAG" }.ignored().get().string().takeIf { it.isNotBlank() }
?.replace(oldValue = "Bridge", newValue = "")?.replace(oldValue = "-", newValue = "")?.trim() ?: "unknown"
}.getOrNull() ?: "invalid"
@@ -200,10 +202,11 @@ object YukiHookBridge {
* @param packageName 当前包名
* @return [Int]
*/
internal fun findUserId(packageName: String) = runCatching {
YukiHookHelper.findMethod(UserHandleClass, name = "getUserId", IntType)
.invoke(null, systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid) as? Int ?: 0
}.getOrNull() ?: 0
internal fun findUserId(packageName: String) =
UserHandleClass.method {
name = "getUserId"
param(IntType)
}.ignored().get().int(systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid)
/**
* 自动忽略 MIUI 系统可能出现的日志收集注入实例
@@ -275,7 +278,7 @@ object YukiHookBridge {
/** Hook [Application] 装载方法 */
runCatching {
if (AppLifecycleCallback.isCallbackSetUp) {
YukiHookHelper.hookMember(YukiHookHelper.findMethod(ApplicationClass, name = "attach", ContextClass), object : YukiMemberHook() {
YukiHookHelper.hook(ApplicationClass.method { name = "attach"; param(ContextClass) }, object : YukiMemberHook() {
override fun beforeHookedMember(wrapper: HookParamWrapper) {
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, false) }
}
@@ -284,56 +287,51 @@ object YukiHookBridge {
(wrapper.args?.get(0) as? Context?)?.also { AppLifecycleCallback.attachBaseContextCallback?.invoke(it, true) }
}
})
YukiHookHelper.hookMember(YukiHookHelper.findMethod(ApplicationClass, name = "onTerminate"), object : YukiMemberHook() {
YukiHookHelper.hook(ApplicationClass.method { name = "onTerminate" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onTerminateCallback?.invoke(it) }
}
})
YukiHookHelper.hookMember(YukiHookHelper.findMethod(ApplicationClass, name = "onLowMemory"), object : YukiMemberHook() {
YukiHookHelper.hook(ApplicationClass.method { name = "onLowMemory" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
(wrapper.instance as? Application?)?.also { AppLifecycleCallback.onLowMemoryCallback?.invoke(it) }
}
})
YukiHookHelper.hookMember(
YukiHookHelper.findMethod(ApplicationClass, name = "onTrimMemory", IntType),
object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
val self = wrapper.instance as? Application? ?: return
val type = wrapper.args?.get(0) as? Int? ?: return
AppLifecycleCallback.onTrimMemoryCallback?.invoke(self, type)
}
})
YukiHookHelper.hookMember(YukiHookHelper.findMethod(ApplicationClass, name = "onConfigurationChanged", ConfigurationClass),
object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
val self = wrapper.instance as? Application? ?: return
val config = wrapper.args?.get(0) as? Configuration? ?: return
AppLifecycleCallback.onConfigurationChangedCallback?.invoke(self, config)
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onTrimMemory"; param(IntType) }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
val self = wrapper.instance as? Application? ?: return
val type = wrapper.args?.get(0) as? Int? ?: return
AppLifecycleCallback.onTrimMemoryCallback?.invoke(self, type)
}
})
YukiHookHelper.hook(ApplicationClass.method { name = "onConfigurationChanged" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
val self = wrapper.instance as? Application? ?: return
val config = wrapper.args?.get(0) as? Configuration? ?: return
AppLifecycleCallback.onConfigurationChangedCallback?.invoke(self, config)
}
})
}
if (YukiHookAPI.Configs.isEnableDataChannel || AppLifecycleCallback.isCallbackSetUp)
YukiHookHelper.hookMember(
YukiHookHelper.findMethod(InstrumentationClass, name = "callApplicationOnCreate", ApplicationClass),
object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
(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 { a -> a == intent.action }) e.second(context, intent)
}
}, IntentFilter().apply { e.first.forEach { a -> addAction(a) } })
}
if (isDataChannelRegister) return
isDataChannelRegister = true
runCatching { YukiHookDataChannel.instance().register(it, packageName) }
YukiHookHelper.hook(InstrumentationClass.method { name = "callApplicationOnCreate" }, object : YukiMemberHook() {
override fun afterHookedMember(wrapper: HookParamWrapper) {
(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) }
}
})
}
})
}
}
@@ -343,12 +341,15 @@ object YukiHookBridge {
*/
internal fun injectModuleAppResources(context: Context) {
if (injectedHostContextHashCodes.contains(context.hashCode())) return
injectedHostContextHashCodes.add(context.hashCode())
if (hasXposedBridge)
runCatching {
YukiHookHelper.findMethod(AssetManagerClass, name = "addAssetPath", StringType)
.invoke(context.resources.assets, moduleAppFilePath)
injectedHostContextHashCodes.add(context.hashCode())
}.onFailure { yLoggerE(msg = "Failed to inject module resources in context [$context]", e = it) }
AssetManagerClass.method {
name = "addAssetPath"
param(StringType)
}.ignored().onNoSuchMethod {
runCatching { injectedHostContextHashCodes.remove(context.hashCode()) }
yLoggerE(msg = "Failed to inject module resources in context [$context]", e = it)
}.get(context.resources.assets).call(moduleAppFilePath)
else yLoggerW(msg = "You can only inject module resources in Xposed Environment")
}
@@ -364,14 +365,12 @@ object YukiHookBridge {
*/
internal fun hookClassLoader(loader: ClassLoader?, result: (clazz: Class<*>, resolve: Boolean) -> Unit) {
runCatching {
YukiHookHelper.hookMember(
YukiHookHelper.findMethod(JavaClassLoader, name = "loadClass", 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) }
}
})
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") }
}
@@ -384,27 +383,23 @@ object YukiHookBridge {
*/
@YukiGenerateApi
fun hookModuleAppStatus(loader: ClassLoader?, isHookResourcesStatus: Boolean = false) {
if (YukiHookAPI.Configs.isEnableHookModuleStatus)
YukiHookHelper.findClass(loader, YukiHookModuleStatus::class.java).also { statusClass ->
if (isHookResourcesStatus.not()) {
YukiHookHelper.hookMember(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME),
object : YukiMemberReplacement() {
override fun replaceHookedMember(wrapper: HookParamWrapper) = true
})
YukiHookHelper.hookMember(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.GET_XPOSED_TAG_METHOD_NAME),
object : YukiMemberReplacement() {
override fun replaceHookedMember(wrapper: HookParamWrapper) = executorName
})
YukiHookHelper.hookMember(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.GET_XPOSED_VERSION_METHOD_NAME),
object : YukiMemberReplacement() {
override fun replaceHookedMember(wrapper: HookParamWrapper) = executorVersion
})
} else
YukiHookHelper.hookMember(YukiHookHelper.findMethod(statusClass, YukiHookModuleStatus.HAS_RESOURCES_HOOK_METHOD_NAME),
object : YukiMemberReplacement() {
override fun replaceHookedMember(wrapper: HookParamWrapper) = true
})
}
if (YukiHookAPI.Configs.isEnableHookModuleStatus.not()) return
classOf<YukiHookModuleStatus>(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
})
}
}
/**

View File

@@ -25,15 +25,19 @@
*
* This file is Created by fankes on 2022/7/28.
*/
@file:Suppress("NewApi")
package com.highcapable.yukihookapi.hook.xposed.bridge.factory
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import java.lang.reflect.Field
import java.lang.reflect.Member
import java.lang.reflect.Method
/**
* Hook 回调优先级配置类
@@ -67,33 +71,20 @@ internal object YukiHookedMembers {
internal object YukiHookHelper {
/**
* 查找 [Class]
* @param loader 当前 [ClassLoader]
* @param baseClass 当前类
* @return [Field]
* @throws IllegalStateException 如果 [ClassLoader] 为空
* Hook [BaseFinder.BaseResult]
* @param traction 直接调用 [BaseFinder.BaseResult]
* @param callback 回调
* @return [Pair] - ([YukiMemberHook.Unhook] or null,[Boolean] 是否已经 Hook)
*/
internal fun findClass(loader: ClassLoader?, baseClass: Class<*>) = loader?.loadClass(baseClass.name) ?: error("ClassLoader is null")
/**
* 查找 [Field]
* @param baseClass 所在类
* @param name 变量名称
* @return [Field]
* @throws NoSuchFieldError 如果找不到变量
*/
internal fun findField(baseClass: Class<*>, name: String) = baseClass.getDeclaredField(name).apply { isAccessible = true }
/**
* 查找 [Method]
* @param baseClass 所在类
* @param name 方法名称
* @param paramTypes 方法参数
* @return [Method]
* @throws NoSuchMethodError 如果找不到方法
*/
internal fun findMethod(baseClass: Class<*>, name: String, vararg paramTypes: Class<*>) =
baseClass.getDeclaredMethod(name, *paramTypes).apply { isAccessible = true }
internal fun hook(traction: BaseFinder.BaseResult, callback: YukiHookCallback) = runCatching {
hookMember(
when (traction) {
is MethodFinder.Result -> traction.ignored().give()
is ConstructorFinder.Result -> traction.ignored().give()
else -> error("Unexpected BaseFinder result interface type")
}, callback
)
}.onFailure { yLoggerE(msg = "Hooking Process exception occurred", e = it) }.getOrNull() ?: Pair(null, false)
/**
* Hook [Member]
@@ -103,18 +94,21 @@ internal object YukiHookHelper {
* @param callback 回调
* @return [Pair] - ([YukiMemberHook.Unhook] or null,[Boolean] 是否已经 Hook)
*/
internal fun hookMember(member: Member, callback: YukiHookCallback): Pair<YukiMemberHook.Unhook?, Boolean> {
internal fun hookMember(member: Member?, callback: YukiHookCallback): Pair<YukiMemberHook.Unhook?, Boolean> {
runCatching {
YukiHookedMembers.hookedMembers.takeIf { it.isNotEmpty() }?.forEach {
if (it.member.toString() == member.toString()) return@runCatching it
if (it.member.toString() == member?.toString()) return@runCatching it
}
}
return if (YukiHookBridge.hasXposedBridge)
YukiMemberHook.Unhook.wrapper(XposedBridge.hookMethod(member, callback.compat())).let {
YukiHookedMembers.hookedMembers.add(it)
Pair(it, false)
}
else Pair(null, false)
return when {
member == null -> Pair(null, false)
YukiHookBridge.hasXposedBridge ->
YukiMemberHook.Unhook.wrapper(XposedBridge.hookMethod(member, callback.compat())).let {
YukiHookedMembers.hookedMembers.add(it)
Pair(it, false)
}
else -> Pair(null, false)
}
}
/**
@@ -125,9 +119,9 @@ internal object YukiHookHelper {
* @param args 参数实例
* @return [Any] or null
*/
internal fun invokeOriginalMember(member: Member, instance: Any?, vararg args: Any?) =
internal fun invokeOriginalMember(member: Member?, instance: Any?, vararg args: Any?) =
if (YukiHookBridge.hasXposedBridge && YukiHookedMembers.hookedMembers.any { it.member.toString() == member.toString() })
XposedBridge.invokeOriginalMethod(member, instance, args)
member?.let { XposedBridge.invokeOriginalMethod(it, instance, args) }
else null
/**