This commit is contained in:
2022-02-07 04:05:18 +08:00
parent ab2584320a
commit 2927a708e8
9 changed files with 238 additions and 53 deletions

View File

@@ -29,12 +29,14 @@
package com.highcapable.yukihookapi
import android.content.pm.ApplicationInfo
import android.app.Application
import android.content.Context
import com.highcapable.yukihookapi.YukiHookAPI.configs
import com.highcapable.yukihookapi.YukiHookAPI.encase
import com.highcapable.yukihookapi.annotation.DoNotUseMethod
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.param.CustomParam
import com.highcapable.yukihookapi.hook.factory.processName
import com.highcapable.yukihookapi.hook.param.EnvironmentParam
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
import de.robv.android.xposed.callbacks.XC_LoadPackage
@@ -54,7 +56,7 @@ object YukiHookAPI {
private var packageParamCallback: (PackageParam.() -> Unit)? = null
/**
* 配置 YukiHook
* 配置 YukiHookAPI
*/
object Configs {
@@ -102,7 +104,17 @@ object YukiHookAPI {
* @param lpparam Xposed [XC_LoadPackage.LoadPackageParam]
*/
@DoNotUseMethod
fun onXposedLoaded(lpparam: XC_LoadPackage.LoadPackageParam) = packageParamCallback?.invoke(PackageParam(lpparam))
fun onXposedLoaded(lpparam: XC_LoadPackage.LoadPackageParam) =
packageParamCallback?.invoke(
PackageParam(
EnvironmentParam(
packageName = lpparam.packageName,
processName = lpparam.processName,
appClassLoader = lpparam.classLoader,
appInfo = lpparam.appInfo
)
)
)
/**
* 作为模块装载调用入口方法 - Xposed API
@@ -126,16 +138,87 @@ object YukiHookAPI {
}
/**
* 自定义 Hook 方法装载入口
* @param classLoader [ClassLoader]
* @param packageName 包名
* @param appInfo [ApplicationInfo]
* 作为 [Application] 装载调用入口方法
*
* 请在 [Application.attachBaseContext] 中写入如下代码:
*
* ....
*
* override fun attachBaseContext(base: Context?) {
*
* ....////
*
* ....// 装载你使用的 Hook 框架的代码
*
* ....// 你的 Hook 框架需要支持 Xposed API
*
* ....////
*
* ....// 装载 YukiHookAPI
*
* ....YukiHookAPI.encase(base) {
*
* ........// Your code here.
*
* ....}
*
* ....super.attachBaseContext(base)
*
* }
*
* ....
*
* 详情请参考 [YukiHookAPI Wiki](https://github.com/fankes/YukiHookAPI/wiki)
* @param baseContext attachBaseContext
* @param initiate Hook 方法体
*/
fun encase(
classLoader: ClassLoader,
packageName: String,
appInfo: ApplicationInfo,
initiate: PackageParam.() -> Unit
) = initiate.invoke(PackageParam(customParam = CustomParam(classLoader, appInfo, packageName)))
fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit) {
if (baseContext != null) initiate.invoke(baseContext.packagePararm)
}
/**
* 作为 [Application] 装载调用入口方法
*
* 请在 [Application.attachBaseContext] 中写入如下代码:
*
* ....
*
* override fun attachBaseContext(base: Context?) {
*
* ....////
*
* ....// 装载你使用的 Hook 框架的代码
*
* ....// 你的 Hook 框架需要支持 Xposed API
*
* ....////
*
* ....// 装载 YukiHookAPI
*
* ....YukiHookAPI.encase(base, MainHooker(), SecondHooker() ...)
*
* ....super.attachBaseContext(base)
*
* }
*
* ....
*
* 详情请参考 [YukiHookAPI Wiki](https://github.com/fankes/YukiHookAPI/wiki)
* @param baseContext attachBaseContext
* @param hooker Hook 子类数组 - 必填不能为空
* @throws IllegalStateException 如果 [hooker] 是空的
*/
fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker) {
if (baseContext != null)
if (hooker.isNotEmpty())
hooker.forEach { it.assignInstance(packageParam = baseContext.packagePararm) }
else error("Hooker is empty")
}
/**
* 通过 baseContext 创建 Hook 入口类
* @return [PackageParam]
*/
private val Context.packagePararm
get() = PackageParam(EnvironmentParam(packageName, processName, classLoader, applicationInfo))
}

View File

@@ -46,17 +46,18 @@ import java.lang.reflect.Constructor
*/
class ConstructorFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
/** 失败尝试次数数组 */
private val remedyPlan = HashMap<Long, ConstructorFinder>()
/** 构造方法参数 */
/** [Constructor] 参数数组 */
private var params: Array<out Class<*>>? = null
/**
* 构造方法参数
* [Constructor] 参数
* - 无参 [Constructor] 不要使用此方法
*
* - 有参 [Constructor] 必须使用此方法设定参数
* @param param 参数数组
*/
fun param(vararg param: Class<*>) {
if (param.isEmpty()) error("param is empty, please delete param() method")
params = param
}

View File

@@ -48,10 +48,16 @@ class FieldFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, p
/** 当前找到的 [Field] */
private var fieldInstance: Field? = null
/** 变量名 */
/**
* [Field] 名称
* - 必须设置
*/
var name = ""
/** 变量类型 */
/**
* [Field] 类型
* - 必须设置
*/
var type: Class<*>? = null
/**

View File

@@ -46,20 +46,32 @@ import java.lang.reflect.Method
*/
class MethodFinder(private val hookInstance: YukiHookCreater.MemberHookCreater, private val hookClass: Class<*>) {
/** 方法参数 */
/** [Method] 参数数组 */
private var params: Array<out Class<*>>? = null
/** 方法名 */
/**
* [Method] 名称
*
* - 必须设置
*/
var name = ""
/** 方法返回值 */
/**
* [Method] 返回值
*
* 可不填写返回值 - 默认模糊查找并取第一个匹配的 [Method]
*/
var returnType: Class<*>? = null
/**
* 方法参数
* [Method] 参数
* - 无参 [Method] 不要使用此方法
*
* - 有参 [Method] 必须使用此方法设定参数
* @param param 参数数组
*/
fun param(vararg param: Class<*>) {
if (param.isEmpty()) error("param is empty, please delete param() method")
params = param
}

View File

@@ -33,10 +33,14 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Process
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
/**
* 在 [YukiHookXposedInitProxy] 中装载 [YukiHookAPI]
@@ -51,6 +55,22 @@ fun YukiHookXposedInitProxy.encase(initiate: PackageParam.() -> Unit) = YukiHook
*/
fun YukiHookXposedInitProxy.encase(vararg hooker: YukiBaseHooker) = YukiHookAPI.encase(hooker = hooker)
/**
* 获取当前进程名称
* @return [String]
*/
val Context.processName
get() = try {
BufferedReader(FileReader(File("/proc/${Process.myPid()}/cmdline"))).let { buff ->
buff.readLine().trim { it <= ' ' }.let {
buff.close()
it
}
}
} catch (_: Throwable) {
packageName ?: ""
}
/**
* 判断模块是否在太极、无极中激活
* @return [Boolean] 是否激活

View File

@@ -23,20 +23,24 @@
* 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.
* This file is Created by fankes on 2022/2/7.
*/
@file:Suppress("unused", "MemberVisibilityCanBePrivate", "EXPERIMENTAL_API_USAGE")
package com.highcapable.yukihookapi.hook.param
import android.content.pm.ApplicationInfo
/**
* 自定义 [PackageParam] 的装载入口置换
* Hook 环境装载实现
* @param packageName 包名
* @param processName 当前进程名
* @param appClassLoader APP [ClassLoader]
* @param appInfo APP [ApplicationInfo]
* @param packageName 包名
*/
class CustomParam(
class EnvironmentParam(
var packageName: String,
var processName: String,
var appClassLoader: ClassLoader,
var appInfo: ApplicationInfo,
var packageName: String
var appInfo: ApplicationInfo
)

View File

@@ -33,21 +33,12 @@ 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 自定义装载类 - 默认空
* @param baseParam 对接环境装载类的实现 - 默认是空的
*/
open class PackageParam(
private var baseParam: XC_LoadPackage.LoadPackageParam? = null,
private var customParam: CustomParam? = null
) {
open class PackageParam(private var baseParam: EnvironmentParam? = null) {
/**
* 获取当前 APP 的 [ClassLoader]
@@ -55,36 +46,33 @@ open class PackageParam(
* @throws IllegalStateException 如果 [ClassLoader] 是空的
*/
val appClassLoader
get() = baseParam?.classLoader ?: customParam?.appClassLoader ?: javaClass.classLoader
?: error("PackageParam ClassLoader is null")
get() = baseParam?.appClassLoader ?: javaClass.classLoader ?: error("PackageParam got null ClassLoader")
/**
* 获取当前 APP 的 [ApplicationInfo]
* @return [ApplicationInfo]
*/
val appInfo get() = baseParam?.appInfo ?: customParam?.appInfo ?: ApplicationInfo()
val appInfo get() = baseParam?.appInfo ?: ApplicationInfo()
/**
* 获取当前 APP 的进程名称
*
* 默认的进程名称是 [packageName] 如果自定义了 [customParam] 将返回包名
* 默认的进程名称是 [packageName]
* @return [String]
*/
val processName get() = baseParam?.processName ?: customParam?.packageName ?: ""
val processName get() = baseParam?.processName ?: packageName
/**
* 获取当前 APP 的包名
* @return [String]
*/
val packageName get() = baseParam?.packageName ?: customParam?.packageName ?: ""
val packageName get() = baseParam?.packageName ?: ""
/**
* 获取当前 APP 是否为第一个 Application
*
* 若自定义了 [customParam] 将永远返回 true
* @return [Boolean]
*/
val isFirstApplication get() = baseParam?.isFirstApplication ?: true
val isFirstApplication get() = packageName == processName
/**
* 赋值并克隆另一个 [PackageParam]
@@ -94,7 +82,6 @@ open class PackageParam(
@DoNotUseMethod
internal fun baseAssignInstance(another: PackageParam) {
this.baseParam = another.baseParam
this.customParam = another.customParam
}
/**