mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-05 18:25:28 +08:00
Added much functions and Merge code
This commit is contained in:
@@ -194,7 +194,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
|
|||||||
}
|
}
|
||||||
File("$projectPath${separator}assets").also { assFile ->
|
File("$projectPath${separator}assets").also { assFile ->
|
||||||
if (File("$projectPath${separator}AndroidManifest.xml").exists()) {
|
if (File("$projectPath${separator}AndroidManifest.xml").exists()) {
|
||||||
if (!assFile.exists() || !assFile.isDirectory) {
|
if (assFile.exists().not() || assFile.isDirectory.not()) {
|
||||||
assFile.delete()
|
assFile.delete()
|
||||||
assFile.mkdirs()
|
assFile.mkdirs()
|
||||||
}
|
}
|
||||||
|
@@ -299,7 +299,7 @@ object YukiHookAPI {
|
|||||||
|
|
||||||
/** 输出欢迎信息调试日志 */
|
/** 输出欢迎信息调试日志 */
|
||||||
private fun printSplashLog() {
|
private fun printSplashLog() {
|
||||||
if (!Configs.isDebug || !isShowSplashLogOnceTime || isModulePackageXposedEnv) return
|
if (Configs.isDebug.not() || isShowSplashLogOnceTime.not() || isModulePackageXposedEnv) return
|
||||||
isShowSplashLogOnceTime = false
|
isShowSplashLogOnceTime = false
|
||||||
yLoggerI(msg = "Welcome to YukiHookAPI $API_VERSION_NAME($API_VERSION_CODE)! Using $executorName API $executorVersion")
|
yLoggerI(msg = "Welcome to YukiHookAPI $API_VERSION_NAME($API_VERSION_CODE)! Using $executorName API $executorVersion")
|
||||||
}
|
}
|
||||||
|
@@ -100,12 +100,12 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
|
|||||||
*/
|
*/
|
||||||
@DoNotUseMethod
|
@DoNotUseMethod
|
||||||
fun hook(): Result {
|
fun hook(): Result {
|
||||||
if (!YukiHookAPI.hasXposedBridge) return Result()
|
if (YukiHookAPI.hasXposedBridge.not()) return Result()
|
||||||
if (hookMembers.isEmpty()) error("Hook Members is empty,hook aborted")
|
if (hookMembers.isEmpty()) error("Hook Members is empty,hook aborted")
|
||||||
else Thread {
|
else Thread {
|
||||||
SystemClock.sleep(10)
|
SystemClock.sleep(10)
|
||||||
if (!isDisableCreaterRunHook && hookClass.instance != null) hookMembers.forEach { (_, member) -> member.hook() }
|
if (isDisableCreaterRunHook.not() && hookClass.instance != null) hookMembers.forEach { (_, member) -> member.hook() }
|
||||||
if (!isDisableCreaterRunHook && hookClass.instance == null)
|
if (isDisableCreaterRunHook.not() && hookClass.instance == null)
|
||||||
if (onHookClassNotFoundFailureCallback == null)
|
if (onHookClassNotFoundFailureCallback == null)
|
||||||
yLoggerE(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"))
|
else onHookClassNotFoundFailureCallback?.invoke(hookClass.throwable ?: Throwable("[${hookClass.name}] not found"))
|
||||||
@@ -360,7 +360,7 @@ class YukiHookCreater(private val packageParam: PackageParam, private val hookCl
|
|||||||
*/
|
*/
|
||||||
@DoNotUseMethod
|
@DoNotUseMethod
|
||||||
fun hook() {
|
fun hook() {
|
||||||
if (!YukiHookAPI.hasXposedBridge || isDisableMemberRunHook) return
|
if (YukiHookAPI.hasXposedBridge.not() || isDisableMemberRunHook) return
|
||||||
if (hookClass.instance == null) {
|
if (hookClass.instance == null) {
|
||||||
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
|
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
|
||||||
onHookingFailureCallback?.invoke(it)
|
onHookingFailureCallback?.invoke(it)
|
||||||
|
@@ -35,8 +35,9 @@ package com.highcapable.yukihookapi.hook.core.finder
|
|||||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||||
|
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
|
||||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||||
import java.lang.reflect.Constructor
|
import java.lang.reflect.Constructor
|
||||||
|
|
||||||
@@ -61,28 +62,50 @@ class ConstructorFinder(
|
|||||||
/** [Constructor] 参数数组 */
|
/** [Constructor] 参数数组 */
|
||||||
private var paramTypes: Array<out Class<*>>? = null
|
private var paramTypes: Array<out Class<*>>? = null
|
||||||
|
|
||||||
|
/** [ModifierRules] 实例 */
|
||||||
|
private var modifiers: ModifierRules? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Constructor] 参数个数
|
||||||
|
*
|
||||||
|
* 你可以不使用 [param] 指定参数类型而是仅使用此变量指定参数个数
|
||||||
|
*
|
||||||
|
* 若参数个数小于零则忽略并使用 [param]
|
||||||
|
*/
|
||||||
|
var paramCount = -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Constructor] 筛选条件
|
||||||
|
*
|
||||||
|
* 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Constructor]
|
||||||
|
* @param initiate 方法体
|
||||||
|
*/
|
||||||
|
fun modifiers(initiate: ModifierRules.() -> Unit) {
|
||||||
|
modifiers = ModifierRules().apply(initiate)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Constructor] 参数
|
* [Constructor] 参数
|
||||||
*
|
*
|
||||||
|
* 如果同时使用了 [paramCount] 则 [paramTypes] 的数量必须与 [paramCount] 完全匹配
|
||||||
|
*
|
||||||
* - ❗无参 [Constructor] 不要使用此方法
|
* - ❗无参 [Constructor] 不要使用此方法
|
||||||
*
|
*
|
||||||
* - ❗有参 [Constructor] 必须使用此方法设定参数
|
* - ❗有参 [Constructor] 必须使用此方法设定参数或使用 [paramCount] 指定个数
|
||||||
* @param paramType 参数类型数组
|
* @param paramType 参数类型数组
|
||||||
*/
|
*/
|
||||||
fun param(vararg paramType: Class<*>) {
|
fun param(vararg paramType: Class<*>) {
|
||||||
if (paramType.isEmpty()) error("paramType is empty, please delete param() method")
|
if (paramType.isEmpty()) error("paramTypes is empty, please delete param() method")
|
||||||
paramTypes = paramType
|
paramTypes = paramType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到构造方法
|
* 得到构造方法
|
||||||
* @return [Constructor]
|
* @return [Constructor]
|
||||||
|
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||||
* @throws NoSuchMethodError 如果找不到构造方法
|
* @throws NoSuchMethodError 如果找不到构造方法
|
||||||
*/
|
*/
|
||||||
private val result
|
private val result get() = ReflectionTool.findConstructor(classSet, modifiers, paramCount, paramTypes)
|
||||||
get() = if (paramTypes != null)
|
|
||||||
ReflectionUtils.findConstructorExact(classSet, *paramTypes!!)
|
|
||||||
else ReflectionUtils.findConstructorExact(classSet)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置实例
|
* 设置实例
|
||||||
@@ -170,7 +193,7 @@ class ConstructorFinder(
|
|||||||
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it", isAlwaysPrint = true)
|
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it", isAlwaysPrint = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isFindSuccess) {
|
if (isFindSuccess.not()) {
|
||||||
onFailureMsg(
|
onFailureMsg(
|
||||||
msg = "trying ${remedyPlans.size} times and all failure by RemedyPlan",
|
msg = "trying ${remedyPlans.size} times and all failure by RemedyPlan",
|
||||||
throwable = lastError,
|
throwable = lastError,
|
||||||
@@ -206,7 +229,7 @@ class ConstructorFinder(
|
|||||||
* @param isNoSuch 是否没有找到构造方法 - 默认否
|
* @param isNoSuch 是否没有找到构造方法 - 默认否
|
||||||
* @param e 错误信息
|
* @param e 错误信息
|
||||||
*/
|
*/
|
||||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
inner class Result(internal val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建监听结果事件方法体
|
* 创建监听结果事件方法体
|
||||||
|
@@ -33,8 +33,9 @@ import android.os.SystemClock
|
|||||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||||
|
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
|
||||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
@@ -50,6 +51,9 @@ class FieldFinder(
|
|||||||
override val classSet: Class<*>? = null
|
override val classSet: Class<*>? = null
|
||||||
) : BaseFinder(tag = "Field", hookInstance, classSet) {
|
) : BaseFinder(tag = "Field", hookInstance, classSet) {
|
||||||
|
|
||||||
|
/** [ModifierRules] 实例 */
|
||||||
|
private var modifiers: ModifierRules? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Field] 名称
|
* [Field] 名称
|
||||||
*
|
*
|
||||||
@@ -64,6 +68,16 @@ class FieldFinder(
|
|||||||
*/
|
*/
|
||||||
var type: Class<*>? = null
|
var type: Class<*>? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Field] 筛选条件
|
||||||
|
*
|
||||||
|
* 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Field]
|
||||||
|
* @param initiate 方法体
|
||||||
|
*/
|
||||||
|
fun modifiers(initiate: ModifierRules.() -> Unit) {
|
||||||
|
modifiers = ModifierRules().apply(initiate)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到变量处理结果
|
* 得到变量处理结果
|
||||||
*
|
*
|
||||||
@@ -80,10 +94,7 @@ class FieldFinder(
|
|||||||
}
|
}
|
||||||
else -> try {
|
else -> try {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
memberInstance =
|
memberInstance = ReflectionTool.findField(classSet, name, modifiers, type)
|
||||||
if (type != null)
|
|
||||||
ReflectionUtils.findFieldIfExists(classSet, type?.name, name)
|
|
||||||
else classSet?.getDeclaredField(name)?.apply { isAccessible = true }
|
|
||||||
}.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") }
|
}.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") }
|
||||||
Result()
|
Result()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
@@ -111,7 +122,7 @@ class FieldFinder(
|
|||||||
* @param isNoSuch 是否没有找到变量 - 默认否
|
* @param isNoSuch 是否没有找到变量 - 默认否
|
||||||
* @param e 错误信息
|
* @param e 错误信息
|
||||||
*/
|
*/
|
||||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
inner class Result(internal val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建监听结果事件方法体
|
* 创建监听结果事件方法体
|
||||||
|
@@ -35,9 +35,10 @@ package com.highcapable.yukihookapi.hook.core.finder
|
|||||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||||
|
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
|
||||||
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
import com.highcapable.yukihookapi.hook.utils.runBlocking
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
@@ -62,6 +63,9 @@ class MethodFinder(
|
|||||||
/** [Method] 参数数组 */
|
/** [Method] 参数数组 */
|
||||||
private var paramTypes: Array<out Class<*>>? = null
|
private var paramTypes: Array<out Class<*>>? = null
|
||||||
|
|
||||||
|
/** [ModifierRules] 实例 */
|
||||||
|
private var modifiers: ModifierRules? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Method] 名称
|
* [Method] 名称
|
||||||
*
|
*
|
||||||
@@ -69,6 +73,15 @@ class MethodFinder(
|
|||||||
*/
|
*/
|
||||||
var name = ""
|
var name = ""
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Method] 参数个数
|
||||||
|
*
|
||||||
|
* 你可以不使用 [param] 指定参数类型而是仅使用此变量指定参数个数
|
||||||
|
*
|
||||||
|
* 若参数个数小于零则忽略并使用 [param]
|
||||||
|
*/
|
||||||
|
var paramCount = -1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Method] 返回值
|
* [Method] 返回值
|
||||||
*
|
*
|
||||||
@@ -76,29 +89,38 @@ class MethodFinder(
|
|||||||
*/
|
*/
|
||||||
var returnType: Class<*>? = null
|
var returnType: Class<*>? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Method] 筛选条件
|
||||||
|
*
|
||||||
|
* 可不设置筛选条件 - 默认模糊查找并取第一个匹配的 [Method]
|
||||||
|
* @param initiate 方法体
|
||||||
|
*/
|
||||||
|
fun modifiers(initiate: ModifierRules.() -> Unit) {
|
||||||
|
modifiers = ModifierRules().apply(initiate)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Method] 参数
|
* [Method] 参数
|
||||||
*
|
*
|
||||||
|
* 如果同时使用了 [paramCount] 则 [paramTypes] 的数量必须与 [paramCount] 完全匹配
|
||||||
|
*
|
||||||
* - ❗无参 [Method] 不要使用此方法
|
* - ❗无参 [Method] 不要使用此方法
|
||||||
*
|
*
|
||||||
* - ❗有参 [Method] 必须使用此方法设定参数
|
* - ❗有参 [Method] 必须使用此方法设定参数或使用 [paramCount] 指定个数
|
||||||
* @param paramType 参数类型数组
|
* @param paramType 参数类型数组
|
||||||
*/
|
*/
|
||||||
fun param(vararg paramType: Class<*>) {
|
fun param(vararg paramType: Class<*>) {
|
||||||
if (paramType.isEmpty()) error("paramType is empty, please delete param() method")
|
if (paramType.isEmpty()) error("paramTypes is empty, please delete param() method")
|
||||||
paramTypes = paramType
|
paramTypes = paramType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到方法
|
* 得到方法
|
||||||
* @return [Method]
|
* @return [Method]
|
||||||
* @throws IllegalStateException 如果 [name] 未设置
|
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||||
* @throws NoSuchMethodError 如果找不到方法
|
* @throws NoSuchMethodError 如果找不到方法
|
||||||
*/
|
*/
|
||||||
private val result
|
private val result get() = ReflectionTool.findMethod(classSet, name, modifiers, returnType, paramCount, paramTypes)
|
||||||
get() = if (paramTypes != null)
|
|
||||||
ReflectionUtils.findMethodBestMatch(classSet, returnType, name, *paramTypes!!)
|
|
||||||
else ReflectionUtils.findMethodNoParam(classSet, returnType, name)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置实例
|
* 设置实例
|
||||||
@@ -194,7 +216,7 @@ class MethodFinder(
|
|||||||
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it", isAlwaysPrint = true)
|
onFailureMsg(msg = "trying ${p + 1} times by RemedyPlan --> $it", isAlwaysPrint = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isFindSuccess) {
|
if (isFindSuccess.not()) {
|
||||||
onFailureMsg(
|
onFailureMsg(
|
||||||
msg = "trying ${remedyPlans.size} times and all failure by RemedyPlan",
|
msg = "trying ${remedyPlans.size} times and all failure by RemedyPlan",
|
||||||
throwable = lastError,
|
throwable = lastError,
|
||||||
@@ -230,7 +252,7 @@ class MethodFinder(
|
|||||||
* @param isNoSuch 是否没有找到方法 - 默认否
|
* @param isNoSuch 是否没有找到方法 - 默认否
|
||||||
* @param e 错误信息
|
* @param e 错误信息
|
||||||
*/
|
*/
|
||||||
inner class Result(private val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
inner class Result(internal val isNoSuch: Boolean = false, private val e: Throwable? = null) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建监听结果事件方法体
|
* 创建监听结果事件方法体
|
||||||
|
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* 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/3/27.
|
||||||
|
*/
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package com.highcapable.yukihookapi.hook.core.finder.type
|
||||||
|
|
||||||
|
import java.lang.reflect.Member
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这是一个 [Member] 描述符定义类
|
||||||
|
*
|
||||||
|
* 可对 R8 混淆后的 [Member] 进行更加详细的定位
|
||||||
|
*/
|
||||||
|
class ModifierRules {
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isPublic = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isPrivate = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isProtected = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isStatic = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isFinal = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isSynchronized = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isVolatile = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isTransient = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isNative = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isInterface = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isAbstract = false
|
||||||
|
|
||||||
|
/** 描述声明使用 */
|
||||||
|
private var isStrict = false
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 public */
|
||||||
|
fun asPublic() {
|
||||||
|
isPublic = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 private */
|
||||||
|
fun asPrivate() {
|
||||||
|
isPrivate = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 protected */
|
||||||
|
fun asProtected() {
|
||||||
|
isProtected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加描述 [Member] 类型包含 static
|
||||||
|
*
|
||||||
|
* 对于任意的静态 [Member] 可添加此描述进行确定
|
||||||
|
*
|
||||||
|
* 特别注意 Kotlin -> Jvm 后的 object 类中的方法并不是静态的
|
||||||
|
*/
|
||||||
|
fun asStatic() {
|
||||||
|
isStatic = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加描述 [Member] 类型包含 final
|
||||||
|
*
|
||||||
|
* 在 Kotlin -> Jvm 后没有 open 标识的 [Member] 和没有任何关联的 [Member] 都将为 final
|
||||||
|
*/
|
||||||
|
fun asFinal() {
|
||||||
|
isFinal = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 synchronized */
|
||||||
|
fun asSynchronized() {
|
||||||
|
isSynchronized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 volatile */
|
||||||
|
fun asVolatile() {
|
||||||
|
isVolatile = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 transient */
|
||||||
|
fun asTransient() {
|
||||||
|
isTransient = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加描述 [Member] 类型包含 native
|
||||||
|
*
|
||||||
|
* 对于任意 JNI 对接的 [Member] 可添加此描述进行确定
|
||||||
|
*/
|
||||||
|
fun asNative() {
|
||||||
|
isNative = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 interface */
|
||||||
|
fun asInterface() {
|
||||||
|
isInterface = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加描述 [Member] 类型包含 abstract
|
||||||
|
*
|
||||||
|
* 对于任意的抽象 [Member] 可添加此描述进行确定
|
||||||
|
*/
|
||||||
|
fun asAbstract() {
|
||||||
|
isAbstract = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加描述 [Member] 类型包含 strict */
|
||||||
|
fun asStrict() {
|
||||||
|
isStrict = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对比 [Member] 类型是否符合条件
|
||||||
|
* @param member 实例
|
||||||
|
* @return [Boolean] 是否符合条件
|
||||||
|
*/
|
||||||
|
internal fun contains(member: Member): Boolean {
|
||||||
|
var conditions = true
|
||||||
|
if (isPublic) conditions = Modifier.isPublic(member.modifiers)
|
||||||
|
if (isPrivate) conditions = conditions && Modifier.isPrivate(member.modifiers)
|
||||||
|
if (isProtected) conditions = conditions && Modifier.isProtected(member.modifiers)
|
||||||
|
if (isStatic) conditions = conditions && Modifier.isStatic(member.modifiers)
|
||||||
|
if (isFinal) conditions = conditions && Modifier.isFinal(member.modifiers)
|
||||||
|
if (isSynchronized) conditions = conditions && Modifier.isSynchronized(member.modifiers)
|
||||||
|
if (isVolatile) conditions = conditions && Modifier.isVolatile(member.modifiers)
|
||||||
|
if (isTransient) conditions = conditions && Modifier.isTransient(member.modifiers)
|
||||||
|
if (isNative) conditions = conditions && Modifier.isNative(member.modifiers)
|
||||||
|
if (isInterface) conditions = conditions && Modifier.isInterface(member.modifiers)
|
||||||
|
if (isAbstract) conditions = conditions && Modifier.isAbstract(member.modifiers)
|
||||||
|
if (isStrict) conditions = conditions && Modifier.isStrict(member.modifiers)
|
||||||
|
return conditions
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
var conditions = ""
|
||||||
|
if (isPublic) conditions += "<public> "
|
||||||
|
if (isPrivate) conditions += "<private> "
|
||||||
|
if (isProtected) conditions += "<protected> "
|
||||||
|
if (isStatic) conditions += "<static> "
|
||||||
|
if (isFinal) conditions += "<final> "
|
||||||
|
if (isSynchronized) conditions += "<synchronized> "
|
||||||
|
if (isVolatile) conditions += "<volatile> "
|
||||||
|
if (isTransient) conditions += "<transient> "
|
||||||
|
if (isNative) conditions += "<native> "
|
||||||
|
if (isInterface) conditions += "<interface> "
|
||||||
|
if (isAbstract) conditions += "<abstract> "
|
||||||
|
if (isStrict) conditions += "<strict> "
|
||||||
|
return "[${conditions.trim()}]"
|
||||||
|
}
|
||||||
|
}
|
@@ -33,7 +33,8 @@ import com.highcapable.yukihookapi.hook.bean.HookClass
|
|||||||
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
|
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
|
||||||
import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
|
import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
|
||||||
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
|
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
|
||||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||||
|
import java.lang.reflect.Member
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Class] 转换为 [HookClass]
|
* [Class] 转换为 [HookClass]
|
||||||
@@ -80,51 +81,31 @@ fun String.hasClass(loader: ClassLoader?) = try {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找变量是否存在
|
* 查找变量是否存在
|
||||||
* @param name 名称
|
* @param initiate 方法体
|
||||||
* @param type 类型 - 不填默认模糊
|
|
||||||
* @return [Boolean] 是否存在
|
* @return [Boolean] 是否存在
|
||||||
*/
|
*/
|
||||||
fun Class<*>.hasField(name: String, type: Class<*>? = null): Boolean =
|
fun Class<*>.hasField(initiate: FieldFinder.() -> Unit) = field(initiate).ignoredError().isNoSuch.not()
|
||||||
try {
|
|
||||||
if (type != null)
|
|
||||||
ReflectionUtils.findFieldIfExists(this, type.name, name)
|
|
||||||
else getDeclaredField(name).apply { isAccessible = true }
|
|
||||||
true
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找方法是否存在
|
* 查找方法是否存在
|
||||||
* @param name 名称
|
* @param initiate 方法体
|
||||||
* @param paramType params
|
|
||||||
* @param returnType 返回类型 - 不填默认模糊
|
|
||||||
* @return [Boolean] 是否存在
|
* @return [Boolean] 是否存在
|
||||||
*/
|
*/
|
||||||
fun Class<*>.hasMethod(name: String, vararg paramType: Class<*>, returnType: Class<*>? = null): Boolean =
|
fun Class<*>.hasMethod(initiate: MethodFinder.() -> Unit) = method(initiate).ignoredError().isNoSuch.not()
|
||||||
try {
|
|
||||||
if (paramType.isNotEmpty())
|
|
||||||
ReflectionUtils.findMethodBestMatch(this, returnType, name, *paramType)
|
|
||||||
else ReflectionUtils.findMethodNoParam(this, returnType, name)
|
|
||||||
true
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找构造方法是否存在
|
* 查找构造方法是否存在
|
||||||
* @param paramType params
|
* @param initiate 方法体
|
||||||
* @return [Boolean] 是否存在
|
* @return [Boolean] 是否存在
|
||||||
*/
|
*/
|
||||||
fun Class<*>.hasConstructor(vararg paramType: Class<*>): Boolean =
|
fun Class<*>.hasConstructor(initiate: ConstructorFinder.() -> Unit) = constructor(initiate).ignoredError().isNoSuch.not()
|
||||||
try {
|
|
||||||
if (paramType.isNotEmpty())
|
/**
|
||||||
ReflectionUtils.findConstructorExact(this, *paramType)
|
* 查询 [Member] 中匹配的描述符
|
||||||
else ReflectionUtils.findConstructorExact(this)
|
* @param initiate 方法体
|
||||||
true
|
* @return [Boolean] 是否存在
|
||||||
} catch (_: Throwable) {
|
*/
|
||||||
false
|
fun Member.hasModifiers(initiate: ModifierRules.() -> Unit) = ModifierRules().apply(initiate).contains(this)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找并得到变量
|
* 查找并得到变量
|
||||||
@@ -145,4 +126,4 @@ fun Class<*>.method(initiate: MethodFinder.() -> Unit) = MethodFinder(classSet =
|
|||||||
* @param initiate 查找方法体
|
* @param initiate 查找方法体
|
||||||
* @return [ConstructorFinder.Result]
|
* @return [ConstructorFinder.Result]
|
||||||
*/
|
*/
|
||||||
fun Class<*>.constructor(initiate: ConstructorFinder.() -> Unit) = ConstructorFinder(classSet = this).apply(initiate).build()
|
fun Class<*>.constructor(initiate: ConstructorFinder.() -> Unit) = ConstructorFinder(classSet = this).apply(initiate).build()
|
@@ -41,7 +41,7 @@ import de.robv.android.xposed.XposedBridge
|
|||||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||||
*/
|
*/
|
||||||
internal fun yLoggerD(msg: String, isDisableLog: Boolean = false) {
|
internal fun yLoggerD(msg: String, isDisableLog: Boolean = false) {
|
||||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerD(msg = msg)
|
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerD(msg = msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +52,7 @@ internal fun yLoggerD(msg: String, isDisableLog: Boolean = false) {
|
|||||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||||
*/
|
*/
|
||||||
internal fun yLoggerI(msg: String, isDisableLog: Boolean = false) {
|
internal fun yLoggerI(msg: String, isDisableLog: Boolean = false) {
|
||||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerI(msg = msg)
|
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerI(msg = msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,7 +63,7 @@ internal fun yLoggerI(msg: String, isDisableLog: Boolean = false) {
|
|||||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||||
*/
|
*/
|
||||||
internal fun yLoggerW(msg: String, isDisableLog: Boolean = false) {
|
internal fun yLoggerW(msg: String, isDisableLog: Boolean = false) {
|
||||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerW(msg = msg)
|
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerW(msg = msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +75,7 @@ internal fun yLoggerW(msg: String, isDisableLog: Boolean = false) {
|
|||||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||||
*/
|
*/
|
||||||
internal fun yLoggerE(msg: String, e: Throwable? = null, isDisableLog: Boolean = false) {
|
internal fun yLoggerE(msg: String, e: Throwable? = null, isDisableLog: Boolean = false) {
|
||||||
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (!isDisableLog) loggerE(msg = msg, e = e)
|
if (YukiHookAPI.Configs.isAllowPrintingLogs) if (isDisableLog.not()) loggerE(msg = msg, e = e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* 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/3/27.
|
||||||
|
*/
|
||||||
|
package com.highcapable.yukihookapi.hook.utils
|
||||||
|
|
||||||
|
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
|
||||||
|
import java.lang.reflect.Constructor
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
import java.lang.reflect.Member
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这是一个对 [Member] 查找的工具实现类
|
||||||
|
*/
|
||||||
|
internal object ReflectionTool {
|
||||||
|
|
||||||
|
/** 当前工具类的标签 */
|
||||||
|
private const val TAG = "YukiHookAPI#ReflectionTool"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找任意变量
|
||||||
|
* @param classSet 变量所在类
|
||||||
|
* @param name 变量名称
|
||||||
|
* @param modifiers 变量描述
|
||||||
|
* @param type 变量类型
|
||||||
|
* @return [Field]
|
||||||
|
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||||
|
* @throws NoSuchFieldError 如果找不到变量
|
||||||
|
*/
|
||||||
|
internal fun findField(classSet: Class<*>?, name: String, modifiers: ModifierRules?, type: Class<*>?): Field {
|
||||||
|
var field: Field? = null
|
||||||
|
run {
|
||||||
|
classSet?.declaredFields?.forEach {
|
||||||
|
var conditions = name == it.name
|
||||||
|
if (type != null) conditions = conditions && it.type == type
|
||||||
|
if (modifiers != null) conditions = conditions && modifiers.contains(it)
|
||||||
|
if (conditions) {
|
||||||
|
field = it.apply { isAccessible = true }
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
} ?: error("Can't find this Field [$name] because classSet is null")
|
||||||
|
}
|
||||||
|
return field ?: throw NoSuchFieldError(
|
||||||
|
"Can't find this Field --> " +
|
||||||
|
"name:[$name] " +
|
||||||
|
"type:[$type] " +
|
||||||
|
"modifiers:${modifiers ?: "[]"} " +
|
||||||
|
"in Class [$classSet] " +
|
||||||
|
"by $TAG"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找任意方法
|
||||||
|
* @param classSet 方法所在类
|
||||||
|
* @param name 方法名称
|
||||||
|
* @param modifiers 方法描述
|
||||||
|
* @param returnType 方法返回值
|
||||||
|
* @param paramCount 方法参数个数
|
||||||
|
* @param paramTypes 方法参数类型
|
||||||
|
* @return [Method]
|
||||||
|
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||||
|
* @throws NoSuchMethodError 如果找不到方法
|
||||||
|
*/
|
||||||
|
internal fun findMethod(
|
||||||
|
classSet: Class<*>?,
|
||||||
|
name: String,
|
||||||
|
modifiers: ModifierRules?,
|
||||||
|
returnType: Class<*>?,
|
||||||
|
paramCount: Int,
|
||||||
|
paramTypes: Array<out Class<*>>?
|
||||||
|
): Method {
|
||||||
|
var method: Method? = null
|
||||||
|
run {
|
||||||
|
classSet?.declaredMethods?.forEach {
|
||||||
|
var conditions = name == it.name
|
||||||
|
if (returnType != null) conditions = conditions && it.returnType == returnType
|
||||||
|
if (paramCount >= 0) conditions = conditions && it.parameterTypes.size == paramCount
|
||||||
|
if (paramTypes != null) conditions = conditions && arrayContentsEq(paramTypes, it.parameterTypes)
|
||||||
|
if (modifiers != null) conditions = conditions && modifiers.contains(it)
|
||||||
|
if (conditions) {
|
||||||
|
method = it.apply { isAccessible = true }
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
} ?: error("Can't find this Method [$name] because classSet is null")
|
||||||
|
}
|
||||||
|
return method ?: throw NoSuchMethodError(
|
||||||
|
"Can't find this Method --> " +
|
||||||
|
"name:[$name] " +
|
||||||
|
"paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " +
|
||||||
|
"paramTypes:[${paramTypes.typeOfString()}] " +
|
||||||
|
"returnType:[$returnType] " +
|
||||||
|
"modifiers:${modifiers ?: "[]"} " +
|
||||||
|
"in Class [$classSet] " +
|
||||||
|
"by $TAG"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找任意构造方法
|
||||||
|
* @param classSet 构造方法所在类
|
||||||
|
* @param modifiers 构造方法描述
|
||||||
|
* @param paramCount 构造方法参数个数
|
||||||
|
* @param paramTypes 构造方法参数类型
|
||||||
|
* @return [Constructor]
|
||||||
|
* @throws IllegalStateException 如果 [classSet] 为 null
|
||||||
|
* @throws NoSuchMethodError 如果找不到构造方法
|
||||||
|
*/
|
||||||
|
internal fun findConstructor(
|
||||||
|
classSet: Class<*>?,
|
||||||
|
modifiers: ModifierRules?,
|
||||||
|
paramCount: Int,
|
||||||
|
paramTypes: Array<out Class<*>>?
|
||||||
|
): Constructor<*> {
|
||||||
|
var constructor: Constructor<*>? = null
|
||||||
|
run {
|
||||||
|
classSet?.declaredConstructors?.forEach {
|
||||||
|
var conditions = false
|
||||||
|
if (paramCount >= 0) conditions = it.parameterTypes.size == paramCount
|
||||||
|
if (paramTypes != null) conditions = arrayContentsEq(paramTypes, it.parameterTypes)
|
||||||
|
if (modifiers != null) conditions = conditions && modifiers.contains(it)
|
||||||
|
if (conditions) {
|
||||||
|
constructor = it.apply { isAccessible = true }
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
} ?: error("Can't find this Constructor because classSet is null")
|
||||||
|
}
|
||||||
|
return constructor ?: throw NoSuchMethodError(
|
||||||
|
"Can't find this Constructor --> " +
|
||||||
|
"paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " +
|
||||||
|
"paramTypes:[${paramTypes.typeOfString()}] " +
|
||||||
|
"modifiers:${modifiers ?: "[]"} " +
|
||||||
|
"in Class [$classSet] " +
|
||||||
|
"by $TAG"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取参数数组文本化内容
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
private fun Array<out Class<*>>?.typeOfString() =
|
||||||
|
StringBuilder("(").also { sb ->
|
||||||
|
var isFirst = true
|
||||||
|
if (this == null || isEmpty()) return "()"
|
||||||
|
forEach {
|
||||||
|
if (isFirst) isFirst = false else sb.append(",")
|
||||||
|
sb.append(it.canonicalName)
|
||||||
|
}
|
||||||
|
sb.append(")")
|
||||||
|
}.toString()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断两个数组是否相等
|
||||||
|
*
|
||||||
|
* 复制自 [Class] 中的 [Class.arrayContentsEq]
|
||||||
|
* @param fArray 第一个数组
|
||||||
|
* @param lArray 第二个数组
|
||||||
|
* @return [Boolean] 是否相等
|
||||||
|
*/
|
||||||
|
private fun arrayContentsEq(fArray: Array<out Any>?, lArray: Array<out Any>?) = run {
|
||||||
|
if (fArray != null) when {
|
||||||
|
lArray == null -> fArray.isEmpty()
|
||||||
|
fArray.size != lArray.size -> false
|
||||||
|
else -> {
|
||||||
|
for (i in fArray.indices) if (fArray[i] !== lArray[i]) return@run false
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else lArray == null || lArray.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
@@ -1,210 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 zpp0196 on 2019/1/24 0024.
|
|
||||||
* This file is Modified by fankes on 2022/2/2 2240.
|
|
||||||
*/
|
|
||||||
package com.highcapable.yukihookapi.hook.utils;
|
|
||||||
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.highcapable.yukihookapi.annotation.DoNotUseClass;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@SuppressWarnings("ALL")
|
|
||||||
@DoNotUseClass
|
|
||||||
/**
|
|
||||||
* ReflectionUtils
|
|
||||||
*/
|
|
||||||
public class ReflectionUtils {
|
|
||||||
|
|
||||||
private static final HashMap<String, Field> fieldCache = new HashMap<>();
|
|
||||||
private static final HashMap<String, Method> methodCache = new HashMap<>();
|
|
||||||
|
|
||||||
private static String getParametersString(Class<?>... clazzes) {
|
|
||||||
StringBuilder sb = new StringBuilder("(");
|
|
||||||
boolean first = true;
|
|
||||||
for (Class<?> clazz : clazzes) {
|
|
||||||
if (first)
|
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
sb.append(",");
|
|
||||||
|
|
||||||
if (clazz != null)
|
|
||||||
sb.append(clazz.getCanonicalName());
|
|
||||||
else
|
|
||||||
sb.append("null");
|
|
||||||
}
|
|
||||||
sb.append(")");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 适用于查找混淆类型的 abcd 变量
|
|
||||||
*
|
|
||||||
* @param clazz 变量所在类
|
|
||||||
* @param typeName 类型名称
|
|
||||||
* @param fieldName 变量名
|
|
||||||
* @return Field
|
|
||||||
* @throws NoSuchFieldException 如果找不到变量
|
|
||||||
*/
|
|
||||||
public static Field findFieldIfExists(Class<?> clazz, String typeName, String fieldName) throws NoSuchFieldException {
|
|
||||||
String fullFieldName = "name:[" + fieldName + "] type:[" + typeName + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
|
||||||
if (!fieldCache.containsKey(fullFieldName)) {
|
|
||||||
if (clazz != null && !TextUtils.isEmpty(typeName) && !TextUtils.isEmpty(fieldName)) {
|
|
||||||
Class<?> clz = clazz;
|
|
||||||
do {
|
|
||||||
for (Field field : clz.getDeclaredFields()) {
|
|
||||||
if (field.getType()
|
|
||||||
.getName()
|
|
||||||
.equals(typeName) && field.getName()
|
|
||||||
.equals(fieldName)) {
|
|
||||||
field.setAccessible(true);
|
|
||||||
fieldCache.put(fullFieldName, field);
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while ((clz = clz.getSuperclass()) != null);
|
|
||||||
throw new NoSuchFieldException("Can't find this field --> " + fullFieldName);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
Field field = fieldCache.get(fullFieldName);
|
|
||||||
if (field == null)
|
|
||||||
throw new NoSuchFieldError(fullFieldName);
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 适用于查找混淆类型的 abcd 方法 - 无 param
|
|
||||||
*
|
|
||||||
* @param clazz 方法所在类
|
|
||||||
* @param returnType 返回类型
|
|
||||||
* @param methodName 方法名
|
|
||||||
* @return Method
|
|
||||||
* @throws NoSuchMethodError 如果找不到方法
|
|
||||||
*/
|
|
||||||
public static Method findMethodNoParam(Class<?> clazz, Class<?> returnType, String methodName) {
|
|
||||||
String fullMethodName = "name:[" + methodName + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
|
||||||
if (!methodCache.containsKey(fullMethodName)) {
|
|
||||||
Method method = findMethodIfExists(clazz, returnType, methodName);
|
|
||||||
methodCache.put(fullMethodName, method);
|
|
||||||
return method;
|
|
||||||
} else {
|
|
||||||
return methodCache.get(fullMethodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不区分 param 整个类搜索 - 适用于混淆方法 abcd
|
|
||||||
*
|
|
||||||
* @param clazz 方法所在类
|
|
||||||
* @param returnType 返回类型
|
|
||||||
* @param methodName 方法名
|
|
||||||
* @param parameterTypes 方法参数类型数组
|
|
||||||
* @return Method
|
|
||||||
* @throws NoSuchMethodError 如果找不到方法
|
|
||||||
*/
|
|
||||||
public static Method findMethodBestMatch(Class<?> clazz, Class<?> returnType, String methodName, Class<?>... parameterTypes) {
|
|
||||||
String fullMethodName = "name:[" + methodName + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
|
||||||
if (!methodCache.containsKey(fullMethodName)) {
|
|
||||||
Method method = findMethodIfExists(clazz, returnType, methodName, parameterTypes);
|
|
||||||
methodCache.put(fullMethodName, method);
|
|
||||||
return method;
|
|
||||||
} else {
|
|
||||||
return methodCache.get(fullMethodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找构造方法
|
|
||||||
*
|
|
||||||
* @param clazz 构造类所在类
|
|
||||||
* @param parameterTypes 构造类方法参数类型数组
|
|
||||||
* @return Constructor
|
|
||||||
* @throws NoSuchMethodError 如果找不到构造类
|
|
||||||
*/
|
|
||||||
public static Constructor<?> findConstructorExact(Class<?> clazz, Class<?>... parameterTypes) {
|
|
||||||
String fullConstructorName = "paramType:[" + getParametersString(parameterTypes) + "in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
|
||||||
try {
|
|
||||||
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
|
|
||||||
constructor.setAccessible(true);
|
|
||||||
return constructor;
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new NoSuchMethodError("Can't find this constructor --> " + fullConstructorName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
|
|
||||||
String fullMethodName = "name:[" + methodName + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder";
|
|
||||||
try {
|
|
||||||
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
|
|
||||||
method.setAccessible(true);
|
|
||||||
return method;
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new NoSuchMethodError("Can't find this method --> " + fullMethodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Method findMethodIfExists(Class<?> clazz, Class<?> returnType, String methodName, Class<?>... parameterTypes) {
|
|
||||||
long l = System.currentTimeMillis();
|
|
||||||
if (clazz != null && !TextUtils.isEmpty(methodName)) {
|
|
||||||
Class<?> clz = clazz;
|
|
||||||
if (returnType == null) return findMethodExact(clazz, methodName, parameterTypes);
|
|
||||||
do {
|
|
||||||
Method[] methods = findMethodsByExactParameters(clazz, returnType, parameterTypes);
|
|
||||||
for (Method method : methods) if (method.getName().equals(methodName)) return method;
|
|
||||||
} while ((clz = clz.getSuperclass()) != null);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Can't find this method --> name:[" + methodName + "] returnType:[" + returnType.getName() + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHookAPI#finder");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Method[] findMethodsByExactParameters(Class<?> clazz, Class<?> returnType, Class<?>... parameterTypes) {
|
|
||||||
List<Method> result = new LinkedList<Method>();
|
|
||||||
for (Method method : clazz.getDeclaredMethods()) {
|
|
||||||
if (returnType != null && returnType != method.getReturnType()) continue;
|
|
||||||
Class<?>[] methodParameterTypes = method.getParameterTypes();
|
|
||||||
if (parameterTypes.length != methodParameterTypes.length) continue;
|
|
||||||
boolean match = true;
|
|
||||||
for (int i = 0; i < parameterTypes.length; i++) {
|
|
||||||
if (parameterTypes[i] != methodParameterTypes[i]) {
|
|
||||||
match = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!match) continue;
|
|
||||||
method.setAccessible(true);
|
|
||||||
result.add(method);
|
|
||||||
}
|
|
||||||
return result.toArray(new Method[result.size()]);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user