Tip: Refactoring Statement: The v.1.0.0 version is quite different from the previous version, and the new version of the tool is static, which is more in line with the characteristics of the tool, and has a better user experience and performance.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
dependencies {
// jitpack
implementation 'com.github.HChenX:HookTool:v.1.0.4'
// maven
implementation 'io.github.hchenx:hooktool:v.1.0.4'
// Choose one of the two
}
- Introduction to HCInit.
public void init() {
HCinit.initBasicData(); // Initialize the basic information of the module
HCinit.initStartupParam(); // Initialize the tool in the zygote phase
HCinit.initLoadPackageParam(); // Initialize the tool in the loadPackage phase
HCinit.xPrefsAutoReload(); // Whether to automatically update sharing preferences is enabled by default
HCinit.useLogExpand(); // For details about whether to use the log enhancement feature, see Method Annotation
}
- Initialize the tool at the Xposed entry.
@Override
public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) {
HCInit.initBasicData(new BasicData()
.setModulePackageName("com.hchen.demo") // Module package name
.setTag("HChenDemo") // Log tag
.setLogLevel(LOG_D) // Log level
.setPrefsName("hchen_prefs") // Prefs storage file name
); // If there is initZygote, it is recommended to configure it here because the timing is very early.
HCInit.initStartupParam(startupParam); // Initialize the tool in the zygote phase
}
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
HCInit.initBasicData(new BasicData()
.setModulePackageName("com.hchen.demo") // Module package name
.setTag("HChenDemo") // Log tag
.setLogLevel(LOG_D) // Log level
.setPrefsName("hchen_prefs") // Prefs stores the file name. Tip: Please keep the file name consistent.
);
}
- If you need to use the prefs tool or use the log class of this tool in the module, then you also need to initialize it on the main interface of the module.
public static class MainActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
HCInit.initBasicData(/* The package name of your module */, /* tag */, /* Log level */); // 必须
}
}
- Called at the code
public class MainTest {
public void test() {
CoreTool.hook(/* content */); // To hook it
CoreTool.findClass(); // Find the class
CoreTool.callMethod(); // Call the method
ChainTool.chain("com.hchen.demo", new ChainTool()
.method("method")
.hook()
.method("method")
.hook()
); // Can be chained
PrefsTool.prefs().getString(); // To read the sharing preferences
// ......
}
}
- Of course, you can also directly inherit the packaged classes of this tool.
- // extends BaseHC is highly recommended!
// Hook
public class MainTest extends BaseHC {
@Override
public void init() {
//BaseHC extends the CoreTool tool, which can be called directly.
}
// Optional.
// The timing is zygote.
// The use of initZygote must be initialized at the hook entrance: HCInit.initStartupParam(startupParam);
@Override
public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) {
findClass("com.hchen.demo.Main", classLoader); // In this phase, you need to pass classLoader or an error will be reported.
}
}
// Caller
public class RunHook implements IXposedHookLoadPackage, IXposedHookZygoteInit {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) {
new MainTest().onLoadPackage(); // The hook can be executed in the loadPackage phase.
}
@Override
public void initZygote(StartupParam startupParam) {
new MainTest().onZygote(); // initZygote Hook.
}
}
- Obfuscated configuration:
// If you don't need to use the log enhancements, you can also just join (for the case of inherited BaseHC use):
-keep class * extends com.hchen.hooktool.BaseHC
// If the directory where you store the hook file is com. hchen. demo. hook
// If you need to use logging enhancements, it is recommended to include obfuscation rules:
// If there are multiple directories, it is recommended that you add them separately.
-keep class com.hchen.demo.hook.**
-keep class com.hchen.demo.hook.**$*
// If you don't extends BaseHC usage or use log enhancements, you don't need to configure obfuscation rules.
- Now that all the work is done, you can use it happily!
- This tool supports chaining calls and uses the chain() method to create chains.
- This is a new chain solution provided by this tool refactoring, is it more concise and efficient?
- Code examples:
// Chained calls
public class MainTest extends BaseHC {
public void test() {
// See! Isn't it concise and easy to understand?
chain("com.hchen.demo", method("test")
.hook(new IAction() {
@Override
public void before() {
super.before();
}
})
.anyMethod("test")
.hook(new IAction() {
@Override
public void after() {
super.after();
}
})
.constructor()
.returnResult(false)
);
}
}
- The various methods of the traditional Xposed MethodHookParam are all Objects. This makes it necessary to type explicitly in order to use it.
- This tool makes full use of generics, so you don't need to type explicitly anymore!
public class MainTest extends BaseHC {
@Override
public void init() {
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
Context context = (Context) param.thisObject;
String string = (String) param.args[0];
param.args[1] = 1;
String result = (String) XposedHelpers.callMethod(param.thisObject, "call",
param.thisObject, param.args[0]);
XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.demo.Main", ClassLoader.getSystemClassLoader()),
"callStatic", param.thisObject, param.args[1]);
int i = (int) XposedHelpers.getStaticObjectField(XposedHelpers.findClass("com.demo.Main", ClassLoader.getSystemClassLoader()),
"field");
}
};
new IAction() {
@Override
public void before() {
Context context = thisObject(); // There is no need to convert explicitly
String string = first(); // More intuitive parameter acquisition :)
second(1); // More intuitive parameterization :)
// non static
setThisField("demo", 1);
callThisMethod("method",...);
// Non-static outside of this class
setField(obj, "demo", 1);
callMethod(obj, "method");
// Static requires class
callStaticMethod("com.demo.Main", "callStatic", thisObject(), second());
int i = getStaticField("com.demo.Main", "field");
setStaticField("com.demo.Main", "test", true);
removeSelf(); // You can call this method to invalidate the hook itself
observeCall(); // Observe the call
getStackTrace(); // Get the stack
}
};
}
}
- Tools provide a comprehensive set of methods for you to call.
- including:
- ContextTool class:
- More convenient access context.
public class MainTest {
public void test() {
// This is the easiest way to obtain context
Context context = ContextTool.getContext(ContextUtils.FLAG_ALL);
}
}
- InvokeTool class:
- More convenient and robust reflection classes.
public class MainTest {
public void test() {
// The same applies to the reflection method, and the same applies to other reflection operations.
InvokeTool.callMethod(InvokeTool.findClass("com.hchen.demo.Main",
getClass().getClassLoader()), "test", new Class[]{});
}
}
- PropTool class:
- A more convenient tool for prop reading and modification.
public class MainTest {
public void test() {
// A prop can only be set if it is called in the system framework
PropTool.setProp("ro.test.prop", "1");
// You can get it at will
String result = PropTool.getProp("ro.test.prop");
}
}
- PrefsTool class:
- Provides the function of prefs read modification.
// Parasitic in-app
public class MainTest extends BaseHC {
@Override
public void init() {
// xprefs mode:
// Note the xprefs mode, the parasitic application cannot modify the configuration and can only read.
String s = prefs().getString("test", "1"); // To read
s = prefs("myPrefs").getString("test", "1"); // You can specify the name of the read file
// sprefs mode:
// The configuration is saved to the private directory of the parasitic application, and the reads are also read from the private directory of the parasitic application.
prefs(context).editor().putString("test", "1").commit();
// If there is no extends BaseHC can be called like this.
PrefsTool.prefs(context).editor().putString("test", "2").commit();
// Note that the sprefs pattern is separate from the xprefs pattern and can co-exist.
// If it's not convenient to get the context, you can use this method to get the parasitic app context asynchronously before setting it.
asyncPrefs(new PrefsTool.IAsyncPrefs() {
@Override
public void async(Context context) {
prefs(context).editor().putString("test", "1").commit();
}
});
}
}
// Module
public static class MainActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// !!!If you are using the xprefs mode, call PrefsTool.prefs(context) on the main interface of the module; Initialize it, otherwise it may not be available ! !
PrefsTool.prefs(this); // or
PrefsTool.prefs(this,/* Your own prefs name */);
// Usage
prefs(this).editor().putString("test", "1").commit();
prefs(this, "myPrefs").editor().putString("test", "1").commit();
}
}
- CoreTool class:
- A complete hook method is available!
- Absolutely satisfying the needs!
- DeviceTool class:
- Convenient access to basic system information.
- See source code and comments for details.
- ResTool class:
- Inject module resources into the target scope.
- For details, see Source Code and Comments.
- PackagesTool class:
- Get package information quickly!
- BitmapTool class:
- Convert Drawable to Bitmap
- More is on the way···
- This tool was used for the following projects!
Project Name | Project Link |
---|---|
ForegroundPin | ForegroundPin |
AutoSEffSwitch | AutoSEffSwitch |
- If your project uses this tool, let me know and I'll add it to the form.
- If you want to know more about this tool, you can also refer to the above items, I hope it will help you!
-
This tool is based on:
-
Please specify when using this tool.
- Thank you for your willingness to use this tool! Enjoy your day!
♥️