mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-01 08:15:37 +08:00
...
This commit is contained in:
@@ -10,6 +10,21 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.YukiHookAPI">
|
||||
|
||||
<!-- 是否是xposed模块 -->
|
||||
<meta-data
|
||||
android:name="xposedmodule"
|
||||
android:value="true" />
|
||||
|
||||
<!-- 模块描述 -->
|
||||
<meta-data
|
||||
android:name="xposeddescription"
|
||||
android:value="YukiHook Xposed Module Test" />
|
||||
|
||||
<!-- 最低xposed版本号 -->
|
||||
<meta-data
|
||||
android:name="xposedminversion"
|
||||
android:value="82" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
|
@@ -0,0 +1,9 @@
|
||||
package com.highcapable.yukihookapi.demo
|
||||
|
||||
import com.highcapable.yukihookapi.hook.init.YukiHookLoadPackage
|
||||
|
||||
class Yuu : YukiHookLoadPackage() {
|
||||
|
||||
override fun onHookStart() {
|
||||
}
|
||||
}
|
@@ -32,6 +32,7 @@ android {
|
||||
dependencies {
|
||||
// Used 82 API Version
|
||||
compileOnly fileTree(include: ['api-82.jar'], dir: 'libs')
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
1
yukihookapi/src/main/assets/xposed_init
Normal file
1
yukihookapi/src/main/assets/xposed_init
Normal file
@@ -0,0 +1 @@
|
||||
com.highcapable.yukihookapi.hook.init.YukiHookLoadPackage
|
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.hook
|
||||
|
||||
import com.highcapable.yukihookapi.param.HookParam
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class YukiHookCreater(private val param: PackageParam) {
|
||||
|
||||
var grabMethod: Method? = null
|
||||
var grabConstructor: Constructor<*>? = null
|
||||
|
||||
fun beforeHook(initiate: HookParam.() -> Unit) {
|
||||
|
||||
}
|
||||
|
||||
fun afterHook(initiate: HookParam.() -> Unit) {
|
||||
|
||||
}
|
||||
|
||||
fun replaceHook(initiate: HookParam.() -> Any?) {
|
||||
|
||||
}
|
||||
|
||||
fun replaceTo(any: Any?) {
|
||||
|
||||
}
|
||||
|
||||
fun intercept() {
|
||||
|
||||
}
|
||||
|
||||
fun hook() {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.hook.factory
|
||||
|
||||
import com.highcapable.yukihookapi.hook.YukiHookCreater
|
||||
|
||||
fun Class<*>.hook(it: YukiHookCreater.() -> Unit) = YukiHookCreater().apply(it).hook()
|
@@ -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/2.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.helper
|
||||
|
||||
import com.highcapable.yukihookapi.param.PackageParam
|
||||
|
||||
/**
|
||||
* YukiHook 的装载 API 调用类
|
||||
* 可以实现作为模块装载和 Hook 自身 APP 两种方式
|
||||
*/
|
||||
object YukiHookHelper {
|
||||
|
||||
/**
|
||||
* 自身作为模块装载调用入口方法
|
||||
* @param initiate Hook 方法体
|
||||
*/
|
||||
fun onHookApp(initiate: PackageParam.() -> Unit) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 作为侵入式 Hook 自身装载调用入口方法
|
||||
* 正在开发敬请期待。
|
||||
* @param initiate Hook 方法体
|
||||
*/
|
||||
fun onHookSelf(initiate: PackageParam.() -> Unit) {}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.hook.init
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.highcapable.yukihookapi.hook.helper.YukiHookHelper
|
||||
import de.robv.android.xposed.IXposedHookLoadPackage
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||
|
||||
/**
|
||||
* 接管 Xposed 的 [IXposedHookLoadPackage] 入口
|
||||
* 你可以使用 [YukiHookHelper] 来监听模块开始装载
|
||||
*/
|
||||
@Keep
|
||||
class YukiHookLoadPackage : IXposedHookLoadPackage {
|
||||
|
||||
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
|
||||
if (lpparam == null) return
|
||||
|
||||
}
|
||||
}
|
@@ -25,7 +25,132 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/2.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.param
|
||||
|
||||
class HookParam {
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
* Hook 方法、构造类的目标对象实现类
|
||||
* @param instance 对接 Xposed API 的 [XC_MethodHook.MethodHookParam]
|
||||
*/
|
||||
class HookParam(private val instance: XC_MethodHook.MethodHookParam) {
|
||||
|
||||
/**
|
||||
* 获取 Hook 方法的参数对象数组
|
||||
* @return [Array]
|
||||
*/
|
||||
val args get() = instance.args ?: arrayOf(0)
|
||||
|
||||
/**
|
||||
* 获取 Hook 方法的参数对象数组第一位
|
||||
* @return [Array]
|
||||
* @throws IllegalStateException 如果数组为空或对象为空
|
||||
*/
|
||||
val firstArgs get() = args[0] ?: error("HookParam args[0] with a non-null object")
|
||||
|
||||
/**
|
||||
* 获取 Hook 方法的参数对象数组最后一位
|
||||
* @return [Array]
|
||||
* @throws IllegalStateException 如果数组为空或对象为空
|
||||
*/
|
||||
val lastArgs get() = args[args.lastIndex] ?: error("HookParam args[lastIndex] with a non-null object")
|
||||
|
||||
/**
|
||||
* 获取 Hook 实例的 Class
|
||||
* @return [Class]
|
||||
*/
|
||||
val thisClass get() = instance.thisObject.javaClass
|
||||
|
||||
/**
|
||||
* 获取 Hook 实例的对象
|
||||
* @return [Any]
|
||||
* @throws IllegalStateException 如果对象为空
|
||||
*/
|
||||
val thisAny get() = instance.thisObject ?: error("HookParam must with a non-null object")
|
||||
|
||||
/**
|
||||
* 获取 Hook 当前普通方法
|
||||
* @return [Method]
|
||||
* @throws IllegalStateException 如果方法为空或方法类型不是 [Method]
|
||||
*/
|
||||
val method get() = instance.method as? Method? ?: error("Current hook method type is wrong or null")
|
||||
|
||||
/**
|
||||
* 获取 Hook 当前构造方法
|
||||
* @return [Constructor]
|
||||
* @throws IllegalStateException 如果方法为空或方法类型不是 [Constructor]
|
||||
*/
|
||||
val constructor get() = instance.method as? Constructor<*>? ?: error("Current hook constructor type is wrong or null")
|
||||
|
||||
/**
|
||||
* 获取、设置 Hook 方法的返回值
|
||||
* @return [Any] or null
|
||||
*/
|
||||
var result: Any?
|
||||
get() = instance.result
|
||||
set(value) {
|
||||
instance.result = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Hook 实例的对象 [T]
|
||||
* @return [Any]
|
||||
* @throws IllegalStateException 如果对象为空或对象类型不是 [T]
|
||||
*/
|
||||
inline fun <reified T> thisAny() = thisAny as? T? ?: error("HookParam object cannot cast to ${T::class.java.name}")
|
||||
|
||||
/**
|
||||
* 获取 Hook 方法的参数实例化对象类
|
||||
* @param index 参数对象数组下标 - 默认是 0
|
||||
* @return [Array]
|
||||
*/
|
||||
fun args(index: Int = 0) = ArgsModifyer(index)
|
||||
|
||||
/**
|
||||
* 拦截整个方法体
|
||||
* 此方法将强制设置方法体的 [result] 为 null
|
||||
*/
|
||||
fun intercept() {
|
||||
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}")
|
||||
instance.args[index] = any
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象为 null
|
||||
* 此方法可以将任何被 Hook 的目标对象设置为空
|
||||
*/
|
||||
fun setNull() = set(null)
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象为 true
|
||||
* 请确保目标对象的类型是 [Boolean] 不然会出错
|
||||
*/
|
||||
fun setTrue() = set(true)
|
||||
|
||||
/**
|
||||
* 设置方法参数的实例对象为 false
|
||||
* 请确保目标对象的类型是 [Boolean] 不然会出错
|
||||
*/
|
||||
fun setFalse() = set(false)
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.param
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage
|
||||
|
||||
/**
|
||||
* 装载 Hook 的目标 APP 入口对象实现类
|
||||
* 如果是侵入式 Hook 自身 APP 可将参数 [instance] 置空获得当前类的 [ClassLoader]
|
||||
* @param instance 对接 Xposed API 的 [XC_LoadPackage.LoadPackageParam]
|
||||
*/
|
||||
class PackageParam(private val instance: XC_LoadPackage.LoadPackageParam? = null) {
|
||||
|
||||
/** 当前 classLoader */
|
||||
private var privateClassLoader = instance?.classLoader ?: javaClass.classLoader
|
||||
|
||||
/**
|
||||
* 获取、设置当前 APP 的 [ClassLoader]
|
||||
* @return [ClassLoader]
|
||||
*/
|
||||
var appClassLoader: ClassLoader
|
||||
get() = privateClassLoader
|
||||
set(value) {
|
||||
privateClassLoader = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的 [ApplicationInfo]
|
||||
* @return [ApplicationInfo]
|
||||
*/
|
||||
val appInfo get() = instance?.appInfo ?: ApplicationInfo()
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的进程名称
|
||||
* 默认的进程名称是 [packageName]
|
||||
* @return [String]
|
||||
*/
|
||||
val processName get() = instance?.processName ?: ""
|
||||
|
||||
/**
|
||||
* 获取当前 APP 的包名
|
||||
* @return [String]
|
||||
*/
|
||||
val packageName get() = instance?.packageName ?: ""
|
||||
|
||||
/**
|
||||
* 获取当前 APP 是否为第一个 Application
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val isFirstApplication get() = instance?.isFirstApplication ?: true
|
||||
}
|
Reference in New Issue
Block a user