https://github.com/LuckyPray/DexKit
An easy-to-use, high-performance dex deobfuscation library.
https://github.com/LuckyPray/DexKit
deobfuscation dex high-performance library native-module xposed
Last synced: 7 months ago
JSON representation
An easy-to-use, high-performance dex deobfuscation library.
- Host: GitHub
- URL: https://github.com/LuckyPray/DexKit
- Owner: LuckyPray
- License: lgpl-3.0
- Created: 2022-07-26T11:12:01.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2024-12-19T05:07:35.000Z (10 months ago)
- Last Synced: 2024-12-19T05:28:23.576Z (10 months ago)
- Topics: deobfuscation, dex, high-performance, library, native-module, xposed
- Language: Kotlin
- Homepage: https://luckypray.org/DexKit/
- Size: 2.6 MB
- Stars: 483
- Watchers: 13
- Forks: 60
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
DexKit
[](https://www.gnu.org/licenses/lgpl-3.0.html)
[](https://central.sonatype.com/search?q=dexkit&namespace=org.luckypray)
[](https://t.me/LuckyPray_DexKit)English | [简体中文](https://github.com/LuckyPray/DexKit/blob/master/README_zh.md)
A high-performance runtime parsing library for dex implemented in C++, used for lookup of obfuscated classes,
methods, or properties.---
# DexKit 2.0
Currently 2.0 has been officially released, please refer to Release Notes for related improvements.
## Supported APIs
Basic Features:
- [x] Multi-condition class search
- [x] Multi-condition method search
- [x] Multi-condition field search
- [x] Provides multiple metadata APIs to obtain field/method/class related data⭐️ Distinctive Features (Recommended):
- [x] Batch search of classes using strings
- [x] Batch search of methods using strings> Note: Optimizations have been implemented for string search scenarios, significantly enhancing
> search speed. Increasing query groups will not lead to a linear increase in time consumption.### Documentation
- [Click here](https://luckypray.org/DexKit/en/) to go to the documentation page to view more detailed tutorials.
### Dependencies
Add `dexkit` dependency in `build.gradle`.
```gradle
repositories {
mavenCentral()
}
dependencies {
// replace with your desired version, e.g. `2.0.0`
implementation 'org.luckypray:dexkit:'
}
```> **Note**
> Starting with **DexKit 2.0**, the new ArtifactId has been changed from `DexKit` to `dexkit`.DexKit current version: [](https://central.sonatype.com/search?q=dexkit&namespace=org.luckypray)
## Usage Example
Here's a simple usage example.
Suppose this class is what we want to obtain, with most of its names obfuscated and changing in each version.
> Sample app:
```java
package org.luckypray.dexkit.demo;import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.h;
import java.util.Random;
import org.luckypray.dexkit.demo.annotations.Router;@Router(path = "/play")
public class PlayActivity extends AppCompatActivity {
private static final String TAG = "PlayActivity";
private TextView a;
private Handler b;public void d(View view) {
Handler handler;
int i;
Log.d("PlayActivity", "onClick: rollButton");
float nextFloat = new Random().nextFloat();
if (nextFloat < 0.01d) {
handler = this.b;
i = -1;
} else if (nextFloat < 0.987f) {
handler = this.b;
i = 0;
} else {
handler = this.b;
i = 114514;
}
handler.sendEmptyMessage(i);
}public void e(boolean z) {
int i;
if (!z) {
i = RandomUtil.a();
} else {
i = 6;
}
String a = h.a("You rolled a ", i);
this.a.setText(a);
Log.d("PlayActivity", "rollDice: " + a);
}protected void onCreate(Bundle bundle) {
super/*androidx.fragment.app.FragmentActivity*/.onCreate(bundle);
setContentView(0x7f0b001d);
Log.d("PlayActivity", "onCreate");
HandlerThread handlerThread = new HandlerThread("PlayActivity");
handlerThread.start();
this.b = new PlayActivity$1(this, handlerThread.getLooper());
this.a = (TextView) findViewById(0x7f080134);
((Button) findViewById(0x7f08013a)).setOnClickListener(new a(this));
}
}
```At this point, to obtain this class, you can use the following code:
> This is just an example, in actual usage, there's no need for such an extensive set of matching
> conditions. Choose and use as needed to avoid unnecessary complexity in matching due to an
> excessive number of conditions.Java Example
```java
public class MainHook implements IXposedHookLoadPackage {
static {
System.loadLibrary("dexkit");
}
private ClassLoader hostClassLoader;
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) {
String packageName = loadPackageParam.packageName;
String apkPath = loadPackageParam.appInfo.sourceDir;
if (!packageName.equals("org.luckypray.dexkit.demo")) {
return;
}
this.hostClassLoader = loadPackageParam.classLoader;
// 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)) {
findPlayActivity(bridge);
// Other use cases
}
}
private void findPlayActivity(DexKitBridge bridge) {
ClassData classData = bridge.findClass(FindClass.create()
// Search within the specified package name range
.searchPackages("org.luckypray.dexkit.demo")
// Exclude the specified package name range
.excludePackages("org.luckypray.dexkit.demo.annotations")
.matcher(ClassMatcher.create()
// ClassMatcher Matcher for classes
.className("org.luckypray.dexkit.demo.PlayActivity")
// FieldsMatcher Matcher for fields in a class
.fields(FieldsMatcher.create()
// Add a matcher for the field
.add(FieldMatcher.create()
// Specify the modifiers of the field
.modifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
// Specify the type of the field
.type("java.lang.String")
// Specify the name of the field
.name("TAG")
)
// Add a matcher for the field of the specified type
.addForType("android.widget.TextView")
.addForType("android.os.Handler")
// Specify the number of fields in the class
.count(3)
)
// MethodsMatcher Matcher for methods in a class
.methods(MethodsMatcher.create()
// Add a matcher for the method
.methods(List.of(
MethodMatcher.create()
// Specify the modifiers of the method
.modifiers(Modifier.PROTECTED)
// Specify the name of the method
.name("onCreate")
// Specify the return type of the method
.returnType("void")
// Specify the parameter type of the method
.paramTypes("android.os.Bundle")
// Specify the strings used by the method
.usingStrings("onCreate"),
MethodMatcher.create()
.paramTypes("android.view.View")
// Specify the numbers used in the method, the type is Byte, Short, Int, Long, Float, Double
.usingNumbers(0.01, -1, 0.987, 0, 114514),
MethodMatcher.create()
.modifiers(Modifier.PUBLIC)
.paramTypes("boolean")
// Specify the method invoke the methods list
.invokeMethods(MethodsMatcher.create()
.add(MethodMatcher.create()
.modifiers(Modifier.PUBLIC | Modifier.STATIC)
.returnType("int")
// be invoke method using strings
.usingStrings(List.of("getRandomDice: "), StringMatchType.Equals)
)
// Only need to contain the call to the above method
.matchType(MatchType.Contains)
)
))
// Specify the number of methods in the class, a minimum of 1, and a maximum of 10
.count(1, 10)
)
// AnnotationsMatcher Matcher for annotations in a class
.annotations(AnnotationsMatcher.create()
// Add a matcher for the annotation
.add(AnnotationMatcher.create()
// Specify the type of the annotation
.type("org.luckypray.dexkit.demo.annotations.Router")
// The annotation needs to contain the specified element
.addElement(AnnotationElementMatcher.create()
// Specify the name of the element
.name("path")
// Specify the value of the element
.stringValue("/play")
)
)
)
// Strings used by all methods in the class
.usingStrings("PlayActivity", "onClick", "onCreate")
)
).singleOrThrow(() -> new IllegalStateException("The returned result is not unique"));
// Print the found class: org.luckypray.dexkit.demo.PlayActivity
System.out.println(classData.getName());
// Get the corresponding class instance
Class> clazz = classData.getInstance(loadPackageParam.classLoader);
}
}
```Kotlin Example
```kotlin
class MainHook : IXposedHookLoadPackage {
companion object {
init {
System.loadLibrary("dexkit")
}
}private lateinit var hostClassLoader: ClassLoader
override fun handleLoadPackage(loadPackageParam: XC_LoadPackage.LoadPackageParam) {
val packageName = loadPackageParam.packageName
val apkPath = loadPackageParam.appInfo.sourceDir
if (!packageName.equals("org.luckypray.dexkit.demo")) {
return
}
this.hostClassLoader = loadPackageParam.classLoader
// 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 ->
findPlayActivity(bridge)
// Other use cases
}
}private fun findPlayActivity(bridge: DexKitBridge) {
val classData = bridge.findClass {
// Search within the specified package name range
searchPackages("org.luckypray.dexkit.demo")
// Exclude the specified package name range
excludePackages("org.luckypray.dexkit.demo.annotations")
// ClassMatcher Matcher for classes
matcher {
// FieldsMatcher Matcher for fields in a class
fields {
// Add a matcher for the field
add {
// Specify the modifiers of the field
modifiers = Modifier.PRIVATE or Modifier.STATIC or Modifier.FINAL
// Specify the type of the field
type = "java.lang.String"
// Specify the name of the field
name = "TAG"
}
// Add a matcher for the field of the specified type
addForType("android.widget.TextView")
addForType("android.os.Handler")
// Specify the number of fields in the class
count = 3
}
// MethodsMatcher Matcher for methods in a class
methods {
// Add a matcher for the method
add {
// Specify the modifiers of the method
modifiers = Modifier.PROTECTED
// Specify the name of the method
name = "onCreate"
// Specify the return type of the method
returnType = "void"
// Specify the parameter types of the method, if the parameter types are uncertain,
// use null, and this method will implicitly declare the number of parameters
paramTypes("android.os.Bundle")
// Specify the strings used in the method
usingStrings("onCreate")
}
add {
paramTypes("android.view.View")
// Specify the numbers used in the method, the type is Byte, Short, Int, Long, Float, Double
usingNumbers(0.01, -1, 0.987, 0, 114514)
}
add {
paramTypes("boolean")
// Specify the methods called in the method list
invokeMethods {
add {
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "int"
// Specify the strings used in the method called in the method,
usingStrings(listOf("getRandomDice: "), StringMatchType.Equals)
}
// Only need to contain the call to the above method
matchType = MatchType.Contains
}
}
count(1..10)
}
// AnnotationsMatcher Matcher for annotations in a class
annotations {
// Add a matcher for the annotation
add {
// Specify the type of the annotation
type = "org.luckypray.dexkit.demo.annotations.Router"
// The annotation needs to contain the specified element
addElement {
// Specify the name of the element
name = "path"
// Specify the value of the element
stringValue("/play")
}
}
}
// Strings used by all methods in the class
usingStrings("PlayActivity", "onClick", "onCreate")
}
}.singleOrNull() ?: error("The returned result is not unique")
// Print the found class: org.luckypray.dexkit.demo.PlayActivity
println(classData.name)
// Get the corresponding class instance
val clazz = classData.getInstance(loadPackageParam.classLoader)
}
}
```## Third-Party Open Source References
- [slicer](https://cs.android.com/android/platform/superproject/+/main:tools/dexter/slicer/)
- [ThreadPool](https://github.com/progschj/ThreadPool)
- [parallel-hashmap](https://github.com/greg7mdp/parallel-hashmap)## Star History
[](https://star-history.com/#luckypray/dexkit&Date)
## License
[LGPL-3.0](https://www.gnu.org/licenses/lgpl-3.0.html) © LuckyPray