This commit is contained in:
2022-02-05 05:21:43 +08:00
parent e6bfc181de
commit 6a6715268f
11 changed files with 175 additions and 28 deletions

View File

@@ -52,6 +52,15 @@ object YukiHookAPI {
/** 全局标识 */
const val TAG = "YukiHookAPI"
/**
* 是否开启调试模式 - 默认启用
*
* 启用后将交由日志输出管理器打印详细 Hook 日志到控制台
*
* 请过滤 [TAG] (YukiHookAPI) 即可找到每条日志
*/
var isDebug = true
/**
* Xposed Hook API 绑定的模块包名 - 未写将自动生成
* - 你不应该设置此变量的名称 - 请使用 [encase] 装载模块包名

View File

@@ -29,13 +29,16 @@
package com.highcapable.yukihookapi.hook.core
import com.highcapable.yukihookapi.YukiHookAPI
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.hook.log.loggerI
import com.highcapable.yukihookapi.hook.param.HookParam
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.utils.runBlocking
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XC_MethodReplacement
import de.robv.android.xposed.XposedBridge
@@ -120,7 +123,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
* 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换
* @param initiate 方法体
*/
fun method(initiate: MethodFinder.() -> Unit) {
fun method(initiate: MethodFinder.() -> Unit) = runBlocking {
runCatching {
member = MethodFinder(hookClass).apply(initiate).find()
}.onFailure {
@@ -129,7 +132,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
onAllFailureCallback?.invoke(it)
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
}
}
}.result { onHookLogMsg(msg = "Find Method [$member] takes ${it}ms") }
/**
* 查找需要 Hook 的构造类
@@ -137,7 +140,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
* 你只能使用一次 [method] 或 [constructor] 方法 - 否则结果会被替换
* @param initiate 方法体
*/
fun constructor(initiate: ConstructorFinder.() -> Unit) {
fun constructor(initiate: ConstructorFinder.() -> Unit) = runBlocking {
runCatching {
member = ConstructorFinder(hookClass).apply(initiate).find()
}.onFailure {
@@ -146,7 +149,7 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
onAllFailureCallback?.invoke(it)
if (onNoSuchMemberCallback == null && onAllFailureCallback == null) onHookFailureMsg(it)
}
}
}.result { onHookLogMsg(msg = "Find Constructor [$member] takes ${it}ms") }
/**
* 查找 [Field]
@@ -155,7 +158,11 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
*/
fun HookParam.field(initiate: FieldFinder.() -> Unit) =
try {
FieldFinder(hookClass).apply(initiate).find()
var result: FieldFinder.Result? = null
runBlocking {
result = FieldFinder(hookClass).apply(initiate).find()
}.result { onHookLogMsg(msg = "Find Field [${result?.give()}] takes ${it}ms") }
result!!
} catch (e: Throwable) {
isStopHookMode = true
onNoSuchMemberCallback?.invoke(e)
@@ -277,6 +284,8 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
if (baseParam == null) return null
return HookParam(baseParam).let { param ->
try {
if (replaceHookCallback != null)
onHookLogMsg(msg = "Replace Hook Member [${member}] done")
replaceHookCallback?.invoke(param)
} catch (e: Throwable) {
onConductFailureCallback?.invoke(param, e)
@@ -295,6 +304,8 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
HookParam(baseParam).also { param ->
runCatching {
beforeHookCallback?.invoke(param)
if (beforeHookCallback != null)
onHookLogMsg(msg = "Before Hook Member [${member}] done")
}.onFailure {
onConductFailureCallback?.invoke(param, it)
onAllFailureCallback?.invoke(it)
@@ -309,6 +320,8 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
HookParam(baseParam).also { param ->
runCatching {
afterHookCallback?.invoke(param)
if (afterHookCallback != null)
onHookLogMsg(msg = "After Hook Member [${member}] done")
}.onFailure {
onConductFailureCallback?.invoke(param, it)
onAllFailureCallback?.invoke(it)
@@ -333,6 +346,14 @@ class YukiHookCreater(private val packageParam: PackageParam, val hookClass: Cla
private fun onHookFailureMsg(throwable: Throwable) =
loggerE(msg = "Try to hook $hookClass[$member] got an Exception", e = throwable)
/**
* Hook 过程中开启了 [YukiHookAPI.isDebug] 输出调试信息
* @param msg 调试日志内容
*/
private fun onHookLogMsg(msg: String) {
if (YukiHookAPI.isDebug) loggerI(msg = msg)
}
override fun toString() = "$member#YukiHook"
/**

View File

@@ -171,7 +171,7 @@ public class ReflectionUtils {
* @param methodName 方法名
*/
public static Method findMethodNoParam(Class<?> clazz, Class<?> returnType, String methodName) {
String fullMethodName = clazz.getName() + '#' + methodName + returnType + "#exact#NoParam";
String fullMethodName = "name:[" + methodName + "] in Class [" + clazz.getName() + "] by YukiHook#finder";
if (!methodCache.containsKey(fullMethodName)) {
Method method = findMethodIfExists(clazz, returnType, methodName);
methodCache.put(fullMethodName, method);
@@ -190,7 +190,7 @@ public class ReflectionUtils {
* @param parameterTypes 方法参数类型数组
*/
public static Method findMethodBestMatch(Class<?> clazz, Class<?> returnType, String methodName, Class<?>... parameterTypes) {
String fullMethodName = clazz.getName() + '#' + methodName + returnType + getParametersString(parameterTypes) + "#exact";
String fullMethodName = "name:[" + methodName + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHook#finder";
if (!methodCache.containsKey(fullMethodName)) {
Method method = findMethodIfExists(clazz, returnType, methodName, parameterTypes);
methodCache.put(fullMethodName, method);
@@ -207,24 +207,24 @@ public class ReflectionUtils {
* @param parameterTypes 构造类方法参数类型数组
*/
public static Constructor<?> findConstructorExact(Class<?> clazz, Class<?>... parameterTypes) {
String fullConstructorName = clazz.getName() + getParametersString(parameterTypes) + "#exact";
String fullConstructorName = "paramType:[" + getParametersString(parameterTypes) + "in Class [" + clazz.getName() + "] by YukiHook#finder";
try {
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
return constructor;
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError("Can't find constructor " + fullConstructorName);
throw new NoSuchMethodError("Can't find this constructor --> " + fullConstructorName);
}
}
private static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#zYukiHook#exact";
String fullMethodName = "name:[" + methodName + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHook#finder";
try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError("Can't find method " + fullMethodName);
throw new NoSuchMethodError("Can't find this method --> " + fullMethodName);
}
}
@@ -238,6 +238,6 @@ public class ReflectionUtils {
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() + ">");
throw new IllegalArgumentException("Can't find this method --> name:[" + methodName + "] returnType:[" + returnType.getName() + "] paramType:[" + getParametersString(parameterTypes) + "] in Class [" + clazz.getName() + "] by YukiHook#finder");
}
}

View File

@@ -0,0 +1,52 @@
/**
* 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/5.
*/
package com.highcapable.yukihookapi.hook.utils
/**
* 计算方法执行耗时
* @param block 方法块
* @return [RunBlockResult]
*/
inline fun <R> runBlocking(block: () -> R): RunBlockResult {
val start = System.currentTimeMillis()
block()
return RunBlockResult(after = System.currentTimeMillis() - start)
}
/**
* 构造耗时计算结果类
* @param after 耗时
*/
class RunBlockResult(private val after: Long) {
/**
* 获取耗时计算结果
* @param initiate 回调结果 - ([Long] 耗时)
*/
fun result(initiate: (Long) -> Unit) = initiate(after)
}