dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.HChenX:HookTool:v.2.1.1'
}
- HCInit 介绍
public void init() {
HCInit.initBasicData(); // 初始化模块基本信息
HCInit.initStartupParam(); // zygote 阶段初始化工具
HCInit.initLoadPackageParam(); // loadPackage 阶段初始化工具
HCInit.setClassLoader(); // 更换全局 Classloader
}
- 在 Hook 入口处初始化本工具
public class HookInit extends HCEntrance /* 建议继承 HCEntrance 类作为入口 */ {
@NonNull
@Override
public HCInit.BasicData initHC(@NonNull HCInit.BasicData basicData) {
return basicData
.setModulePackageName("com.hchen.demo") // 模块包名
.setTag("HChenDemo") // 日志 tag
.setLogLevel(LOG_D) // 日志等级
.setPrefsName("hchen_prefs") // prefs 文件名 (可选)
.setAutoReload(true) // 是否自动更新共享首选项,默认开启 (可选)
.setLogExpandPath("com.hchen.demo.hook") // 日志增强功能 (可选)
.setLogExpandIgnoreClassNames("Demo"); // 排除指定类名 (可选)
}
@NonNull
@Override
public String[] ignorePackageNameList() {
// 指定忽略的包名
return new String[]{
"com.android.test"
};
}
@Override
public void onModuleLoad(@NonNull XC_LoadPackage.LoadPackageParam loadPackageParam) {
super.onModuleLoad(loadPackageParam); // 模块自身被加载时调用
}
@Override
public void onLoadPackage(@NonNull XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
HCInit.initLoadPackageParam(loadPackageParam); // 必须,初始化工具
new HookDemo().onApplication().onLoadPackage(); // 添加 onApplication 后才会执行 onApplication() 回调,onLoadPackage 方法必须调用
}
@Override
public void onInitZygote(@NonNull StartupParam startupParam) throws Throwable {
new HookDemo().onZygote();
}
}
- 在模块主界面初始化
public class Application extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
HCInit.initBasicData(new HCInit.BasicData()
.setModulePackageName("com.hchen.demo") // 模块包名
.setTag("HChenDemo") // 日志 tag
.setLogLevel(LOG_D) // 日志等级
.setPrefsName("hchen_prefs") // prefs 存储文件名 (可选)
);
}
}
- Hook 类内强烈建议继承 HCBase 使用!
public class HookDemo extends HCBase /* 建议继承 HCBase 使用 */ {
@Override
protected boolean isEnabled() {
// 是否启用本 Hook
return super.isEnabled();
}
@Override
protected void init() { // loadPackage 阶段
boolean isExists = existsClass("com.hchen.demo.Demo"); // 是否存在类
Class<?> clazz = findClass("com.hchen.demo.Demo"); // 查找类
hookMethod("com.hchen.demo.Demo", "demo", boolean.class, new IHook() {
@Override
public void before() {
// 在 demo 方法调用前执行
// 可以拦截方法执行,或者修改方法参数值
setResult(true); // 拦截并返回 true
setArg(0, false); // 设置方法第一个参数为 false
}
@Override
public void after() {
// 在 demo 方法执行后调用
// 可以用于修改方法返回结果
setResult(true);
}
@Override
public boolean onThrow(int flag, Throwable e) {
// before 或者 after 内代码抛错时会调用
// 返回 true 代表已处理异常,工具将不会自动处理
return super.onThrow(flag, e);
}
});
}
@Override
protected void init(@NonNull ClassLoader classLoader) { // loadPackage 阶段
// 区别是可以指定自定义的 classloader
findClass("com.hchen.demo.Demo", classLoader);
}
@Override
protected void initZygote(@NonNull IXposedHookZygoteInit.StartupParam startupParam) { // zygote 阶段
// 一般不会用到这个时机
findClass("com.hchen.demo.Demo", startupParam.getClass().getClassLoader()); // 可以这样写
}
@Override
protected void onApplication(@NonNull Context context) {
// 目标应用创建 context 时回调
}
@Override
protected void onThrowable(int flag, @NonNull Throwable e) {
// 上述方法发生抛错时调用,你可以在此处执行清理操作,不建议继续执行 Hook 逻辑
}
}
- 混淆配置:
// 如果你不需要使用日志增强功能,也可以只加入 (对于继承 HCBase 使用的情况):
-keep class * extends com.hchen.hooktool.HCBase
// 如果需要使用日志增强功能,那么建议加入混淆规则:
// 假设存放 hook 类的目录为 com.hchen.demo.hook
// 如果有多个存放的目录,建议都分别加入。
-keep class com.hchen.demo.hook.**
-keep class com.hchen.demo.hook.**$*
// 其他建议配置:
-keep class com.hchen.hooktool.HCState {
private final static boolean isXposedEnabled;
private final static java.lang.String framework;
private final static int version;
}
-keep class * implements android.os.Parcelable {
public static ** CREATOR;
}
- 到此完成全部工作,可以愉快的使用了!
- 本工具支持链式调用,使用 buildChain() 方法创建链式。
- 这是本工具重构提供的全新链式方案,是否更简洁高效了呢?
- 代码示例:
// 链式调用
public class MainTest extends HCBase {
public void test() {
// 看!是不是很简洁易懂?
buildChain("com.hchen.demo")
.findMethod("test")
.hook(new IHook() {
@Override
public void before() {
super.before();
}
})
.findAllMethod("test")
.hook(new IHook() {
@Override
public void after() {
super.after();
}
})
.findConstructor()
.returnResult(false);
}
}
- 工具提供了全面丰富的方法供你调用
- 包括:
- ContextTool 类:
- 更方便的获取 context
public class MainTest {
public void test() {
// 即可最简单的获取 context
Context context = ContextTool.getContext(ContextUtils.FLAG_ALL);
}
}
- InvokeTool 类:
- 更方便稳健的反射类
public class MainTest {
public void test() {
// 即可反射调用方法,其他反射操作同理
InvokeTool.callMethod(InvokeTool.findClass("com.hchen.demo.Main"), "test", new Class[]{});
}
}
- SystemPropTool 类:
- 更方便的 prop 读取修改工具
public class MainTest {
public void test() {
// 只能在系统框架中调用才能设置 persist 类型的 prop
SystemPropTool.setProp("persist.test.prop", "1");
// 获取应该可以随意
String result = SystemPropTool.getProp("persist.test.prop");
}
}
- PrefsTool 类:
- 提供 prefs 读取修改功能
public class HookDemo extends HCBase {
@Override
public void init() {
// xprefs 模式:
// 注意 xprefs 模式,寄生应用不能修改配置只能读取
String s = prefs().getString("test", "1"); // 即可读取
s = prefs("myPrefs").getString("test", "1"); // 可指定读取文件名
// sprefs 模式:
// 配置会保存到寄生应用的私有目录,读取也会从寄生应用私有目录读取
prefs(context).editor().putString("test", "1").commit();
// 如果没有继承 HCBase 可以这样调用
PrefsTool.prefs(context).editor().putString("test", "2").commit();
// 注意 sprefs 模式 是和 xprefs 模式相互独立的,可共同存在
// 如果不方便获取 context 可用使用此方法,异步获取寄生应用上下文后再设置
asyncPrefs(new IAsyncPrefs() {
@Override
public void async(@NonNull IPrefsApply sPrefs) {
sPrefs.editor().put("test", "1").commit();
}
});
}
}
public class Application extends android.app.Application {
@Override
protected void onCreate() {
// 重要提醒:
// 如果需要使用 xprefs 模式,请务必在模块主界面调用 PrefsTool.prefs(context); 进行初始化,否则可能不可用!
PrefsTool.prefs(this); // 或
PrefsTool.prefs(this,/* 你自己的 prefs 名称 */);
// 使用方法
prefs(this).editor().putString("test", "1").commit();
prefs(this, "myPrefs").editor().putString("test", "1").commit();
}
}
- ShellTool 类:
- 提供简易的执行 Shell 命令的能力
- 使用方法:
public class MainTest {
public void test() {
ShellTool shellTool = ShellTool.builder().isRoot(true).create();
shellTool = ShellTool.obtain();
ShellResult shellResult = shellTool.cmd("ls").exec();
if (shellResult != null) {
boolean result = shellResult.isSuccess();
}
shellTool.cmd("""
if [[ 1 == 1 ]]; then
echo hello;
elif [[ 1 == 2 ]]; then
echo world;
fi
""").exec();
shellTool.cmd("echo hello").async();
shellTool.cmd("echo world").async(new IExecListener() {
@Override
public void output(@NonNull String command, @NonNull String[] outputs, @NonNull String exitCode) {
IExecListener.super.output(command, outputs, exitCode);
}
});
shellTool.addExecListener(new IExecListener() {
@Override
public void output(@NonNull String command, @NonNull String[] outputs, @NonNull String exitCode) {
IExecListener.super.output(command, outputs, exitCode);
}
@Override
public void error(@NonNull String command, @NonNull String[] errors, @NonNull String exitCode) {
IExecListener.super.error(command, errors, exitCode);
}
@Override
public void notRoot(@NonNull String exitCode) {
IExecListener.super.notRoot(exitCode);
}
@Override
public void brokenPip(@NonNull String command, @NonNull String[] errors, @NonNull String reason) {
IExecListener.super.brokenPip(command, errors, reason);
}
});
shellTool.close();
}
}
- CoreTool 类:
- 提供完善的 Hook 方法!
- 绝对满足需求!
- DeviceTool 类:
- 方便的获取系统基本信息
- 具体参见源代码和注释
- ResInjectTool 类:
- 将模块资源注入目标作用域
- 具体参见源代码与注释
- PackagesTool 类:
- 快速获取软件包信息!
- 其他更多精彩正在加载···
- 以下项目使用了本工具!
项目名称 | 项目链接 |
---|---|
AppRetentionHook | AppRetentionHook |
AutoSEffSwitch | AutoSEffSwitch |
SwitchFreeForm | SwitchFreeForm |
ForegroundPin | ForegroundPin |
ClipboardList | ClipboardList |
SuperLyric | SuperLyric |
- 如果你的项目使用了本工具,可以告诉我,我将会把其加入表格
- 想要详细了解本工具也可以参考上述项目,希望给你带来帮助!
- 感谢您愿意使用本工具!Enjoy your day!
♥️