mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-01 08:15:37 +08:00
...
This commit is contained in:
117
.idea/codeStyles/Project.xml
generated
Normal file
117
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,117 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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/9.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.bean
|
||||
|
||||
/**
|
||||
* 自适应异常 [Class] 接管类
|
||||
* @param instance 实例
|
||||
* @param name 完整名称
|
||||
* @param throwable 异常
|
||||
*/
|
||||
class HookClass(
|
||||
var instance: Class<*>? = null,
|
||||
var name: String,
|
||||
var throwable: Throwable? = null
|
||||
)
|
@@ -31,6 +31,7 @@ package com.highcapable.yukihookapi.hook.core
|
||||
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.bean.HookClass
|
||||
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
|
||||
@@ -38,6 +39,7 @@ import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.log.loggerI
|
||||
import com.highcapable.yukihookapi.hook.param.HookParam
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import de.robv.android.xposed.XC_MethodReplacement
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
@@ -49,9 +51,9 @@ import java.lang.reflect.Member
|
||||
*
|
||||
* 这是一个 API 对接类 - 实现原生对接 [XposedBridge]
|
||||
* @param packageParam 需要传入 [PackageParam] 实现方法调用
|
||||
* @param hookClass 要 Hook 的 [Class] - 必须使用当前 Hook APP 的 [ClassLoader] 装载
|
||||
* @param hookClass 要 Hook 的 [HookClass] 实例
|
||||
*/
|
||||
class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Class<*>) {
|
||||
class YukiHookCreater(private val packageParam: PackageParam, private val hookClass: HookClass) {
|
||||
|
||||
/**
|
||||
* Hook 全部方法的标识
|
||||
@@ -61,6 +63,16 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
/** 设置要 Hook 的方法、构造类 */
|
||||
private var hookMembers = HashMap<String, MemberHookCreater>()
|
||||
|
||||
/**
|
||||
* 得到当前被 Hook 的 [Class]
|
||||
*
|
||||
* - ❗不推荐直接使用 - 万一得不到 [Class] 对象则会无法处理异常导致崩溃
|
||||
* @return [Class]
|
||||
* @throws IllegalStateException 如果当前 [Class] 未被正确装载
|
||||
*/
|
||||
val thisClass
|
||||
get() = hookClass.instance ?: error("Cannot get hook class \"${hookClass.name}\" cause ${hookClass.throwable?.message}")
|
||||
|
||||
/**
|
||||
* 注入要 Hook 的方法、构造类
|
||||
* @param tag 可设置标签 - 在发生错误时方便进行调试
|
||||
@@ -164,9 +176,10 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* @return [MethodFinder.Result]
|
||||
*/
|
||||
fun method(initiate: MethodFinder.() -> Unit): MethodFinder.Result {
|
||||
if (hookClass.instance == null) return MethodFinder(hookInstance = this).failure(hookClass.throwable)
|
||||
hookAllMembers = HookAllMembers.HOOK_NONE
|
||||
isHookMemberSetup = true
|
||||
return MethodFinder(hookInstance = this, hookClass).apply(initiate).build()
|
||||
return MethodFinder(hookInstance = this, hookClass.instance).apply(initiate).build()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,9 +190,10 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* @return [ConstructorFinder.Result]
|
||||
*/
|
||||
fun constructor(initiate: ConstructorFinder.() -> Unit = {}): ConstructorFinder.Result {
|
||||
if (hookClass.instance == null) return ConstructorFinder(hookInstance = this).failure(hookClass.throwable)
|
||||
hookAllMembers = HookAllMembers.HOOK_NONE
|
||||
isHookMemberSetup = true
|
||||
return ConstructorFinder(hookInstance = this, hookClass).apply(initiate).build()
|
||||
return ConstructorFinder(hookInstance = this, hookClass.instance).apply(initiate).build()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +202,8 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
* @return [FieldFinder.Result]
|
||||
*/
|
||||
fun HookParam.field(initiate: FieldFinder.() -> Unit) =
|
||||
FieldFinder(hookInstance = this@MemberHookCreater, hookClass).apply(initiate).build()
|
||||
if (hookClass.instance == null) FieldFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable)
|
||||
else FieldFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 在方法执行完成前 Hook
|
||||
@@ -298,11 +313,20 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
@DoNotUseMethod
|
||||
fun hook() {
|
||||
if (!YukiHookAPI.hasXposedBridge) return
|
||||
if (hookClass.instance == null) {
|
||||
(hookClass.throwable ?: Throwable("Failed Hooked Class [${hookClass.name}]")).also {
|
||||
onHookingFailureCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (onHookingFailureCallback == null && onAllFailureCallback == null)
|
||||
onHookFailureMsg(it)
|
||||
}
|
||||
return
|
||||
}
|
||||
/** 定义替换 Hook 回调方法体 */
|
||||
val replaceMent = object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(baseParam: MethodHookParam?): Any? {
|
||||
if (baseParam == null) return null
|
||||
return HookParam(baseParam).let { param ->
|
||||
return HookParam(HookParamWrapper(baseParam)).let { param ->
|
||||
try {
|
||||
if (replaceHookCallback != null)
|
||||
onHookLogMsg(msg = "Replace Hook Member [${member ?: "All Member $allMethodsName"}] done [$tag]")
|
||||
@@ -322,7 +346,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
val beforeAfterHook = object : XC_MethodHook() {
|
||||
override fun beforeHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
HookParam(HookParamWrapper(baseParam)).also { param ->
|
||||
runCatching {
|
||||
beforeHookCallback?.invoke(param)
|
||||
if (beforeHookCallback != null)
|
||||
@@ -338,7 +362,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
|
||||
override fun afterHookedMethod(baseParam: MethodHookParam?) {
|
||||
if (baseParam == null) return
|
||||
HookParam(baseParam).also { param ->
|
||||
HookParam(HookParamWrapper(baseParam)).also { param ->
|
||||
runCatching {
|
||||
afterHookCallback?.invoke(param)
|
||||
if (afterHookCallback != null)
|
||||
@@ -379,12 +403,12 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
|
||||
when (hookAllMembers) {
|
||||
HookAllMembers.HOOK_ALL_METHODS ->
|
||||
if (isReplaceHookMode)
|
||||
XposedBridge.hookAllMethods(hookClass, allMethodsName, replaceMent)
|
||||
else XposedBridge.hookAllMethods(hookClass, allMethodsName, beforeAfterHook)
|
||||
XposedBridge.hookAllMethods(hookClass.instance, allMethodsName, replaceMent)
|
||||
else XposedBridge.hookAllMethods(hookClass.instance, allMethodsName, beforeAfterHook)
|
||||
HookAllMembers.HOOK_ALL_CONSTRUCTORS ->
|
||||
if (isReplaceHookMode)
|
||||
XposedBridge.hookAllConstructors(hookClass, replaceMent)
|
||||
else XposedBridge.hookAllConstructors(hookClass, beforeAfterHook)
|
||||
XposedBridge.hookAllConstructors(hookClass.instance, replaceMent)
|
||||
else XposedBridge.hookAllConstructors(hookClass.instance, beforeAfterHook)
|
||||
else -> error("Hooked got a no error possible")
|
||||
}
|
||||
}.onFailure {
|
||||
|
@@ -44,7 +44,7 @@ import java.lang.reflect.Constructor
|
||||
* @param hookInstance 当前 Hook 实例
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
|
||||
class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) {
|
||||
|
||||
/** [Constructor] 参数数组 */
|
||||
private var params: Array<out Class<*>>? = null
|
||||
@@ -91,6 +91,16 @@ class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCrea
|
||||
Result(isNoSuch = true, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个异常结果
|
||||
*
|
||||
* - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @param throwable 异常
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
|
||||
|
||||
/**
|
||||
* 发生错误时输出日志
|
||||
* @param msg 消息日志
|
||||
|
@@ -43,7 +43,7 @@ import java.lang.reflect.Field
|
||||
* @param hookInstance 当前 Hook 实例
|
||||
* @param hookClass 当前被 Hook 的 [Class]
|
||||
*/
|
||||
class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
|
||||
class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) {
|
||||
|
||||
/** 当前找到的 [Field] */
|
||||
private var fieldInstance: Field? = null
|
||||
@@ -85,6 +85,16 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p
|
||||
Result(isNoSuch = true, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个异常结果
|
||||
*
|
||||
* - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @param throwable 异常
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
|
||||
|
||||
/**
|
||||
* Field 查找结果实现类
|
||||
*
|
||||
|
@@ -44,7 +44,7 @@ import java.lang.reflect.Method
|
||||
* @param hookInstance 当前 Hook 实例
|
||||
* @param hookClass 当前 Hook 的 Class
|
||||
*/
|
||||
class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
|
||||
class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>? = null) {
|
||||
|
||||
/** [Method] 参数数组 */
|
||||
private var params: Array<out Class<*>>? = null
|
||||
@@ -109,6 +109,16 @@ class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater,
|
||||
Result(isNoSuch = true, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个异常结果
|
||||
*
|
||||
* - ❗此功能交由方法体自动完成 - 你不应该手动调用此方法
|
||||
* @param throwable 异常
|
||||
* @return [Result]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
fun failure(throwable: Throwable?) = Result(isNoSuch = true, throwable)
|
||||
|
||||
/**
|
||||
* 发生错误时输出日志
|
||||
* @param msg 消息日志
|
||||
|
@@ -29,6 +29,7 @@
|
||||
|
||||
package com.highcapable.yukihookapi.hook.factory
|
||||
|
||||
import com.highcapable.yukihookapi.hook.bean.HookClass
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
@@ -52,6 +53,18 @@ val String.hasClass
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* [Class] 转换为 [HookClass]
|
||||
* @return [HookClass]
|
||||
*/
|
||||
val Class<*>.hookClass get() = HookClass(instance = this, name)
|
||||
|
||||
/**
|
||||
* [HookClass] 转换为 [Class]
|
||||
* @return [Class] or null
|
||||
*/
|
||||
val HookClass.clazz get() = instance
|
||||
|
||||
/**
|
||||
* 查找方法是否存在
|
||||
* @param name 名称
|
||||
|
@@ -29,42 +29,46 @@
|
||||
|
||||
package com.highcapable.yukihookapi.hook.param
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* Hook 方法、构造类的目标对象实现类
|
||||
* @param baseParam 对接 Xposed API 的 [XC_MethodHook.MethodHookParam]
|
||||
* @param wrapper [HookParam] 的参数包装类实例
|
||||
*/
|
||||
class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
|
||||
class HookParam(private val wrapper: HookParamWrapper) {
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数对象数组
|
||||
* 获取当前 [member] or [constructor] 的参数对象数组
|
||||
* @return [Array]
|
||||
*/
|
||||
val args get() = baseParam.args ?: arrayOf(0)
|
||||
val args get() = wrapper.args ?: arrayOf(0)
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数对象数组第一位
|
||||
* 获取当前 [member] or [constructor] 的参数对象数组第一位
|
||||
* @return [Array]
|
||||
* @throws IllegalStateException 如果数组为空或对象为空
|
||||
*/
|
||||
val firstArgs get() = args[0] ?: error("HookParam args[0] with a non-null object")
|
||||
val firstArgs
|
||||
get() = if (args.isNotEmpty()) args[0] ?: error("HookParam args[0] with a non-null object")
|
||||
else error("HookParam args is empty")
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数对象数组最后一位
|
||||
* 获取当前 [member] or [constructor] 的参数对象数组最后一位
|
||||
* @return [Array]
|
||||
* @throws IllegalStateException 如果数组为空或对象为空
|
||||
*/
|
||||
val lastArgs get() = args[args.lastIndex] ?: error("HookParam args[lastIndex] with a non-null object")
|
||||
val lastArgs
|
||||
get() = if (args.isNotEmpty()) args[args.lastIndex] ?: error("HookParam args[lastIndex] with a non-null object")
|
||||
else error("HookParam args is empty")
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 实例的对象
|
||||
* @return [Any]
|
||||
* @throws IllegalStateException 如果对象为空
|
||||
*/
|
||||
val instance get() = baseParam.thisObject ?: error("HookParam must with a non-null object")
|
||||
val instance get() = wrapper.instance ?: error("HookParam must with a non-null instance")
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 实例的类对象
|
||||
@@ -73,27 +77,27 @@ class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
|
||||
val instanceClass get() = instance.javaClass
|
||||
|
||||
/**
|
||||
* 获取当前 Hook 的方法
|
||||
* @return [Method]
|
||||
* @throws IllegalStateException 如果方法为空或方法类型不是 [Method]
|
||||
* 获取当前 Hook 的方法、构造方法
|
||||
* @return [Member]
|
||||
* @throws IllegalStateException 如果 [Member] 是空的
|
||||
*/
|
||||
val method get() = baseParam.method as? Method? ?: error("Current hook method type is wrong or null")
|
||||
val member get() = wrapper.member ?: error("Current hook member 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")
|
||||
val constructor get() = wrapper.member as? Constructor<*>? ?: error("Current hook constructor type is wrong or null")
|
||||
|
||||
/**
|
||||
* 获取、设置当前 [method] or [constructor] 的返回值
|
||||
* 获取、设置当前 [member] or [constructor] 的返回值
|
||||
* @return [Any] or null
|
||||
*/
|
||||
var result: Any?
|
||||
get() = baseParam.result
|
||||
get() = wrapper.result
|
||||
set(value) {
|
||||
baseParam.result = value
|
||||
wrapper.result = value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,10 +105,10 @@ class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
|
||||
* @return [T]
|
||||
* @throws IllegalStateException 如果对象为空或对象类型不是 [T]
|
||||
*/
|
||||
inline fun <reified T> instance() = instance as? T? ?: error("HookParam object cannot cast to ${T::class.java.name}")
|
||||
inline fun <reified T> instance() = instance as? T? ?: error("HookParam instance cannot cast to ${T::class.java.name}")
|
||||
|
||||
/**
|
||||
* 获取当前 [method] or [constructor] 的参数实例化对象类
|
||||
* 获取当前 [member] or [constructor] 的参数实例化对象类
|
||||
* @param index 参数对象数组下标 - 默认是 0
|
||||
* @return [ArgsModifyer]
|
||||
*/
|
||||
@@ -151,7 +155,7 @@ class HookParam(private val baseParam: XC_MethodHook.MethodHookParam) {
|
||||
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
|
||||
wrapper.setArgs(index, any)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -31,16 +31,18 @@ package com.highcapable.yukihookapi.hook.param
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
|
||||
import com.highcapable.yukihookapi.hook.bean.HookClass
|
||||
import com.highcapable.yukihookapi.hook.core.YukiHookCreater
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.factory.hookClass
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
|
||||
|
||||
/**
|
||||
* 装载 Hook 的目标 APP 入口对象实现类
|
||||
* @param baseParam [PackageParam] 的参数包装类实例 - 默认是空的
|
||||
* @param wrapper [PackageParam] 的参数包装类实例 - 默认是空的
|
||||
*/
|
||||
open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
|
||||
open class PackageParam(private var wrapper: PackageParamWrapper? = null) {
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的 [ClassLoader]
|
||||
@@ -48,13 +50,13 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
|
||||
* @throws IllegalStateException 如果 [ClassLoader] 是空的
|
||||
*/
|
||||
val appClassLoader
|
||||
get() = baseParam?.appClassLoader ?: javaClass.classLoader ?: error("PackageParam got null ClassLoader")
|
||||
get() = wrapper?.appClassLoader ?: javaClass.classLoader ?: error("PackageParam got null ClassLoader")
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的 [ApplicationInfo]
|
||||
* @return [ApplicationInfo]
|
||||
*/
|
||||
val appInfo get() = baseParam?.appInfo ?: ApplicationInfo()
|
||||
val appInfo get() = wrapper?.appInfo ?: ApplicationInfo()
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的进程名称
|
||||
@@ -62,13 +64,13 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
|
||||
* 默认的进程名称是 [packageName]
|
||||
* @return [String]
|
||||
*/
|
||||
val processName get() = baseParam?.processName ?: packageName
|
||||
val processName get() = wrapper?.processName ?: packageName
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的包名
|
||||
* @return [String]
|
||||
*/
|
||||
val packageName get() = baseParam?.packageName ?: ""
|
||||
val packageName get() = wrapper?.packageName ?: ""
|
||||
|
||||
/**
|
||||
* 获取当前 APP 是否为第一个 Application
|
||||
@@ -78,20 +80,26 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
|
||||
|
||||
/**
|
||||
* 获得当前使用的存取数据对象缓存实例
|
||||
*
|
||||
* @return [YukiHookModulePrefs]
|
||||
*/
|
||||
val prefs by lazy { YukiHookModulePrefs() }
|
||||
|
||||
/**
|
||||
* 获得当前使用的存取数据对象缓存实例
|
||||
* @param name 自定义 Sp 存储名称
|
||||
* @return [YukiHookModulePrefs]
|
||||
*/
|
||||
fun prefs(name: String) = prefs.name(name)
|
||||
|
||||
/**
|
||||
* 赋值并克隆另一个 [PackageParam]
|
||||
*
|
||||
* - ❗此方法为私有功能性 API - 你不应该手动调用此方法
|
||||
* @param another 另一个 [PackageParam]
|
||||
* @param anotherParam 另一个 [PackageParam]
|
||||
*/
|
||||
@DoNotUseMethod
|
||||
internal fun baseAssignInstance(another: PackageParam) {
|
||||
this.baseParam = another.baseParam
|
||||
internal fun baseAssignInstance(anotherParam: PackageParam) {
|
||||
thisParam.wrapper = anotherParam.wrapper
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,27 +119,46 @@ open class PackageParam(private var baseParam: PackageParamWrapper? = null) {
|
||||
*/
|
||||
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 如果找不到类会报错
|
||||
* @return [HookClass]
|
||||
*/
|
||||
fun findClass(name: String): Class<*> = appClassLoader.loadClass(name)
|
||||
fun findClass(name: String) = try {
|
||||
appClassLoader.loadClass(name).hookClass
|
||||
} catch (e: Throwable) {
|
||||
HookClass(name = name, throwable = e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 方法、构造类
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun Class<*>.hook(initiate: YukiHookCreater.() -> Unit) =
|
||||
YukiHookCreater(packageParam = this@PackageParam, hookClass = bind()).apply(initiate).hook()
|
||||
YukiHookCreater(packageParam = thisParam, hookClass = hookClass.bind()).apply(initiate).hook()
|
||||
|
||||
/**
|
||||
* Hook 方法、构造类
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
fun HookClass.hook(initiate: YukiHookCreater.() -> Unit) =
|
||||
YukiHookCreater(packageParam = thisParam, hookClass = bind()).apply(initiate).hook()
|
||||
|
||||
/**
|
||||
* 将目标 [Class] 绑定到 [appClassLoader]
|
||||
*
|
||||
* - ❗请注意未绑定到 [appClassLoader] 的 [Class] 不能被装载 - 调用 [hook] 方法会自动绑定
|
||||
* @return [HookClass]
|
||||
*/
|
||||
private fun HookClass.bind() = try {
|
||||
appClassLoader.loadClass(name).hookClass
|
||||
} catch (e: Throwable) {
|
||||
HookClass(name = name, throwable = e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回自身实例
|
||||
* @return [PackageParam]
|
||||
*/
|
||||
private val thisParam get() = this
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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/9.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.param.wrapper
|
||||
|
||||
import com.highcapable.yukihookapi.hook.param.HookParam
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
* 用于包装 [HookParam]
|
||||
* @param baseParam 对接 [XC_MethodHook.MethodHookParam]
|
||||
*/
|
||||
class HookParamWrapper(private val baseParam: XC_MethodHook.MethodHookParam) {
|
||||
|
||||
/**
|
||||
* [Member] 实例
|
||||
* @return [Member] or null
|
||||
*/
|
||||
val member: Member? get() = baseParam.method
|
||||
|
||||
/**
|
||||
* 当前实例对象
|
||||
* @return [Any] or null
|
||||
*/
|
||||
val instance: Any? get() = baseParam.thisObject
|
||||
|
||||
/**
|
||||
* 方法、构造方法数组
|
||||
* @return [Array] or null
|
||||
*/
|
||||
val args: Array<Any?>? get() = baseParam.args
|
||||
|
||||
/**
|
||||
* 方法、设置方法结果
|
||||
* @return [Any] or null
|
||||
*/
|
||||
var result: Any?
|
||||
get() = baseParam.result
|
||||
set(value) {
|
||||
baseParam.result = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方法参数
|
||||
* @param index 数组下标
|
||||
* @param any 参数对象实例
|
||||
*/
|
||||
fun setArgs(index: Int, any: Any?) {
|
||||
baseParam.args[index] = any
|
||||
}
|
||||
}
|
@@ -51,15 +51,15 @@ import java.io.File
|
||||
*
|
||||
* - 详见 [New XSharedPreferences](https://github.com/LSPosed/LSPosed/wiki/New-XSharedPreferences#for-the-module)
|
||||
*
|
||||
* - 未使用 LSposed 环境请将你的模块 API 降至 26 以下 - YukiHookAPI 将会尝试使用 [makeWorldReadable] 但仍有可能不成功
|
||||
* - 未使用 LSPosed 环境请将你的模块 API 降至 26 以下 - YukiHookAPI 将会尝试使用 [makeWorldReadable] 但仍有可能不成功
|
||||
*
|
||||
* - ❗当你在模块中存取数据的时候 [context] 必须不能是空的
|
||||
* @param context 上下文实例 - 默认空
|
||||
*/
|
||||
class YukiHookModulePrefs(private val context: Context? = null) {
|
||||
|
||||
/** 存储名称 - 包名 + _preferences */
|
||||
private val prefsName get() = "${YukiHookAPI.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences"
|
||||
/** 存储名称 - 默认包名 + _preferences */
|
||||
private var prefsName = "${YukiHookAPI.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences"
|
||||
|
||||
/** 是否为 Xposed 环境 */
|
||||
private val isXposedEnvironment = YukiHookAPI.hasXposedBridge
|
||||
@@ -83,26 +83,24 @@ class YukiHookModulePrefs(private val context: Context? = null) {
|
||||
* 获得 [XSharedPreferences] 对象
|
||||
* @return [XSharedPreferences]
|
||||
*/
|
||||
private val xPref by lazy {
|
||||
XSharedPreferences(YukiHookAPI.modulePackageName, prefsName).apply {
|
||||
private val xPref
|
||||
get() = XSharedPreferences(YukiHookAPI.modulePackageName, prefsName).apply {
|
||||
makeWorldReadable()
|
||||
reload()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 [SharedPreferences] 对象
|
||||
* @return [SharedPreferences]
|
||||
*/
|
||||
private val sPref by lazy {
|
||||
try {
|
||||
private val sPref
|
||||
get() = try {
|
||||
context?.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE)
|
||||
?: error("If you want to use module prefs,you must set the context instance first")
|
||||
} catch (_: Throwable) {
|
||||
context?.getSharedPreferences(prefsName, Context.MODE_PRIVATE)
|
||||
?: error("If you want to use module prefs,you must set the context instance first")
|
||||
}
|
||||
}
|
||||
|
||||
/** 设置全局可读可写 */
|
||||
private fun makeWorldReadable() = runCatching {
|
||||
@@ -112,6 +110,16 @@ class YukiHookModulePrefs(private val context: Context? = null) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 Sp 存储名称
|
||||
* @param name 自定义的 Sp 存储名称
|
||||
* @return [YukiHookModulePrefs]
|
||||
*/
|
||||
fun name(name: String): YukiHookModulePrefs {
|
||||
prefsName = name
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 [String] 键值
|
||||
*
|
||||
|
Reference in New Issue
Block a user