DexKit
A high-performance dex runtime parsing library implemented in C++
Elegant and Simple
DexKit is built with a user-friendly API entirely using Kotlin DSL, supporting nested complex queries and providing good support for Java as well.
High-Performance
Implemented using C++ at its core, DexKit delivers superior performance. It utilizes multiple algorithms on top of multithreading, allowing it to complete complex searches in an extremely short time.
Cross-platform
It offers multi-platform support. After testing on Windows, Linux, or MacOS, the code can be directly migrated to the Android platform.
Ultimate Experience, Say No to Tediousness
Example Code
Assume this is obfuscated code from a host app. We need to dynamically adapt the hook for this method. Due to obfuscation, method names and class names may change with each version.
public class abc {
public boolean cvc() {
boolean b = false;
// ...
Log.d("VipCheckUtil", "userInfo: xxxx");
// ...
return b;
}
}
DexKit can easily solve this problem!
Xposed hook code
By creating an instance of
DexKitBridge
, we can perform specific searches on the app's dex file.
warning
Only one instance of DexKitBridge
needs to be created. If you do not wish to use try-with-resources or Kotlin's .use for automatic closing of the DexKitBridge
instance, you need to manage its lifecycle manually. Ensure to call .close()
when it's no longer needed to prevent memory leaks.
class AppHooker {
companion object {
init { System.loadLibrary("dexkit") }
}
private var hostClassLoader: ClassLoader
public constructor(loadPackageParam: LoadPackageParam) {
this.hostClassLoader = loadPackageParam.classLoader
val apkPath = loadPackageParam.appInfo.sourceDir
// DexKit creation is a time-consuming operation, please do not create the object repeatedly.
// If you need to use it globally, please manage the life cycle yourself and ensure
// that the .close() method is called when not needed to prevent memory leaks.
// Here we use `Closable.use` to automatically close the DexKitBridge instance.
DexKitBridge.create(apkPath).use { bridge ->
isVipHook(bridge)
// Other hook ...
}
}
private fun isVipHook(bridge: DexKitBridge) {
val methodData = bridge.findMethod {
matcher {
// All conditions are optional, you can freely combine them
modifiers = Modifier.PUBLIC
returnType = "boolean"
paramCount = 0
usingStrings("VipCheckUtil", "userInfo:")
}
}.single()
val method: Method = methodData.getMethodInstance(hostClassLoader)
XposedBridge.hookMethod(method, XC_MethodReplacement.returnConstant(true))
}
// ...
}
class AppHooker {
static {
System.loadLibrary("dexkit");
}
private ClassLoader hostClassLoader;
public AppHooker(LoadPackageParam loadPackageParam) {
this.hostClassLoader = loadPackageParam.classLoader;
String apkPath = loadPackageParam.appInfo.sourceDir;
// DexKit creation is a time-consuming operation, please do not create the object repeatedly.
// If you need to use it globally, please manage the life cycle yourself and ensure
// that the .close() method is called when not needed to prevent memory leaks.
// Here we use `try-with-resources` to automatically close the DexKitBridge instance.
try (DexKitBridge bridge = DexKitBridge.create(apkPath)) {
isVipHook(bridge);
// Other hook ...
}
}
private void isVipHook(DexKitBridge bridge) {
MethodData methodData = bridge.findMethod(FindMethod.create()
.matcher(MethodMatcher.create()
// All conditions are optional, you can freely combine them
.modifiers(Modifier.PUBLIC)
.paramCount(0)
.returnType("boolean")
.usingStrings("VipCheckUtil", "userInfo:")
)
).single();
Method method = methodData.getMethodInstance(hostClassLoader);
XposedBridge.hookMethod(method, XC_MethodReplacement.returnConstant(true));
}
// ...
}
It's that simple!