mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-06 18:55:35 +08:00
...
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.highcapable.yukihookapi" />
|
@@ -1 +0,0 @@
|
||||
com.highcapable.yukihookapi.hook.xposed.YukiHookLoadPackage
|
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate", "unused", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package com.highcapable.yukihookapi
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import com.highcapable.yukihookapi.YukiHookAPI.encase
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseField
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.param.CustomParam
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
|
||||
/**
|
||||
* YukiHook 的装载 API 调用类
|
||||
*
|
||||
* 可以实现作为模块装载和自定义 Hook 装载两种方式
|
||||
*
|
||||
* 模块装载方式已经自动对接 Xposed API - 可直接调用 [encase] 完成操作
|
||||
*/
|
||||
object YukiHookAPI {
|
||||
|
||||
/** 全局标识 */
|
||||
const val TAG = "YukiHookAPI"
|
||||
|
||||
/** Xposed Hook API 绑定的模块包名 */
|
||||
@DoNotUseField
|
||||
internal var modulePackageName = ""
|
||||
|
||||
/** Xposed Hook API 方法体回调 */
|
||||
@DoNotUseField
|
||||
internal var packageParamCallback: (PackageParam.() -> Unit)? = null
|
||||
|
||||
/**
|
||||
* 作为模块装载调用入口方法 - Xposed API
|
||||
* @param moduleName 模块包名 - 填入当前的 BuildConfig.APPLICATION_ID
|
||||
* @param initiate Hook 方法体
|
||||
*/
|
||||
fun encase(moduleName: String = "", initiate: PackageParam.() -> Unit) {
|
||||
modulePackageName = moduleName
|
||||
packageParamCallback = initiate
|
||||
}
|
||||
|
||||
/**
|
||||
* 作为模块装载调用入口方法 - Xposed API
|
||||
* @param moduleName 模块包名 - 填入当前的 BuildConfig.APPLICATION_ID
|
||||
* @param hooker Hook 子类数组 - 必填不能为空
|
||||
* @throws IllegalStateException 如果 [hooker] 是空的
|
||||
*/
|
||||
fun encase(moduleName: String = "", vararg hooker: YukiBaseHooker) {
|
||||
modulePackageName = moduleName
|
||||
packageParamCallback = {
|
||||
if (hooker.isNotEmpty())
|
||||
hooker.forEach { it.assignInstance(packageParam = this) }
|
||||
else error("Hooker is empty")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 Hook 方法装载入口
|
||||
* @param classLoader [ClassLoader]
|
||||
* @param packageName 包名
|
||||
* @param appInfo [ApplicationInfo]
|
||||
* @param initiate Hook 方法体
|
||||
*/
|
||||
fun encase(
|
||||
classLoader: ClassLoader,
|
||||
packageName: String,
|
||||
appInfo: ApplicationInfo,
|
||||
initiate: PackageParam.() -> Unit
|
||||
) = initiate.invoke(PackageParam(customParam = CustomParam(classLoader, appInfo, packageName)))
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
|
||||
package com.highcapable.yukihookapi.annotation
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@MustBeDocumented
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.FIELD,
|
||||
AnnotationTarget.LOCAL_VARIABLE,
|
||||
AnnotationTarget.VALUE_PARAMETER,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
/**
|
||||
* ⚠️ 警告方法外部调用声明
|
||||
* 此方法除继承和接口外不应该在这里被调用
|
||||
* 如果调用此方法可能会出现错误或 APP 发生异常
|
||||
*/
|
||||
annotation class DoNotUseField
|
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
|
||||
package com.highcapable.yukihookapi.annotation
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@MustBeDocumented
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.LOCAL_VARIABLE,
|
||||
AnnotationTarget.VALUE_PARAMETER,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
/**
|
||||
* ⚠️ 警告方法外部调用声明
|
||||
* 此方法除继承和接口外不应该在这里被调用
|
||||
* 如果调用此方法可能会出现错误或 APP 发生异常
|
||||
*/
|
||||
annotation class DoNotUseMethod
|
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
|
||||
package com.highcapable.yukihookapi.annotation
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@MustBeDocumented
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.LOCAL_VARIABLE,
|
||||
AnnotationTarget.VALUE_PARAMETER,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
/**
|
||||
* 暂时不需要(用的很少)的变量
|
||||
* 可以打上此标记
|
||||
*/
|
||||
annotation class UseLessField
|
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
|
||||
package com.highcapable.yukihookapi.annotation
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@MustBeDocumented
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.LOCAL_VARIABLE,
|
||||
AnnotationTarget.VALUE_PARAMETER,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
/**
|
||||
* 暂时不需要(用的很少)的方法
|
||||
* 可以打上此标记
|
||||
*/
|
||||
annotation class UseLessMethod
|
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/3.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.annotation.xposed
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.highcapable.yukihookapi.hook.proxy.YukiHookXposedInitProxy
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookLoadPackage
|
||||
|
||||
/**
|
||||
* 标识注入 YukiHook 的类
|
||||
*
|
||||
* 此类将使用 [YukiHookLoadPackage] 自动调用 XposedInit
|
||||
*
|
||||
* 你可以将被注释的类继承于 [YukiHookXposedInitProxy] 接口实现 [YukiHookXposedInitProxy.onHook] 方法
|
||||
*
|
||||
* 只能拥有一个 Hook 入口 - 多个入口将以首个得到的入口为准
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Keep
|
||||
annotation class InjectYukiHookWithXposed
|
@@ -1,393 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate", "unused", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core
|
||||
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
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.param.HookParam
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import de.robv.android.xposed.XC_MethodReplacement
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* YukiHook 核心类实现方法
|
||||
*
|
||||
* 这是一个 API 对接类 - 实现原生对接 [XposedBridge]
|
||||
* @param packageParam 需要传入 [PackageParam] 实现方法调用
|
||||
* @param hookClass 要 Hook 的 [Class]
|
||||
*/
|
||||
class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Class<*>) {
|
||||
|
||||
/** 设置要 Hook 的方法、构造类 */
|
||||
private var hookMembers = HashMap<String, MemberHookCreater>()
|
||||
|
||||
/**
|
||||
* 注入要 Hook 的方法、构造类
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun injectMember(initiate: MemberHookCreater.() -> Unit) =
|
||||
MemberHookCreater().apply(initiate).apply {
|
||||
hookMembers[toString()] = this
|
||||
}.create()
|
||||
|
||||
/**
|
||||
* Hook 执行入口 - 不可在外部调用
|
||||
* @throws IllegalStateException 如果必要参数没有被设置
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun hook() {
|
||||
if (hookMembers.isEmpty()) error("Hook Members is empty,hook aborted")
|
||||
hookMembers.forEach { (_, member) -> member.hook() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能全局方法、构造类查找类实现方法
|
||||
*
|
||||
* 处理需要 Hook 的方法
|
||||
*/
|
||||
inner class MemberHookCreater {
|
||||
|
||||
/** [beforeHook] 回调 */
|
||||
private var beforeHookCallback: (HookParam.() -> Unit)? = null
|
||||
|
||||
/** [afterHook] 回调 */
|
||||
private var afterHookCallback: (HookParam.() -> Unit)? = null
|
||||
|
||||
/** [replaceAny]、[replaceUnit]、[replaceTo] 等回调 */
|
||||
private var replaceHookCallback: (HookParam.() -> Any?)? = null
|
||||
|
||||
/** Hook 过程中出现错误回调 */
|
||||
private var onConductFailureCallback: ((HookParam, Throwable) -> Unit)? = null
|
||||
|
||||
/** Hook 开始时出现错误回调 */
|
||||
private var onHookingFailureCallback: ((Throwable) -> Unit)? = null
|
||||
|
||||
/** 当找不到方法、变量时错误回调 */
|
||||
private var onNoSuchMemberCallback: ((Throwable) -> Unit)? = null
|
||||
|
||||
/** 全部错误回调 */
|
||||
private var onAllFailureCallback: ((Throwable) -> Unit)? = null
|
||||
|
||||
/** 是否为替换 Hook 模式 */
|
||||
private var isReplaceHookMode = false
|
||||
|
||||
/** 是否停止 Hook */
|
||||
private var isStopHookMode = false
|
||||
|
||||
/**
|
||||
* 手动指定要 Hook 的方法、构造类
|
||||
*
|
||||
* 你可以调用 [hookClass] 来手动查询要 Hook 的方法
|
||||
*/
|
||||
var member: Member? = null
|
||||
|
||||
/**
|
||||
* 查找需要 Hook 的方法
|
||||
*
|
||||
* 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun method(initiate: MethodFinder.() -> Unit) {
|
||||
runCatching {
|
||||
member = MethodFinder(hookClass).apply(initiate).find()
|
||||
}.onFailure {
|
||||
isStopHookMode = true
|
||||
onNoSuchMemberCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找需要 Hook 的构造类
|
||||
*
|
||||
* 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun constructor(initiate: ConstructorFinder.() -> Unit) {
|
||||
runCatching {
|
||||
member = ConstructorFinder(hookClass).apply(initiate).find()
|
||||
}.onFailure {
|
||||
isStopHookMode = true
|
||||
onNoSuchMemberCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找 [Field]
|
||||
* @param initiate 方法体
|
||||
* @return [FieldFinder.Result]
|
||||
*/
|
||||
fun HookParam.field(initiate: FieldFinder.() -> Unit) =
|
||||
try {
|
||||
FieldFinder(hookClass).apply(initiate).find()
|
||||
} catch (e: Throwable) {
|
||||
isStopHookMode = true
|
||||
onNoSuchMemberCallback?.invoke(e)
|
||||
onAllFailureCallback?.invoke(e)
|
||||
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(e)
|
||||
FieldFinder(hookClass).Result()
|
||||
}
|
||||
|
||||
/**
|
||||
* 在方法执行完成前 Hook
|
||||
*
|
||||
* 不可与 [replaceAny]、[replaceUnit]、[replaceTo] 同时使用
|
||||
* @param initiate [HookParam] 方法体
|
||||
*/
|
||||
fun beforeHook(initiate: HookParam.() -> Unit) {
|
||||
isReplaceHookMode = false
|
||||
beforeHookCallback = initiate
|
||||
}
|
||||
|
||||
/**
|
||||
* 在方法执行完成后 Hook
|
||||
*
|
||||
* 不可与 [replaceAny]、[replaceUnit]、[replaceTo] 同时使用
|
||||
* @param initiate [HookParam] 方法体
|
||||
*/
|
||||
fun afterHook(initiate: HookParam.() -> Unit) {
|
||||
isReplaceHookMode = false
|
||||
afterHookCallback = initiate
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换此方法内容 - 给出返回值
|
||||
*
|
||||
* 不可与 [beforeHook]、[afterHook] 同时使用
|
||||
* @param initiate [HookParam] 方法体
|
||||
*/
|
||||
fun replaceAny(initiate: HookParam.() -> Any?) {
|
||||
isReplaceHookMode = true
|
||||
replaceHookCallback = initiate
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换此方法内容 - 没有返回值 ([Unit])
|
||||
*
|
||||
* 不可与 [beforeHook]、[afterHook] 同时使用
|
||||
* @param initiate [HookParam] 方法体
|
||||
*/
|
||||
fun replaceUnit(initiate: HookParam.() -> Unit) {
|
||||
isReplaceHookMode = true
|
||||
replaceHookCallback = initiate
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换方法返回值
|
||||
*
|
||||
* 不可与 [beforeHook]、[afterHook] 同时使用
|
||||
* @param any 要替换为的返回值对象
|
||||
*/
|
||||
fun replaceTo(any: Any?) {
|
||||
isReplaceHookMode = true
|
||||
replaceHookCallback = { any }
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换方法返回值为 true
|
||||
*
|
||||
* 确保替换方法的返回对象为 [Boolean]
|
||||
*
|
||||
* 不可与 [beforeHook]、[afterHook] 同时使用
|
||||
*/
|
||||
fun replaceToTrue() {
|
||||
isReplaceHookMode = true
|
||||
replaceHookCallback = { true }
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换方法返回值为 false
|
||||
*
|
||||
* 确保替换方法的返回对象为 [Boolean]
|
||||
*
|
||||
* 不可与 [beforeHook]、[afterHook] 同时使用
|
||||
*/
|
||||
fun replaceToFalse() {
|
||||
isReplaceHookMode = true
|
||||
replaceHookCallback = { false }
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截此方法
|
||||
*
|
||||
* 这将会禁止此方法执行并返回 null
|
||||
*
|
||||
* 不可与 [beforeHook]、[afterHook] 同时使用
|
||||
*/
|
||||
fun intercept() {
|
||||
isReplaceHookMode = true
|
||||
replaceHookCallback = { null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 创建入口 - 不可在外部调用
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun create() = Result()
|
||||
|
||||
/**
|
||||
* Hook 执行入口 - 不可在外部调用
|
||||
* @throws IllegalStateException 如果必要参数没有被设置
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun hook() {
|
||||
if (isStopHookMode) return
|
||||
member?.also { member ->
|
||||
runCatching {
|
||||
if (isReplaceHookMode)
|
||||
XposedBridge.hookMethod(member, object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(baseParam: MethodHookParam?): Any? {
|
||||
if (baseParam == null) return null
|
||||
return HookParam(baseParam).let { param ->
|
||||
try {
|
||||
replaceHookCallback?.invoke(param)
|
||||
} catch (e: Throwable) {
|
||||
onConductFailureCallback?.invoke(param, e)
|
||||
onAllFailureCallback?.invoke(e)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
else
|
||||
XposedBridge.hookMethod(member, object : XC_MethodHook() {
|
||||
override fun beforeHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
runCatching {
|
||||
beforeHookCallback?.invoke(param)
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
runCatching {
|
||||
afterHookCallback?.invoke(param)
|
||||
}.onFailure {
|
||||
onConductFailureCallback?.invoke(param, it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onConductFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}.onFailure {
|
||||
onHookingFailureCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onHookingFailureCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
|
||||
}
|
||||
} ?: error("Hook Member cannot be null")
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 失败但未设置 [onAllFailureCallback] 将默认输出失败信息
|
||||
* @param throwable 异常信息
|
||||
*/
|
||||
private fun onHookFailureMsg(throwable: Throwable) =
|
||||
loggerE(msg = "Try to hook $hookClass[$member] got an Exception", e = throwable)
|
||||
|
||||
override fun toString() = "$member#YukiHook"
|
||||
|
||||
/**
|
||||
* 监听 Hook 结果实现类
|
||||
*
|
||||
* 可在这里处理失败事件监听
|
||||
*/
|
||||
inner class Result {
|
||||
|
||||
/**
|
||||
* 创建监听失败事件方法体
|
||||
* @param initiate 方法体
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun failures(initiate: Result.() -> Unit) = apply(initiate)
|
||||
|
||||
/**
|
||||
* 监听 Hook 进行过程中发生错误的回调方法
|
||||
* @param initiate 回调错误 - ([HookParam] 当前 Hook 实例,[Throwable] 异常)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onConductFailure(initiate: (HookParam, Throwable) -> Unit): Result {
|
||||
onConductFailureCallback = initiate
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听 Hook 开始时发生错误的回调方法
|
||||
* @param initiate 回调错误 - ([Throwable] 异常)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onHookingFailure(initiate: (Throwable) -> Unit): Result {
|
||||
onHookingFailureCallback = initiate
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听 Hook 过程发生找不到方法、变量错误的回调方法
|
||||
* @param initiate 回调错误 - ([Throwable] 异常)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onNoSuchMemberFailure(initiate: (Throwable) -> Unit): Result {
|
||||
onNoSuchMemberCallback = initiate
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听全部 Hook 过程发生错误的回调方法
|
||||
* @param initiate 回调错误 - ([Throwable] 异常)
|
||||
* @return [Result] 可继续向下监听
|
||||
*/
|
||||
fun onAllFailure(initiate: (Throwable) -> Unit): Result {
|
||||
onAllFailureCallback = initiate
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/4.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder
|
||||
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import java.lang.reflect.Constructor
|
||||
|
||||
/**
|
||||
* [Constructor] 查找类
|
||||
*
|
||||
* 可通过指定类型查找指定构造类
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class ConstructorFinder(private val hookClass: Class<*>) {
|
||||
|
||||
/** 方法参数 */
|
||||
private var params: Array<out Class<*>>? = null
|
||||
|
||||
/**
|
||||
* 方法参数
|
||||
* @param param 参数数组
|
||||
*/
|
||||
fun param(vararg param: Class<*>) {
|
||||
params = param
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到构造类 - 不能在外部调用
|
||||
* @return [Constructor]
|
||||
* @throws NoSuchMethodError 如果找不到构造类
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun find(): Constructor<*> =
|
||||
if (params != null)
|
||||
ReflectionUtils.findConstructorExact(hookClass, *params!!)
|
||||
else ReflectionUtils.findConstructorExact(hookClass)
|
||||
}
|
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/4.
|
||||
*/
|
||||
@file:Suppress("unused", "UNCHECKED_CAST", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder
|
||||
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import java.lang.reflect.Field
|
||||
|
||||
/**
|
||||
* Field 查找结果实现类
|
||||
*
|
||||
* 可在这里处理找到的 [fieldInstance]
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class FieldFinder(private val hookClass: Class<*>) {
|
||||
|
||||
/** 当前找到的 [Field] */
|
||||
private var fieldInstance: Field? = null
|
||||
|
||||
/** 变量名 */
|
||||
var name = ""
|
||||
|
||||
/** 变量类型 */
|
||||
var type: Class<*>? = null
|
||||
|
||||
/**
|
||||
* 得到变量处理结果 - 不能在外部调用
|
||||
* @return [Result]
|
||||
* @throws NoSuchFieldError 如果找不到变量
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun find(): Result {
|
||||
fieldInstance = when {
|
||||
name.isBlank() -> error("Field name cannot be empty")
|
||||
else -> ReflectionUtils.findFieldIfExists(hookClass, type?.name, name)
|
||||
}
|
||||
return Result()
|
||||
}
|
||||
|
||||
/**
|
||||
* Field 查找结果实现类
|
||||
*
|
||||
* 可在这里处理找到的 [fieldInstance]
|
||||
*/
|
||||
inner class Result {
|
||||
|
||||
/**
|
||||
* 设置变量实例
|
||||
* @param instance 变量所在的实例对象 - 如果是静态可不填 - 默认 null
|
||||
* @param any 设置的实例内容
|
||||
*/
|
||||
fun set(instance: Any? = null, any: Any?) = give()?.set(instance, any)
|
||||
|
||||
/**
|
||||
* 得到变量实例
|
||||
* @param instance 变量所在的实例对象 - 如果是静态可不填 - 默认 null
|
||||
* @return [T] or null
|
||||
*/
|
||||
fun <T> get(instance: Any? = null) = give()?.get(instance) as? T?
|
||||
|
||||
/**
|
||||
* 得到变量本身
|
||||
* @return [Field] or null
|
||||
*/
|
||||
fun give() = fieldInstance
|
||||
}
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/4.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.core.finder
|
||||
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.utils.ReflectionUtils
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* [Method] 查找类
|
||||
*
|
||||
* 可通过指定类型查找指定方法
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class MethodFinder(private val hookClass: Class<*>) {
|
||||
|
||||
/** 方法参数 */
|
||||
private var params: Array<out Class<*>>? = null
|
||||
|
||||
/** 方法名 */
|
||||
var name = ""
|
||||
|
||||
/** 方法返回值 */
|
||||
var returnType: Class<*>? = null
|
||||
|
||||
/**
|
||||
* 方法参数
|
||||
* @param param 参数数组
|
||||
*/
|
||||
fun param(vararg param: Class<*>) {
|
||||
params = param
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到方法 - 不能在外部调用
|
||||
* @return [Method]
|
||||
* @throws NoSuchMethodError 如果找不到方法
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun find(): Method =
|
||||
when {
|
||||
name.isBlank() -> error("Method name cannot be empty")
|
||||
else ->
|
||||
if (params != null)
|
||||
ReflectionUtils.findMethodBestMatch(hookClass, returnType, name, *params!!)
|
||||
else ReflectionUtils.findMethodNoParam(hookClass, returnType, name)
|
||||
}
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/3.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.entity
|
||||
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.proxy.YukiHookXposedInitProxy
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
|
||||
/**
|
||||
* YukiHook 的子类实现
|
||||
*
|
||||
* 也许你的 Module 中存在多个 Hooker - 继承此类可以方便帮你管理每个 Hooker
|
||||
*
|
||||
* 你可以继续继承此类进行自定义 Hooker 相关参数
|
||||
*
|
||||
* 你可以在 [YukiHookXposedInitProxy] 的 [YukiHookXposedInitProxy.onHook] 中实现如下用法
|
||||
*
|
||||
* 调用 [YukiHookAPI.encase] encase(moduleName = "模块包名", MainHooker(), SecondHooker(), ThirdHooker() ...)
|
||||
*
|
||||
* 调用 [PackageParam.loadHooker] loadHooker(hooker = CustomHooker())
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* 继承类参考示例:
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* class CustomHooker : YukiBaseHooker() {
|
||||
*
|
||||
* ....override fun onHook() {
|
||||
*
|
||||
* ........// Your code here.
|
||||
*
|
||||
* ....}
|
||||
*
|
||||
* }
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* 详情请参考 [YukiHookAPI Wiki](https://github.com/fankes/YukiHookAPI/wiki)
|
||||
*/
|
||||
abstract class YukiBaseHooker : PackageParam() {
|
||||
|
||||
/**
|
||||
* 赋值并克隆一个 [PackageParam]
|
||||
* @param packageParam 需要使用的 [PackageParam]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun assignInstance(packageParam: PackageParam) {
|
||||
baseAssignInstance(packageParam)
|
||||
onHook()
|
||||
}
|
||||
|
||||
/** 子类 Hook 开始 */
|
||||
abstract fun onHook()
|
||||
}
|
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.factory
|
||||
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* 字符串转换为实体类
|
||||
* @return [Class]
|
||||
* @throws NoClassDefFoundError
|
||||
*/
|
||||
val String.clazz: Class<*> get() = Class.forName(this)
|
||||
|
||||
/**
|
||||
* 查找方法是否存在
|
||||
* @param name 名称
|
||||
* @param clazz params
|
||||
* @return [Boolean] 是否存在
|
||||
*/
|
||||
fun Class<*>.hasMethod(name: String, vararg clazz: Class<*>): Boolean =
|
||||
try {
|
||||
getDeclaredMethod(name, *clazz)
|
||||
true
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找静态 [Field] 的实例
|
||||
* @param name 名称
|
||||
* @return [Any] 实例对象
|
||||
* @throws NoSuchFieldError
|
||||
*/
|
||||
fun Class<*>.findStaticField(name: String): Any? = getDeclaredField(name).apply { isAccessible = true }[null]
|
||||
|
||||
/**
|
||||
* 查找 [Field] 的实例 - 不能是静态
|
||||
* @param any 对象
|
||||
* @param name 名称
|
||||
* @return [Any] 实例对象
|
||||
* @throws NoSuchFieldError
|
||||
*/
|
||||
fun Class<*>.findField(any: Any?, name: String): Any? = getDeclaredField(name).apply { isAccessible = true }[any]
|
||||
|
||||
/**
|
||||
* 设置 [Field] - 不能是静态
|
||||
* @param any 对象
|
||||
* @param name 名称
|
||||
* @param value 值
|
||||
* @throws NoSuchFieldError
|
||||
*/
|
||||
fun Class<*>.modifyField(any: Any?, name: String, value: Any?) {
|
||||
getDeclaredField(name).apply {
|
||||
isAccessible = true
|
||||
set(any, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找目标变量
|
||||
* @param name 方法名
|
||||
* @return [Field]
|
||||
* @throws NoSuchFieldError 如果找不到变量会报错
|
||||
*/
|
||||
fun Class<*>.findField(name: String): Field =
|
||||
getDeclaredField(name).apply { isAccessible = true }
|
||||
|
||||
/**
|
||||
* 得到方法
|
||||
* @param name 方法名称
|
||||
* @param clazz params
|
||||
* @return [Method]
|
||||
* @throws NoSuchMethodError
|
||||
*/
|
||||
fun Class<*>.findMethod(name: String, vararg clazz: Class<*>): Method? =
|
||||
getDeclaredMethod(name, *clazz).apply { isAccessible = true }
|
||||
|
||||
/**
|
||||
* 得到构造类
|
||||
* @param parameterTypes params
|
||||
* @return [Constructor]
|
||||
* @throws NoSuchMethodError
|
||||
*/
|
||||
fun Class<*>.findConstructor(vararg parameterTypes: Class<*>?): Constructor<out Any>? =
|
||||
getDeclaredConstructor(*parameterTypes).apply { isAccessible = true }
|
||||
|
||||
/**
|
||||
* 执行方法 - 静态
|
||||
* @param anys 方法参数
|
||||
* @return [T]
|
||||
* @throws IllegalStateException 如果 [T] 类型错误
|
||||
*/
|
||||
inline fun <reified T> Method.invokeStatic(vararg anys: Any) =
|
||||
invoke(null, anys) as? T? ?: error("Method ReturnType cannot cast to ${T::class.java}")
|
||||
|
||||
/**
|
||||
* 执行方法 - 非静态
|
||||
* @param any 目标对象
|
||||
* @param anys 方法参数
|
||||
* @return [T]
|
||||
* @throws IllegalStateException 如果 [T] 类型错误
|
||||
*/
|
||||
inline fun <reified T> Method.invokeAny(any: Any?, vararg anys: Any) =
|
||||
invoke(any, anys) as? T? ?: error("Method ReturnType cannot cast to ${T::class.java}")
|
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.factory
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.proxy.YukiHookXposedInitProxy
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
|
||||
/**
|
||||
* 在 [YukiHookXposedInitProxy] 中装载 [YukiHookAPI]
|
||||
* @param moduleName 模块包名 - 填入当前的 BuildConfig.APPLICATION_ID
|
||||
* @param initiate Hook 方法体
|
||||
*/
|
||||
fun YukiHookXposedInitProxy.encase(moduleName: String = "", initiate: PackageParam.() -> Unit) =
|
||||
YukiHookAPI.encase(moduleName, initiate)
|
||||
|
||||
/**
|
||||
* 在 [YukiHookXposedInitProxy] 中装载 [YukiHookAPI]
|
||||
* @param moduleName 模块包名 - 填入当前的 BuildConfig.APPLICATION_ID
|
||||
* @param hooker Hook 子类数组 - 必填不能为空
|
||||
* @throws IllegalStateException 如果 [hooker] 是空的
|
||||
*/
|
||||
fun YukiHookXposedInitProxy.encase(moduleName: String = "", vararg hooker: YukiBaseHooker) =
|
||||
YukiHookAPI.encase(moduleName, *hooker)
|
||||
|
||||
/**
|
||||
* 判断模块是否在太极、无极中激活
|
||||
* @return [Boolean] 是否激活
|
||||
*/
|
||||
val Context.isTaichiModuleActive: Boolean
|
||||
get() {
|
||||
var isModuleActive = false
|
||||
runCatching {
|
||||
var result: Bundle? = null
|
||||
Uri.parse("content://me.weishu.exposed.CP/").also { uri ->
|
||||
runCatching {
|
||||
result = contentResolver.call(uri, "active", null, null)
|
||||
}.onFailure {
|
||||
// TaiChi is killed, try invoke
|
||||
runCatching {
|
||||
startActivity(Intent("me.weishu.exp.ACTION_ACTIVE").apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
}.onFailure { return false }
|
||||
}
|
||||
if (result == null)
|
||||
result = contentResolver.call(Uri.parse("content://me.weishu.exposed.CP/"), "active", null, null)
|
||||
if (result == null) return false
|
||||
}
|
||||
isModuleActive = result?.getBoolean("active", false) == true
|
||||
}
|
||||
return isModuleActive
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/3.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.log
|
||||
|
||||
import android.util.Log
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - D
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param msg 日志打印的内容
|
||||
*/
|
||||
fun loggerD(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
Log.d(tag, msg)
|
||||
XposedBridge.log("[$tag][D]--> $msg")
|
||||
}
|
||||
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - I
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param msg 日志打印的内容
|
||||
*/
|
||||
fun loggerI(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
Log.i(tag, msg)
|
||||
XposedBridge.log("[$tag][I]--> $msg")
|
||||
}
|
||||
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - W
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param msg 日志打印的内容
|
||||
*/
|
||||
fun loggerW(tag: String = YukiHookAPI.TAG, msg: String) = runCatching {
|
||||
Log.w(tag, msg)
|
||||
XposedBridge.log("[$tag][W]--> $msg")
|
||||
}
|
||||
|
||||
/**
|
||||
* 向控制台和 [XposedBridge] 打印日志 - E
|
||||
*
|
||||
* 你可以对此方法进行二次封装
|
||||
*
|
||||
* [XposedBridge] 中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookAPI.TAG]
|
||||
* @param msg 日志打印的内容
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
*/
|
||||
fun loggerE(tag: String = YukiHookAPI.TAG, msg: String, e: Throwable? = null) = runCatching {
|
||||
Log.e(tag, msg, e)
|
||||
XposedBridge.log("[$tag][E]--> $msg")
|
||||
e?.also { XposedBridge.log(it) }
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.proxy
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.factory.encase
|
||||
|
||||
/**
|
||||
* YukiHook 的 Xposed 装载 API 调用接口
|
||||
*
|
||||
* Hook 开始时将自动调用 [onHook] 方法
|
||||
*
|
||||
* 请在 [onHook] 中调用 [YukiHookAPI.encase] 或直接调用 [encase]
|
||||
*
|
||||
* 可写作如下形式:
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* override fun onHook() = YukiHookAPI.encase(moduleName = "模块包名") {
|
||||
*
|
||||
* ....// Your code here.
|
||||
*
|
||||
* }
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* 还可写作如下形式:
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* override fun onHook() = encase(moduleName = "模块包名") {
|
||||
*
|
||||
* ....// Your code here.
|
||||
*
|
||||
* }
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* 若你喜欢分类创建 Hooker - 还可以这样写:
|
||||
*
|
||||
* ......
|
||||
*
|
||||
* override fun onHook() = encase(moduleName = "模块包名", MainHooker(), SecondHooker(), ThirdHooker() ...)
|
||||
*
|
||||
* ......
|
||||
*
|
||||
* 详情请参考 [YukiHookAPI Wiki](https://github.com/fankes/YukiHookAPI/wiki)
|
||||
*/
|
||||
@Keep
|
||||
interface YukiHookXposedInitProxy {
|
||||
|
||||
/** 模块装载调用入口方法 - Xposed API */
|
||||
@Keep
|
||||
fun onHook()
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.type
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
|
||||
/**
|
||||
* 获得 [Context] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ContextClass get() = Context::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Activity] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ActivityClass get() = Activity::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Service] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ServiceClass get() = Service::class.java
|
||||
|
||||
/**
|
||||
* 获得 [BroadcastReceiver] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val BroadcastReceiverClass get() = BroadcastReceiver::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Bundle] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val BundleClass get() = Bundle::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Resources] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ResourcesClass get() = Resources::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Application] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ApplicationClass get() = Application::class.java
|
@@ -1,104 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.type
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* 获得 [Any] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val AnyType get() = Any::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Unit] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val UnitType get() = Unit::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Boolean] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val BooleanType get() = Boolean::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Int] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val IntType get() = Int::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Long] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val LongType get() = Long::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Short] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ShortType get() = Short::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Float] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val FloatType get() = Float::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [Double] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val DoubleType get() = Double::class.javaPrimitiveType
|
||||
|
||||
/**
|
||||
* 获得 [String] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val StringType get() = String::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Char] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val CharType get() = Char::class.java
|
||||
|
||||
/**
|
||||
* 获得 [CharSequence] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val CharSequenceType get() = CharSequence::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Serializable] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val SerializableClass get() = Serializable::class.java
|
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.type
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
|
||||
/**
|
||||
* 获得 [View] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ViewClass get() = View::class.java
|
||||
|
||||
/**
|
||||
* 获得 [ViewGroup] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ViewGroupClass get() = ViewGroup::class.java
|
||||
|
||||
/**
|
||||
* 获得 [TextView] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val TextViewClass get() = TextView::class.java
|
||||
|
||||
/**
|
||||
* 获得 [ImageView] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ImageViewClass get() = ImageView::class.java
|
||||
|
||||
/**
|
||||
* 获得 [EditText] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val EditTextClass get() = EditText::class.java
|
||||
|
||||
/**
|
||||
* 获得 [Button] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val ButtonClass get() = Button::class.java
|
||||
|
||||
/**
|
||||
* 获得 [CheckBox] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val CheckBoxClass get() = CheckBox::class.java
|
||||
|
||||
/**
|
||||
* 获得 [CompoundButton] 类型
|
||||
* @return [Class]
|
||||
*/
|
||||
val CompoundButtonClass get() = CompoundButton::class.java
|
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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 java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
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();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static <T> T getStaticObjectIfExists(Class<?> clazz, Class<?> fieldType, String fieldName) {
|
||||
return getObjectIfExists(clazz, fieldType, fieldName, null);
|
||||
}
|
||||
|
||||
public static <T> T getObjectIfExists(Class<?> clazz, Class<?> fieldType, String fieldName, Object obj) {
|
||||
return getObjectIfExists(clazz, fieldType.getName(), fieldName, obj);
|
||||
}
|
||||
|
||||
public static <T> T getObjectIfExists(Class<?> clazz, String typeName, String fieldName, Object obj) {
|
||||
try {
|
||||
Field field = findFieldIfExists(clazz, typeName, fieldName);
|
||||
return field == null ? null : (T) field.get(obj);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setStaticObjectField(Class<?> clazz, Class<?> fieldType, String fieldName, Object value)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
findFieldIfExists(clazz, fieldType, fieldName).set(null, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setObjectField(Object obj, Class<?> fieldType, String fieldName, Object value)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
if (obj != null) {
|
||||
Field field = findFieldIfExists(obj.getClass(), fieldType, fieldName);
|
||||
if (field != null) {
|
||||
field.set(obj, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Field findFieldIfExists(Class<?> clazz, Class<?> fieldType, String fieldName)
|
||||
throws NoSuchFieldException {
|
||||
return findFieldIfExists(clazz, fieldType.getName(), fieldName);
|
||||
}
|
||||
|
||||
public static boolean isCallingFrom(String className) {
|
||||
StackTraceElement[] stackTraceElements = Thread.currentThread()
|
||||
.getStackTrace();
|
||||
for (StackTraceElement element : stackTraceElements) {
|
||||
if (element.getClassName()
|
||||
.contains(className)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isCallingFromEither(String... classname) {
|
||||
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
|
||||
for (StackTraceElement element : stackTraceElements) {
|
||||
for (String name : classname) {
|
||||
if (element.toString().contains(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Field findField(Class<?> clazz, String typeName, String fieldName) {
|
||||
try {
|
||||
return findFieldIfExists(clazz, typeName, fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new IllegalArgumentException("Can't find field <" + clazz.getName() + "#" + typeName + "#" + fieldName + ">");
|
||||
}
|
||||
}
|
||||
|
||||
public static Field findFieldIfExists(Class<?> clazz, String typeName, String fieldName)
|
||||
throws NoSuchFieldException {
|
||||
String fullFieldName = clazz.getName() + "#" + fieldName + "#" + typeName;
|
||||
|
||||
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(clazz.getName() + "#" + typeName + " " + fieldName);
|
||||
}
|
||||
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 方法名
|
||||
*/
|
||||
public static Method findMethodNoParam(Class<?> clazz, Class<?> returnType, String methodName) {
|
||||
String fullMethodName = clazz.getName() + '#' + methodName + returnType + "#exact#NoParam";
|
||||
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 方法参数类型数组
|
||||
*/
|
||||
public static Method findMethodBestMatch(Class<?> clazz, Class<?> returnType, String methodName, Class<?>... parameterTypes) {
|
||||
String fullMethodName = clazz.getName() + '#' + methodName + returnType + getParametersString(parameterTypes) + "#exact";
|
||||
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 构造类方法参数类型数组
|
||||
*/
|
||||
public static Constructor<?> findConstructorExact(Class<?> clazz, Class<?>... parameterTypes) {
|
||||
String fullConstructorName = clazz.getName() + getParametersString(parameterTypes) + "#exact";
|
||||
try {
|
||||
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
|
||||
constructor.setAccessible(true);
|
||||
return constructor;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError("Can't find constructor " + fullConstructorName);
|
||||
}
|
||||
}
|
||||
|
||||
private static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
|
||||
String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#zYukiHook#exact";
|
||||
try {
|
||||
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError("Can't find 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 = XposedHelpers.findMethodsByExactParameters(clazz, returnType, parameterTypes);
|
||||
for (Method method : methods) if (method.getName().equals(methodName)) return method;
|
||||
} while ((clz = clz.getSuperclass()) != null);
|
||||
}
|
||||
throw new IllegalArgumentException("Method not found <name:" + methodName + " returnType:" + returnType.getName() + " paramType:" + getParametersString(parameterTypes) + "> in Class <" + clazz.getName() + ">");
|
||||
}
|
||||
}
|
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.xposed
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||
import com.highcapable.yukihookapi.hook.factory.clazz
|
||||
import com.highcapable.yukihookapi.hook.factory.findConstructor
|
||||
import com.highcapable.yukihookapi.hook.factory.findMethod
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.proxy.YukiHookXposedInitProxy
|
||||
import com.highcapable.yukihookapi.hook.type.BooleanType
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
import de.robv.android.xposed.IXposedHookLoadPackage
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||
|
||||
/**
|
||||
* 接管 Xposed 的 [IXposedHookLoadPackage] 入口
|
||||
*
|
||||
* 你可以使用 [YukiHookAPI.encase] 或在 [YukiHookXposedInitProxy] 中监听模块开始装载
|
||||
*
|
||||
* 需要标识 Hook 入口的类 - 请声明注释 [InjectYukiHookWithXposed]
|
||||
*/
|
||||
@Keep
|
||||
class YukiHookLoadPackage : IXposedHookLoadPackage {
|
||||
|
||||
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
|
||||
if (lpparam == null) return
|
||||
runCatching {
|
||||
/** 执行入口方法 */
|
||||
hookEntryClassName().clazz.apply {
|
||||
findMethod(name = "onHook")?.invoke(findConstructor()?.newInstance())
|
||||
}
|
||||
}.onFailure {
|
||||
loggerE(msg = "Try to load ${hookEntryClassName()} Failed", e = it)
|
||||
}
|
||||
/** 装载 APP Hook 实体类 */
|
||||
PackageParam(lpparam).apply {
|
||||
/** Hook 模块激活状态 */
|
||||
loadApp(name = YukiHookAPI.modulePackageName) {
|
||||
YukiHookModuleStatus::class.java.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "isActive"
|
||||
returnType = BooleanType
|
||||
}
|
||||
replaceToTrue()
|
||||
}.onAllFailure { loggerE(msg = "Try to Hook ModuleStatus Failed", e = it) }
|
||||
}
|
||||
}
|
||||
/** 设置装载回调 */
|
||||
YukiHookAPI.packageParamCallback?.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得目标装载类名 - 通过 APT 自动设置 TODO 待实现
|
||||
* @return [String] 目标装载类名
|
||||
*/
|
||||
@Keep
|
||||
private fun hookEntryClassName() = "com.highcapable.yukihookapi.demo.hook.inject.MainInjecter"
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/3.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.xposed
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.highcapable.yukihookapi.hook.log.loggerI
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus.isActive
|
||||
|
||||
/**
|
||||
* 这是一个 Xposed 模块 Hook 状态类
|
||||
*
|
||||
* 我们需要监听自己的模块是否被激活 - 可直接调用这个类的 [isActive] 方法
|
||||
*/
|
||||
@Keep
|
||||
object YukiHookModuleStatus {
|
||||
|
||||
/**
|
||||
* 此方法经过 Hook 后返回 true 即模块已激活
|
||||
* @return [Boolean]
|
||||
*/
|
||||
@Keep
|
||||
fun isActive(): Boolean {
|
||||
loggerI(msg = "This Module is not actived")
|
||||
return false
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.param
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
|
||||
/**
|
||||
* 自定义 [PackageParam] 的装载入口置换类
|
||||
* @param appClassLoader APP [ClassLoader]
|
||||
* @param appInfo APP [ApplicationInfo]
|
||||
* @param packageName 包名
|
||||
*/
|
||||
class CustomParam(
|
||||
var appClassLoader: ClassLoader,
|
||||
var appInfo: ApplicationInfo,
|
||||
var packageName: String
|
||||
)
|
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.param
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* Hook 方法、构造类的目标对象实现类
|
||||
* @param baseParam 对接 Xposed API 的 [XC_MethodHook.MethodHookParam]
|
||||
*/
|
||||
class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数对象数组
|
||||
* @return [Array]
|
||||
*/
|
||||
val args get() = baseParam.args ?: arrayOf(0)
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数对象数组第一位
|
||||
* @return [Array]
|
||||
* @throws IllegalStateException 如果数组为空或对象为空
|
||||
*/
|
||||
val firstArgs get() = args[0] ?: error("HookParam args[0] with a non-null object")
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数对象数组最后一位
|
||||
* @return [Array]
|
||||
* @throws IllegalStateException 如果数组为空或对象为空
|
||||
*/
|
||||
val lastArgs get() = args[args.lastIndex] ?: error("HookParam args[lastIndex] with a non-null object")
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 实例的对象
|
||||
* @return [Any]
|
||||
* @throws IllegalStateException 如果对象为空
|
||||
*/
|
||||
val instance get() = baseParam.thisObject ?: error("HookParam must with a non-null object")
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 实例的类对象
|
||||
* @return [Class]
|
||||
*/
|
||||
val instanceClass get() = instance.javaClass
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 的方法
|
||||
* @return [Method]
|
||||
* @throws IllegalStateException 如果方法为空或方法类型不是 [Method]
|
||||
*/
|
||||
val method get() = baseParam.method as? Method? ?: error("Current hook method type is wrong or null")
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 的构造方法
|
||||
* @return [Constructor]
|
||||
* @throws IllegalStateException 如果方法为空或方法类型不是 [Constructor]
|
||||
*/
|
||||
val constructor get() = baseParam.method as? Constructor<*>? ?: error("Current hook constructor type is wrong or null")
|
||||
|
||||
/**
|
||||
* 获取、设置当前 [method] or [constructor] 的返回值
|
||||
* @return [Any] or null
|
||||
*/
|
||||
var result: Any?
|
||||
get() = baseParam.result
|
||||
set(value) {
|
||||
baseParam.result = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 实例的对象 [T]
|
||||
* @return [T]
|
||||
* @throws IllegalStateException 如果对象为空或对象类型不是 [T]
|
||||
*/
|
||||
inline fun <reified T> instance() = instance as? T? ?: error("HookParam object cannot cast to ${T::class.java.name}")
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数实例化对象类
|
||||
* @param index 参数对象数组下标 - 默认是 0
|
||||
* @return [ArgsModifyer]
|
||||
*/
|
||||
fun args(index: Int = 0) = ArgsModifyer(index)
|
||||
|
||||
/**
|
||||
* 设置 [result] 返回值为 true
|
||||
*
|
||||
* 请确保返回值类型为 [Boolean]
|
||||
*/
|
||||
fun resultTrue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 [result] 返回值为 false
|
||||
*
|
||||
* 请确保返回值类型为 [Boolean]
|
||||
*/
|
||||
fun resultFalse() {
|
||||
result = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置返回值为 null
|
||||
*
|
||||
* 此方法将强制设置方法体的 [result] 为 null
|
||||
*/
|
||||
fun resultNull() {
|
||||
result = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 对方法参数的修改进行实例化类
|
||||
* @param index 参数对象数组下标
|
||||
*/
|
||||
inner class ArgsModifyer(private val index: Int) {
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象
|
||||
* @param any 实例对象
|
||||
* @throws IllegalStateException 如果目标方法参数对象数组为空或 [index] 下标不存在
|
||||
*/
|
||||
fun <T> set(any: T?) {
|
||||
if (args.isEmpty()) error("HookParam method args is empty,mabe not has args")
|
||||
if (index > args.lastIndex) error("HookParam method args index out of bounds,max is ${args.lastIndex}")
|
||||
baseParam.args[index] = any
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象为 null
|
||||
*
|
||||
* 此方法可以将任何被 Hook 的目标对象设置为空
|
||||
*/
|
||||
fun setNull() = set(null)
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象为 true
|
||||
*
|
||||
* 请确保目标对象的类型是 [Boolean] 不然会发生意想不到的问题
|
||||
*/
|
||||
fun setTrue() = set(true)
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象为 false
|
||||
*
|
||||
* 请确保目标对象的类型是 [Boolean] 不然会发生意想不到的问题
|
||||
*/
|
||||
fun setFalse() = set(false)
|
||||
}
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 HighCapable
|
||||
*
|
||||
* This file is part of YukiHookAPI.
|
||||
*
|
||||
* 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/2/2.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package com.highcapable.yukihookapi.param
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||
|
||||
/**
|
||||
* 装载 Hook 的目标 APP 入口对象实现类
|
||||
*
|
||||
* 如果你想将 YukiHook 作为 Hook API 使用 - 你可自定义 [customParam]
|
||||
*
|
||||
* ⚠️ 特别注意如果 [baseParam] 和 [customParam] 都为空将发生问题
|
||||
* @param baseParam 对接 Xposed API 的 [XC_LoadPackage.LoadPackageParam] - 默认空
|
||||
* @param customParam 自定义装载类 - 默认空
|
||||
*/
|
||||
open class PackageParam(
|
||||
private var baseParam: XC_LoadPackage.LoadPackageParam? = null,
|
||||
private var customParam: CustomParam? = null
|
||||
) {
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的 [ClassLoader]
|
||||
* @return [ClassLoader]
|
||||
* @throws IllegalStateException 如果 [ClassLoader] 是空的
|
||||
*/
|
||||
val appClassLoader
|
||||
get() = baseParam?.classLoader ?: customParam?.appClassLoader ?: javaClass.classLoader
|
||||
?: error("PackageParam ClassLoader is null")
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的 [ApplicationInfo]
|
||||
* @return [ApplicationInfo]
|
||||
*/
|
||||
val appInfo get() = baseParam?.appInfo ?: customParam?.appInfo ?: ApplicationInfo()
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的进程名称
|
||||
*
|
||||
* 默认的进程名称是 [packageName] 如果自定义了 [customParam] 将返回包名
|
||||
* @return [String]
|
||||
*/
|
||||
val processName get() = baseParam?.processName ?: customParam?.packageName ?: ""
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的包名
|
||||
* @return [String]
|
||||
*/
|
||||
val packageName get() = baseParam?.packageName ?: customParam?.packageName ?: ""
|
||||
|
||||
/**
|
||||
* 获取当前 APP 是否为第一个 Application
|
||||
*
|
||||
* 若自定义了 [customParam] 将永远返回 true
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val isFirstApplication get() = baseParam?.isFirstApplication ?: true
|
||||
|
||||
/**
|
||||
* 赋值并克隆另一个 [PackageParam]
|
||||
* @param another 另一个 [PackageParam]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun baseAssignInstance(another: PackageParam) {
|
||||
this.baseParam = another.baseParam
|
||||
this.customParam = another.customParam
|
||||
}
|
||||
|
||||
/**
|
||||
* 装载并 Hook 指定包名的 APP
|
||||
* @param name 包名
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun loadApp(name: String, initiate: PackageParam.() -> Unit) {
|
||||
if (packageName == name) initiate(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 装载 Hook 子类
|
||||
*
|
||||
* 你可以在 Hooker 中继续装载 Hooker
|
||||
* @param hooker Hook 子类
|
||||
*/
|
||||
fun loadHooker(hooker: YukiBaseHooker) = hooker.assignInstance(packageParam = this)
|
||||
|
||||
/**
|
||||
* 将目标 [Class] 绑定到 [appClassLoader]
|
||||
*
|
||||
* ⚠️ 请注意未绑定到 [appClassLoader] 的 [Class] 不能被装载 - 调用 [hook] 方法会自动绑定
|
||||
* @return [Class]
|
||||
* @throws NoClassDefFoundError 如果找不到类会报错
|
||||
*/
|
||||
fun Class<*>.bind(): Class<*> = appClassLoader.loadClass(name)
|
||||
|
||||
/**
|
||||
* 通过 [appClassLoader] 查询并装载 [Class]
|
||||
* @param name 类名
|
||||
* @return [Class]
|
||||
* @throws NoClassDefFoundError 如果找不到类会报错
|
||||
*/
|
||||
fun findClass(name: String): Class<*> = appClassLoader.loadClass(name)
|
||||
|
||||
/**
|
||||
* Hook 方法、构造类
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun Class<*>.hook(initiate: YukiHookCreater.() -> Unit) =
|
||||
YukiHookCreater(packageParam = this@PackageParam, hookClass = bind()).apply(initiate).hook()
|
||||
}
|
Reference in New Issue
Block a user