mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-06 02:35:40 +08:00
255 lines
6.8 KiB
Markdown
255 lines
6.8 KiB
Markdown
# 从 Xposed API 迁移
|
||
|
||
> 若你熟悉 Xposed API,你可以参考下方的相同点将自己的 API 快速迁移到 `YukiHookAPI`。
|
||
|
||
## 迁移 Hook 入口点
|
||
|
||
> 从 `XC_LoadPackage.LoadPackageParam` 迁移至 `PackageParam`。
|
||
|
||
`YukiHookAPI` 对 `PackageParam` 实现了 `lambda` 方法体 `this` 用法,在 `encase` 方法体内即可全局得到 `PackageParam` 对象。
|
||
|
||
> API 功能差异对比如下
|
||
|
||
<!-- tabs:start -->
|
||
|
||
#### **Yuki Hook API**
|
||
|
||
```kotlin
|
||
override fun onHook() = encase {
|
||
// 得到当前 Hook 的包名
|
||
packageName
|
||
// 得到当前 Hook 的 ApplicationInfo
|
||
appInfo
|
||
// 得到宿主 Application 生命周期
|
||
appContext
|
||
// Hook 指定的 APP
|
||
loadApp(name = "com.demo.test") {
|
||
// Class Hook
|
||
findClass("com.demo.test.TestClass").hook {
|
||
injectMember {
|
||
method {
|
||
name = "test"
|
||
param(BooleanType)
|
||
}
|
||
afterHook {
|
||
// ...
|
||
}
|
||
}
|
||
}
|
||
// Resources Hook (固定用法)
|
||
resources().hook {
|
||
injectResource {
|
||
conditions {
|
||
name = "ic_launcher"
|
||
mipmap()
|
||
}
|
||
replaceToModuleResource(R.mipmap.ic_launcher)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### **Xposed API**
|
||
|
||
```kotlin
|
||
private lateinit var moduleResources: XModuleResources
|
||
|
||
override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam) {
|
||
moduleResources = XModuleResources.createInstance(sparam.modulePath, null)
|
||
}
|
||
|
||
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
|
||
// 得到当前 Hook 的包名
|
||
lpparam.packageName
|
||
// 得到当前 Hook 的 ApplicationInfo
|
||
lpparam.applicationInfo
|
||
// 得到宿主 Application 生命周期
|
||
AndroidAppHelper.currentApplication()
|
||
// Class Hook
|
||
if(lpparam.packageName == "com.demo.test")
|
||
XposedHelpers.findAndHookMethod("com.demo.test.TestClass", lpparam.classLoader, "test", Boolean::class.java, object : XC_MethodHook() {
|
||
override fun afterHookedMethod(param: MethodHookParam) {
|
||
// ...
|
||
}
|
||
})
|
||
}
|
||
|
||
override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam) {
|
||
// 得到当前 Hook 的包名
|
||
resparam.packageName
|
||
// 创建 Hook
|
||
resparam.res.setReplacement("com.demo.test", "mipmap", "ic_launcher", moduleResources.fwd(R.mipmap.ic_launcher))
|
||
}
|
||
```
|
||
|
||
<!-- tabs:end -->
|
||
|
||
## 迁移 Hook 方法体
|
||
|
||
> 从 `XC_MethodHook.MethodHookParam` 迁移至 `HookParam`。
|
||
|
||
### Before/After Hook
|
||
|
||
`YukiHookAPI` 同样对 `HookParam` 实现了 `lambda` 方法体 `this` 用法,在 `beforeHook`、`afterHook` 等方法体内即可全局得到 `HookParam` 对象。
|
||
|
||
> API 功能差异对比如下
|
||
|
||
<!-- tabs:start -->
|
||
|
||
#### **Yuki Hook API**
|
||
|
||
```kotlin
|
||
afterHook {
|
||
// 得到当前 Hook 的实例
|
||
instance
|
||
// 得到当前 Hook 的 Class 实例
|
||
instanceClass
|
||
// 得到并 cast 当前 Hook 的实例为指定类型 T
|
||
instance<T>()
|
||
// 得到方法参数数组
|
||
args
|
||
// 得到方法参数的第一位 T
|
||
args().first().cast<T>()
|
||
// 得到方法参数的最后一位 T
|
||
args().last().cast<T>()
|
||
// 得到方法参数的任意下标 T,这里用 2 举例
|
||
args(index = 2).cast<T>()
|
||
// 设置方法参数的任意下标,这里用 2 举例
|
||
args(index = 2).set(...)
|
||
// 得到返回值
|
||
result
|
||
// 得到返回值并 cast 为 T
|
||
result<T>()
|
||
// 修改返回值内容
|
||
result = ...
|
||
// 删除返回值内容
|
||
resultNull()
|
||
// 向 Hook APP 抛出异常
|
||
Throwable("Fatal").throwToApp()
|
||
// 执行未经 Hook 的原始方法
|
||
method.invokeOriginal(...)
|
||
}
|
||
```
|
||
|
||
#### **Xposed API**
|
||
|
||
```kotlin
|
||
override fun afterHookedMethod(param: MethodHookParam) {
|
||
// 得到当前 Hook 的实例
|
||
param.thisObject
|
||
// 得到当前 Hook 的 Class 实例
|
||
param.thisObject.javaClass
|
||
// 得到并 cast 当前 Hook 的实例为指定类型 T
|
||
param.thisObject as T
|
||
// 得到方法参数数组
|
||
param.args
|
||
// 得到方法参数的第一位 T
|
||
param.args[0] as T
|
||
// 得到方法参数的最后一位 T
|
||
param.args[param.args.lastIndex] as T
|
||
// 得到方法参数的任意下标 T,这里用 2 举例
|
||
param.args[2] as T
|
||
// 设置方法参数的任意下标,这里用 2 举例
|
||
param.args[2] = ...
|
||
// 得到返回值
|
||
param.result
|
||
// 得到返回值并 cast 为 T
|
||
param.result as T
|
||
// 修改返回值内容
|
||
param.result = ...
|
||
// 删除返回值内容
|
||
param.result = null
|
||
// 向 Hook APP 抛出异常
|
||
param.throwable = Throwable("Fatal")
|
||
// 执行未经 Hook 的原始方法
|
||
XposedBridge.invokeOriginalMethod(param.method, param.thisObject, ...)
|
||
}
|
||
```
|
||
|
||
<!-- tabs:end -->
|
||
|
||
### Replace Hook
|
||
|
||
`replaceHook` 方法比较特殊,`YukiHookAPI` 为它做出了多种形式以供选择。
|
||
|
||
> API 功能差异对比如下
|
||
|
||
<!-- tabs:start -->
|
||
|
||
#### **Yuki Hook API**
|
||
|
||
无返回值的方法 `void`。
|
||
|
||
```kotlin
|
||
replaceUnit {
|
||
// 直接在这里实现被替换的逻辑
|
||
}
|
||
```
|
||
|
||
有返回值的方法。
|
||
|
||
```kotlin
|
||
replaceAny {
|
||
// 在这里实现被替换的逻辑
|
||
// ...
|
||
// 需要返回方法对应的返回值,无需写 return,只需将参数放到最后一位
|
||
// 假设这个方法的返回值是 Int,我们只需要保证最后一位是我们需要的返回值即可
|
||
0
|
||
}
|
||
```
|
||
|
||
有些方法我们只需替换其返回值,则有如下实现。
|
||
|
||
```kotlin
|
||
// 替换为你需要的返回值
|
||
replaceTo(...)
|
||
// 替换为 Boolean 类型的返回值
|
||
replaceToTrue()
|
||
// 拦截返回值
|
||
intercept()
|
||
```
|
||
|
||
!> 直接替换返回值的方法传入的参数是固定不变的,若想实现动态替换返回值请使用 `replaceAny` 方法体。
|
||
|
||
#### **Xposed API**
|
||
|
||
无返回值的方法 `void`。
|
||
|
||
```kotlin
|
||
override fun replaceHookedMethod(param: MethodHookParam): Any? {
|
||
// 直接在这里实现被替换的逻辑
|
||
return null
|
||
}
|
||
```
|
||
|
||
有返回值的方法。
|
||
|
||
```kotlin
|
||
override fun replaceHookedMethod(param: MethodHookParam): Int {
|
||
// 在这里实现被替换的逻辑
|
||
// ...
|
||
// 假设这个方法的返回值是 Int
|
||
return 0
|
||
}
|
||
```
|
||
|
||
有些方法我们只需替换其返回值,则有如下实现。
|
||
|
||
```kotlin
|
||
// 替换为你需要的返回值
|
||
override fun replaceHookedMethod(param: MethodHookParam) = ...
|
||
// 替换为 Boolean 类型的返回值
|
||
override fun replaceHookedMethod(param: MethodHookParam) = true
|
||
// 拦截返回值
|
||
override fun replaceHookedMethod(param: MethodHookParam) = null
|
||
```
|
||
|
||
<!-- tabs:end -->
|
||
|
||
## 迁移其它功能
|
||
|
||
`YukiHookAPI` 对 Xposed API 进行了完全重写,你可以参考 [API 文档](api/home) 以及 [特色功能](guide/special-feature) 来决定一些功能性的迁移和使用。
|
||
|
||
<br/><br/>
|
||
[浏览下一篇 ➡️](config/api-example.md) |