8.0 KiB
用法示例
这里介绍了
YukiHookAPI
的基本工作方式以及列举了简单的 Hook 例子和常用功能。
结构图解
下方的结构描述了
YukiHookAPI
的基本工作方式和原理。
Host Environment
└── YukiHookCreater
└── Class
└── MemberHookCreater
└── Member
├── Before
└── After
MemberHookCreater
└── Member
├── Before
└── After
...
上方的结构换做代码将可写为如下形式。
TargetClass.hook {
injectMember {
method {
// Your code here.
}
beforeHook {
// Your code here.
}
afterHook {
// Your code here.
}
}
}
Demo
你可以在下方找到 API 提供的 Demo 来学习
YukiHookAPI
的使用方法。
同时安装宿主和模块 Demo,通过激活模块来测试宿主中被 Hook 的功能。
一个简单的 Hook 例子
假设,我们要 Hook com.android.browser
中的 onCreate
方法并弹出一个对话框。
在 encase
方法体中添加代码。
示例如下
loadApp(name = "com.android.browser") {
ActivityClass.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
returnType = UnitType
}
afterHook {
AlertDialog.Builder(instance())
.setTitle("Hooked")
.setMessage("I am hook!")
.setPositiveButton("OK", null)
.show()
}
}
}
}
至此,onCreate
方法将被成功 Hook 并在 com.android.browser
中的每个 Activity
启动时弹出此对话框。
那么,我想继续 Hook onStart
方法要怎么做呢?
在刚刚的代码中,继续插入一个 injectMember
方法体即可。
示例如下
loadApp(name = "com.android.browser") {
ActivityClass.hook {
injectMember {
method {
name = "onCreate"
param(BundleClass)
returnType = UnitType
}
afterHook {
AlertDialog.Builder(instance())
.setTitle("Hooked")
.setMessage("I am hook!")
.setPositiveButton("OK", null)
.show()
}
}
injectMember {
method {
name = "onStart"
returnType = UnitType
}
afterHook {
// Your code here.
}
}
}
}
对于当前项目下没有的 Class
,你可以使用 stub
方式或 findClass
方法来得到需要 Hook 的类。
比如,我要得到 com.example.demo.TestClass
。
示例如下
findClass(name = "com.example.demo.TestClass").hook {
injectMember {
// Your code here.
}
}
若 com.example.demo
是你要 Hook 的 APP,那么写法可以更简单。
示例如下
findClass(name = "$packageName.TestClass").hook {
injectMember {
// Your code here.
}
}
到这里有些同学可能就开始说了,在某些场景下 findClass
显得有些繁琐。
因为可能有些同学有如下需求。
示例如下
const val TestClass = "com.example.demo.TestClass"
TestClass.hook {
injectMember {
// Your code here.
}
}
没关系,你还可以使用字符串类名直接创建一个 Hook。
示例如下
("$packageName.TestClass").hook {
injectMember {
// Your code here.
}
}
异常处理
YukiHookAPI
重新设计了对异常的监听,任何异常都不会在 Hook 过程中抛出,避免打断下一个 Hook 流程导致 Hook 进程“死掉”。
你可以处理 Hook 方法过程发生的异常。
示例如下
injectMember {
// Your code here.
}.result {
// 处理 Hook 开始时的异常
onHookingFailure {}
// 处理 Hook 过程中的异常
onConductFailure { param, throwable -> }
// 处理全部异常
onAllFailure {}
// ...
}
你还可以处理 Hook 的 Class
不存在时发生的异常。
示例如下
TargetClass.hook {
injectMember {
// Your code here.
}
}.onHookClassNotFoundFailure {
// Your code here.
}
你还可以处理查找方法时的异常。
示例如下
method {
// Your code here.
}.onNoSuchMethod {
// Your code here.
}
这里介绍了可能发生的常见异常,若要了解更多请参考 API 异常处理。
状态监听
在使用 XposedHelper
的同学往往会在 Hook 后打印 UnHook
的方法确定是否 Hook 成功。
在 YukiHookAPI
中,你可以用以下方法方便地重新实现这个功能。
首先我们可以监听 Hook 已经准备开始。
示例如下
YourClass.hook {
// Your code here.
}.onPrepareHook {
loggerD(msg = "$instanceClass hook start")
}
!> 请注意 instanceClass
建议只在 onPrepareHook
中使用,万一被 Hook 的 Class
不存在将会抛出无法拦截的异常导致 Hook 进程“死掉”。
然后,我们还可以对 Hook 的方法结果进行监听是否成功。
示例如下
injectMember {
// Your code here.
}.onHooked { member ->
loggerD(msg = "$member has hooked")
}
扩展用法
你可以在 Hook 过程中使用下面的方法方便地实现各种判断和功能。
多个宿主
如果你的模块需要同时处理多个 APP 的 Hook 事件,你可以使用 loadApp
方法体来区分你要 Hook 的 APP。
示例如下
loadApp(name = "com.android.browser") {
// Your code here.
}
loadApp(name = "com.android.phone") {
// Your code here.
}
详细用法可 点击这里 进行查看。
多个进程
如果你 Hook 的宿主 APP 有多个进程,你可以使用 withProcess
方法体来对它们分别进行 Hook。
示例如下
withProcess(mainProcessName) {
// Your code here.
}
withProcess(name = "$packageName:tool") {
// Your code here.
}
详细用法可 点击这里 进行查看。
写法优化
为了使代码更加简洁,你可以删去 YukiHookAPI
的名称,将你的 onHook
入口写作 lambda
形式。
示例如下
override fun onHook() = encase {
// Your code here.
}
Xposed 模块判断自身激活状态
通常情况下,我们会选择写一个方法,使其返回 false
,然后 Hook 掉这个方法使其返回 true
来证明 Hook 已经生效。
在 YukiHookAPI
中你完全不需要再这么做了,YukiHookAPI
已经帮你封装好了这个操作,你可以直接进行使用。
现在,你可以直接使用 isXposedModuleActive
在模块中判断自身是否被激活。
示例如下
if(isXposedModuleActive) {
// Your code here.
}
由于一些特殊原因,在太极、无极中的模块无法使用标准方法检测激活状态。
此时你可以在 Activity
中使用 isTaiChiModuleActive
判断自身是否被激活。
示例如下
if(isTaiChiModuleActive) {
// Your code here.
}
若你想使用两者得兼的判断方案,YukiHookAPI
同样为你封装了便捷的方式。
此时你可以在 Activity
中使用 isModuleActive
判断自身是否在 Xposed 或太极、无极中被激活。
示例如下
if(isModuleActive) {
// Your code here.
}
若要了解更多可 点击这里 进行查看。
!> 除了提供标准 API 的 Hook 框架之外,其它情况下模块可能都将无法判断自己是否被激活。