Fix LSPosed when opened "只有模块classloader可以使用Xposed API" not founded the API's bug And add more feature function

This commit is contained in:
2022-03-06 00:13:43 +08:00
parent ca01a47efa
commit c1797ebade
14 changed files with 107 additions and 35 deletions

View File

@@ -37,7 +37,7 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration
import java.io.File
/**
* 这是 YukiHookAPI 的自动生成处理类 - 核心基于 KSP
* 这是 [YukiHookAPI] 的自动生成处理类 - 核心基于 KSP
*
* 可以帮你快速生成 Xposed 入口类和包名
*

View File

@@ -36,22 +36,21 @@ import com.highcapable.yukihookapi.YukiHookAPI.encase
import com.highcapable.yukihookapi.annotation.DoNotUseField
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.hasClass
import com.highcapable.yukihookapi.hook.factory.processName
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.*
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage
/**
* YukiHookAPI 的装载调用类
* [YukiHookAPI] 的装载调用类
*
* 可以实现作为模块装载和自定义 Hook 装载两种方式
*
* 模块装载方式已经自动对接 Xposed API - 可直接调用 [encase] 完成操作
*
* 你可以调用 [configs] 对 YukiHookAPI 进行配置
* 你可以调用 [configs] 对 [YukiHookAPI] 进行配置
*/
object YukiHookAPI {
@@ -97,10 +96,21 @@ object YukiHookAPI {
* 请过滤 [debugTag] 即可找到每条日志
*/
var isDebug = true
/**
* 是否启用调试日志的输出功能
*
* - ❗关闭后将会停用 [YukiHookAPI] 对全部日志的输出
*
* 但是不影响当你手动调用下面这些方法输出日志
*
* [loggerD]、[loggerI]、[loggerW]、[loggerE]
*/
var isAllowPrintingLogs = true
}
/**
* 配置 YukiHookAPI 相关参数
* 配置 [YukiHookAPI] 相关参数
*
* 详情请参考 [configs 方法](https://github.com/fankes/YukiHookAPI/wiki/API-%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE#configs-%E6%96%B9%E6%B3%95)
* @param initiate 方法体
@@ -207,7 +217,7 @@ object YukiHookAPI {
}
/** 输出找不到 [XposedBridge] 的错误日志 */
private fun printNoXposedBridge() = loggerE(msg = "Could not found XposedBridge in current space! Aborted")
private fun printNoXposedBridge() = yLoggerE(msg = "Could not found XposedBridge in current space! Aborted")
/**
* 通过 baseContext 创建 Hook 入口类
@@ -220,5 +230,9 @@ object YukiHookAPI {
* 是否存在 [XposedBridge]
* @return [Boolean]
*/
internal val hasXposedBridge get() = ("de.robv.android.xposed.XposedBridge").hasClass
internal val hasXposedBridge
get() = runCatching {
if (Configs.isDebug) yLoggerI(msg = "YukiHookAPI is running on Xposed API ${XposedBridge.getXposedVersion()}")
true
}.getOrNull() ?: false
}

View File

@@ -29,10 +29,11 @@
package com.highcapable.yukihookapi.annotation.xposed
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
/**
* 标识 YukiHookAPI 注入 Xposed 入口的类注释
* 标识 [YukiHookAPI] 注入 Xposed 入口的类注释
*
* - 你的项目 source 目录默认为 "src/main/" 可在 [sourcePath] 中进行自定义 - 自动处理程序将只检查 ..app/[sourcePath]/java.. 中间部分
*

View File

@@ -36,8 +36,8 @@ import com.highcapable.yukihookapi.hook.bean.HookClass
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerI
import com.highcapable.yukihookapi.hook.param.HookParam
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
@@ -48,7 +48,7 @@ import java.lang.reflect.Field
import java.lang.reflect.Member
/**
* YukiHookAPI 核心 Hook 实现类
* [YukiHookAPI] 核心 Hook 实现类
*
* 这是一个 API 对接类 - 实现原生对接 [XposedBridge]
* @param packageParam 需要传入 [PackageParam] 实现方法调用
@@ -103,7 +103,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
else Thread {
SystemClock.sleep(10)
if (onHookClassNotFoundFailureCallback == null)
loggerE(msg = "HookClass [${hookClass.name}] not found", e = hookClass.throwable)
yLoggerE(msg = "HookClass [${hookClass.name}] not found", e = hookClass.throwable)
else onHookClassNotFoundFailureCallback?.invoke(hookClass.throwable ?: Throwable("[${hookClass.name}] not found"))
}.start()
return Result()
@@ -427,7 +427,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
onHookingFailureCallback?.invoke(it)
onAllFailureCallback?.invoke(it)
if (isNotIgnoredHookingFailure)
loggerE(
yLoggerE(
msg = if (isHookMemberSetup)
"Hooked Member with a finding error by $hookClass [$tag]"
else "Hooked Member cannot be non-null by $hookClass [$tag]",
@@ -448,7 +448,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
}
}.onFailure {
onAllFailureCallback?.invoke(it)
if (isNotIgnoredHookingFailure) loggerE(msg = "Hooked All Members with an error in Class [$hookClass] [$tag]")
if (isNotIgnoredHookingFailure) yLoggerE(msg = "Hooked All Members with an error in Class [$hookClass] [$tag]")
}
}
@@ -457,7 +457,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
* @param msg 调试日志内容
*/
private fun onHookLogMsg(msg: String) {
if (YukiHookAPI.Configs.isDebug) loggerI(msg = msg)
if (YukiHookAPI.Configs.isDebug) yLoggerI(msg = msg)
}
/**
@@ -465,7 +465,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
* @param throwable 异常信息
*/
private fun onHookFailureMsg(throwable: Throwable) =
loggerE(msg = "Try to hook ${hookClass.instance ?: hookClass.name}[$member] got an Exception [$tag]", e = throwable)
yLoggerE(msg = "Try to hook ${hookClass.instance ?: hookClass.name}[$member] got an Exception [$tag]", e = throwable)
/**
* 判断是否没有设置 Hook 过程中的任何异常拦截

View File

@@ -32,7 +32,7 @@ package com.highcapable.yukihookapi.hook.core.finder
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
import com.highcapable.yukihookapi.hook.utils.runBlocking
import java.lang.reflect.Constructor
@@ -177,7 +177,7 @@ class ConstructorFinder(
)
remedyPlans.clear()
}
} else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookTag}]")
} else yLoggerW(msg = "RemedyPlan is empty,forgot it? [${hookTag}]")
}
/**

View File

@@ -33,7 +33,7 @@ import android.os.SystemClock
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
import com.highcapable.yukihookapi.hook.utils.runBlocking
import java.lang.reflect.Field
@@ -75,7 +75,7 @@ class FieldFinder(
@DoNotUseMethod
override fun build(isBind: Boolean) = when {
name.isBlank() -> {
loggerE(msg = "Field name cannot be empty in Class [$classSet] [${hookTag}]")
yLoggerE(msg = "Field name cannot be empty in Class [$classSet] [${hookTag}]")
Result(isNoSuch = true)
}
else -> try {
@@ -91,7 +91,7 @@ class FieldFinder(
} catch (e: Throwable) {
Thread {
SystemClock.sleep(10)
if (isNotIgnoredHookingFailure) loggerE(msg = "NoSuchField happend in [$classSet] [${hookTag}]", e = e)
if (isNotIgnoredHookingFailure) yLoggerE(msg = "NoSuchField happend in [$classSet] [${hookTag}]", e = e)
}.start()
Result(isNoSuch = true, e)
}

View File

@@ -32,8 +32,8 @@ package com.highcapable.yukihookapi.hook.core.finder
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
import com.highcapable.yukihookapi.hook.utils.runBlocking
import java.lang.reflect.Method
@@ -117,7 +117,7 @@ class MethodFinder(
@DoNotUseMethod
override fun build(isBind: Boolean) = when {
name.isBlank() -> {
loggerE(msg = "Method name cannot be empty in Class [$classSet] [${hookTag}]")
yLoggerE(msg = "Method name cannot be empty in Class [$classSet] [${hookTag}]")
Result(isNoSuch = true)
}
else -> try {
@@ -201,7 +201,7 @@ class MethodFinder(
)
remedyPlans.clear()
}
} else loggerW(msg = "RemedyPlan is empty,forgot it? [${hookTag}]")
} else yLoggerW(msg = "RemedyPlan is empty,forgot it? [${hookTag}]")
}
/**

View File

@@ -31,8 +31,8 @@ import android.os.SystemClock
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerI
import java.lang.reflect.Member
/**
@@ -75,7 +75,7 @@ abstract class BaseFinder(
* @param isAlwaysPrint 忽略条件每次都打印错误
*/
internal fun onFailureMsg(msg: String = "", throwable: Throwable? = null, isAlwaysPrint: Boolean = false) {
fun print() = loggerE(msg = "NoSuch$tag happend in [$classSet] $msg [${hookTag}]", e = throwable)
fun print() = yLoggerE(msg = "NoSuch$tag happend in [$classSet] $msg [${hookTag}]", e = throwable)
if (isAlwaysPrint) print()
else Thread {
SystemClock.sleep(10)
@@ -88,7 +88,7 @@ abstract class BaseFinder(
* @param msg 调试日志内容
*/
internal fun onHookLogMsg(msg: String) {
if (YukiHookAPI.Configs.isDebug) loggerI(msg = msg)
if (YukiHookAPI.Configs.isDebug) yLoggerI(msg = msg)
}
/**

View File

@@ -34,7 +34,7 @@ import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
/**
* YukiHookAPI 的子类 Hooker 实现
* [YukiHookAPI] 的子类 Hooker 实现
*
* 也许你的 Module 中存在多个 Hooker - 继承此类可以方便帮你管理每个 Hooker
*

View File

@@ -78,6 +78,22 @@ fun String.hasClass(loader: ClassLoader?) = try {
false
}
/**
* 查找变量是否存在
* @param name 名称
* @param type 类型 - 不填默认模糊
* @return [Boolean] 是否存在
*/
fun Class<*>.hasField(name: String, type: Class<*>? = null): Boolean =
try {
if (type != null)
ReflectionUtils.findFieldIfExists(this, type.name, name)
else getDeclaredField(name).apply { isAccessible = true }
true
} catch (_: Throwable) {
false
}
/**
* 查找方法是否存在
* @param name 名称

View File

@@ -33,6 +33,47 @@ import android.util.Log
import com.highcapable.yukihookapi.YukiHookAPI
import de.robv.android.xposed.XposedBridge
/**
* [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - D
*
* - ❗此方法为私有功能性 API - 你不应该手动调用此方法
* @param msg 日志打印的内容
*/
internal fun yLoggerD(msg: String) {
if (YukiHookAPI.Configs.isAllowPrintingLogs) loggerD(msg = msg)
}
/**
* [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - I
*
* - ❗此方法为私有功能性 API - 你不应该手动调用此方法
* @param msg 日志打印的内容
*/
internal fun yLoggerI(msg: String) {
if (YukiHookAPI.Configs.isAllowPrintingLogs) loggerI(msg = msg)
}
/**
* [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - W
*
* - ❗此方法为私有功能性 API - 你不应该手动调用此方法
* @param msg 日志打印的内容
*/
internal fun yLoggerW(msg: String) {
if (YukiHookAPI.Configs.isAllowPrintingLogs) loggerW(msg = msg)
}
/**
* [YukiHookAPI] 向控制台和 [XposedBridge] 打印日志 - E
*
* - ❗此方法为私有功能性 API - 你不应该手动调用此方法
* @param msg 日志打印的内容
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
*/
internal fun yLoggerE(msg: String, e: Throwable? = null) {
if (YukiHookAPI.Configs.isAllowPrintingLogs) loggerE(msg = msg, e = e)
}
/**
* 向控制台和 [XposedBridge] 打印日志 - D
*

View File

@@ -28,7 +28,7 @@
package com.highcapable.yukihookapi.hook.xposed
import androidx.annotation.Keep
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.yLoggerI
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus.isActive
/**
@@ -47,7 +47,7 @@ object YukiHookModuleStatus {
*/
@Keep
fun isActive(): Boolean {
loggerI(msg = "This Module is not actived")
yLoggerI(msg = "This Module is not actived")
return false
}
}

View File

@@ -49,7 +49,7 @@ import java.io.File
*
* - 使用 LSPosed 环境请在 AndroidManifests.xml 中将 "xposedminversion" 最低设置为 93
*
* - 未使用 LSPosed 环境请将你的模块 API 降至 26 以下 - YukiHookAPI 将会尝试使用 [makeWorldReadable] 但仍有可能不成功
* - 未使用 LSPosed 环境请将你的模块 API 降至 26 以下 - [YukiHookAPI] 将会尝试使用 [makeWorldReadable] 但仍有可能不成功
*
* - ❗当你在模块中存取数据的时候 [context] 必须不能是空的
*

View File

@@ -34,7 +34,7 @@ import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.factory.encase
/**
* YukiHookAPI 的 Xposed 装载 API 调用接口
* [YukiHookAPI] 的 Xposed 装载 API 调用接口
*
* - ❗请在此类上添加注释 [InjectYukiHookWithXposed] 标记模块 Hook 入口
*