capacitor-dex-editor 0.0.62 → 0.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +18 -0
- package/android/src/main/java/com/aetherlink/dexeditor/DexManager.java +70 -3
- package/android/src/main/java/com/aetherlink/dexeditor/RustDex.java +86 -0
- package/android/src/main/jniLibs/arm64-v8a/libdex_rust.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libdex_rust.so +0 -0
- package/android/src/main/jniLibs/x86/libdex_rust.so +0 -0
- package/android/src/main/jniLibs/x86_64/libdex_rust.so +0 -0
- package/package.json +1 -1
package/android/build.gradle
CHANGED
|
@@ -9,13 +9,16 @@ buildscript {
|
|
|
9
9
|
repositories {
|
|
10
10
|
google()
|
|
11
11
|
mavenCentral()
|
|
12
|
+
maven { url "https://plugins.gradle.org/m2/" }
|
|
12
13
|
}
|
|
13
14
|
dependencies {
|
|
14
15
|
classpath 'com.android.tools.build:gradle:8.7.2'
|
|
16
|
+
classpath 'org.mozilla.rust-android-gradle:plugin:0.9.6'
|
|
15
17
|
}
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
apply plugin: 'com.android.library'
|
|
21
|
+
apply plugin: 'org.mozilla.rust-android-gradle.rust-android'
|
|
19
22
|
|
|
20
23
|
android {
|
|
21
24
|
namespace "com.aetherlink.dexeditor"
|
|
@@ -72,3 +75,18 @@ dependencies {
|
|
|
72
75
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
73
76
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
74
77
|
}
|
|
78
|
+
|
|
79
|
+
// Rust 编译配置
|
|
80
|
+
cargo {
|
|
81
|
+
module = "../rust"
|
|
82
|
+
libname = "dex_rust"
|
|
83
|
+
targets = ["arm", "arm64", "x86", "x86_64"]
|
|
84
|
+
profile = "release"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 将 Rust 编译任务添加到构建流程
|
|
88
|
+
tasks.configureEach { task ->
|
|
89
|
+
if ((task.name == 'javaPreCompileDebug' || task.name == 'javaPreCompileRelease')) {
|
|
90
|
+
task.dependsOn 'cargoBuild'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -150,6 +150,7 @@ public class DexManager {
|
|
|
150
150
|
String sessionId;
|
|
151
151
|
String apkPath;
|
|
152
152
|
Map<String, DexBackedDexFile> dexFiles;
|
|
153
|
+
Map<String, byte[]> dexBytes; // DEX 字节数据,用于 Rust 搜索
|
|
153
154
|
Map<String, ClassDef> modifiedClasses;
|
|
154
155
|
// 使用 LRU 缓存限制内存,最多缓存 200 个类
|
|
155
156
|
Map<String, String> smaliCache = new java.util.LinkedHashMap<String, String>(200, 0.75f, true) {
|
|
@@ -164,11 +165,15 @@ public class DexManager {
|
|
|
164
165
|
this.sessionId = sessionId;
|
|
165
166
|
this.apkPath = apkPath;
|
|
166
167
|
this.dexFiles = new HashMap<>();
|
|
168
|
+
this.dexBytes = new HashMap<>();
|
|
167
169
|
this.modifiedClasses = new HashMap<>();
|
|
168
170
|
}
|
|
169
171
|
|
|
170
|
-
void addDex(String dexName, DexBackedDexFile dexFile) {
|
|
172
|
+
void addDex(String dexName, DexBackedDexFile dexFile, byte[] bytes) {
|
|
171
173
|
this.dexFiles.put(dexName, dexFile);
|
|
174
|
+
if (bytes != null) {
|
|
175
|
+
this.dexBytes.put(dexName, bytes);
|
|
176
|
+
}
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
179
|
|
|
@@ -1638,10 +1643,11 @@ public class DexManager {
|
|
|
1638
1643
|
baos.write(buffer, 0, len);
|
|
1639
1644
|
}
|
|
1640
1645
|
is.close();
|
|
1646
|
+
byte[] dexData = baos.toByteArray();
|
|
1641
1647
|
|
|
1642
1648
|
// 解析 DEX
|
|
1643
|
-
DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.getDefault(),
|
|
1644
|
-
multiSession.addDex(dexName, dexFile);
|
|
1649
|
+
DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.getDefault(), dexData);
|
|
1650
|
+
multiSession.addDex(dexName, dexFile, dexData);
|
|
1645
1651
|
totalClasses += dexFile.getClasses().size();
|
|
1646
1652
|
|
|
1647
1653
|
Log.d(TAG, "Loaded DEX: " + dexName + " with " + dexFile.getClasses().size() + " classes");
|
|
@@ -1759,6 +1765,7 @@ public class DexManager {
|
|
|
1759
1765
|
|
|
1760
1766
|
/**
|
|
1761
1767
|
* 在多 DEX 会话中搜索
|
|
1768
|
+
* 优先使用 Rust 实现,如果不可用则回退到 Java 实现
|
|
1762
1769
|
*/
|
|
1763
1770
|
public JSObject searchInMultiSession(String sessionId, String query, String searchType,
|
|
1764
1771
|
boolean caseSensitive, int maxResults) throws Exception {
|
|
@@ -1767,6 +1774,16 @@ public class DexManager {
|
|
|
1767
1774
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
1768
1775
|
}
|
|
1769
1776
|
|
|
1777
|
+
// 尝试使用 Rust 实现进行搜索
|
|
1778
|
+
if (RustDex.isAvailable() && !session.dexBytes.isEmpty()) {
|
|
1779
|
+
try {
|
|
1780
|
+
return searchWithRust(session, query, searchType, caseSensitive, maxResults);
|
|
1781
|
+
} catch (Exception e) {
|
|
1782
|
+
Log.w(TAG, "Rust search failed, falling back to Java: " + e.getMessage());
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// Java 回退实现
|
|
1770
1787
|
JSObject result = new JSObject();
|
|
1771
1788
|
JSArray results = new JSArray();
|
|
1772
1789
|
String queryMatch = caseSensitive ? query : query.toLowerCase();
|
|
@@ -1883,6 +1900,56 @@ public class DexManager {
|
|
|
1883
1900
|
return result;
|
|
1884
1901
|
}
|
|
1885
1902
|
|
|
1903
|
+
/**
|
|
1904
|
+
* 使用 Rust 实现搜索(高性能)
|
|
1905
|
+
*/
|
|
1906
|
+
private JSObject searchWithRust(MultiDexSession session, String query, String searchType,
|
|
1907
|
+
boolean caseSensitive, int maxResults) throws Exception {
|
|
1908
|
+
JSObject result = new JSObject();
|
|
1909
|
+
JSArray allResults = new JSArray();
|
|
1910
|
+
|
|
1911
|
+
for (Map.Entry<String, byte[]> entry : session.dexBytes.entrySet()) {
|
|
1912
|
+
String dexName = entry.getKey();
|
|
1913
|
+
byte[] dexData = entry.getValue();
|
|
1914
|
+
|
|
1915
|
+
// 调用 Rust 搜索
|
|
1916
|
+
String jsonResult = RustDex.searchInDex(dexData, query, searchType, caseSensitive, maxResults);
|
|
1917
|
+
|
|
1918
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1919
|
+
// 解析 Rust 返回的 JSON
|
|
1920
|
+
org.json.JSONObject rustResult = new org.json.JSONObject(jsonResult);
|
|
1921
|
+
org.json.JSONArray rustResults = rustResult.optJSONArray("results");
|
|
1922
|
+
|
|
1923
|
+
if (rustResults != null) {
|
|
1924
|
+
for (int i = 0; i < rustResults.length() && allResults.length() < maxResults; i++) {
|
|
1925
|
+
org.json.JSONObject item = rustResults.getJSONObject(i);
|
|
1926
|
+
JSObject jsItem = new JSObject();
|
|
1927
|
+
jsItem.put("type", item.optString("type", searchType));
|
|
1928
|
+
jsItem.put("className", item.optString("className", ""));
|
|
1929
|
+
jsItem.put("dexFile", dexName);
|
|
1930
|
+
if (item.has("methodName")) {
|
|
1931
|
+
jsItem.put("methodName", item.getString("methodName"));
|
|
1932
|
+
}
|
|
1933
|
+
if (item.has("fieldName")) {
|
|
1934
|
+
jsItem.put("fieldName", item.getString("fieldName"));
|
|
1935
|
+
}
|
|
1936
|
+
allResults.put(jsItem);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
if (allResults.length() >= maxResults) break;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
result.put("query", query);
|
|
1945
|
+
result.put("searchType", searchType);
|
|
1946
|
+
result.put("total", allResults.length());
|
|
1947
|
+
result.put("results", allResults);
|
|
1948
|
+
result.put("engine", "rust");
|
|
1949
|
+
|
|
1950
|
+
return result;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1886
1953
|
/**
|
|
1887
1954
|
* 获取类的 Smali 代码(内部方法)
|
|
1888
1955
|
*/
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
package com.aetherlink.dexeditor;
|
|
2
|
+
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* RustDex - Rust 实现的 DEX 解析器 JNI 接口
|
|
7
|
+
* 使用 azw413/smali crate 实现高性能 DEX 搜索
|
|
8
|
+
*/
|
|
9
|
+
public class RustDex {
|
|
10
|
+
private static final String TAG = "RustDex";
|
|
11
|
+
private static boolean libraryLoaded = false;
|
|
12
|
+
|
|
13
|
+
static {
|
|
14
|
+
try {
|
|
15
|
+
System.loadLibrary("dex_rust");
|
|
16
|
+
libraryLoaded = true;
|
|
17
|
+
Log.d(TAG, "Rust library loaded successfully");
|
|
18
|
+
} catch (UnsatisfiedLinkError e) {
|
|
19
|
+
Log.w(TAG, "Failed to load Rust library: " + e.getMessage());
|
|
20
|
+
libraryLoaded = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 检查 Rust 库是否可用
|
|
26
|
+
*/
|
|
27
|
+
public static boolean isAvailable() {
|
|
28
|
+
return libraryLoaded;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 在 DEX 中搜索
|
|
33
|
+
* @param dexBytes DEX 文件字节数组
|
|
34
|
+
* @param query 搜索查询
|
|
35
|
+
* @param searchType 搜索类型: class, method, field, string, code
|
|
36
|
+
* @param caseSensitive 是否区分大小写
|
|
37
|
+
* @param maxResults 最大结果数
|
|
38
|
+
* @return JSON 格式的搜索结果
|
|
39
|
+
*/
|
|
40
|
+
public static native String searchInDex(
|
|
41
|
+
byte[] dexBytes,
|
|
42
|
+
String query,
|
|
43
|
+
String searchType,
|
|
44
|
+
boolean caseSensitive,
|
|
45
|
+
int maxResults
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 列出 DEX 中的类
|
|
50
|
+
* @param dexBytes DEX 文件字节数组
|
|
51
|
+
* @param packageFilter 包名过滤器
|
|
52
|
+
* @param offset 偏移量
|
|
53
|
+
* @param limit 限制数量
|
|
54
|
+
* @return JSON 格式的类列表
|
|
55
|
+
*/
|
|
56
|
+
public static native String listClasses(
|
|
57
|
+
byte[] dexBytes,
|
|
58
|
+
String packageFilter,
|
|
59
|
+
int offset,
|
|
60
|
+
int limit
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 获取类的 Smali 代码
|
|
65
|
+
* @param dexBytes DEX 文件字节数组
|
|
66
|
+
* @param className 类名
|
|
67
|
+
* @return JSON 格式的 Smali 代码
|
|
68
|
+
*/
|
|
69
|
+
public static native String getClassSmali(
|
|
70
|
+
byte[] dexBytes,
|
|
71
|
+
String className
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Java 回退实现 - 当 Rust 库不可用时使用
|
|
76
|
+
*/
|
|
77
|
+
public static String searchInDexFallback(
|
|
78
|
+
byte[] dexBytes,
|
|
79
|
+
String query,
|
|
80
|
+
String searchType,
|
|
81
|
+
boolean caseSensitive,
|
|
82
|
+
int maxResults
|
|
83
|
+
) {
|
|
84
|
+
return "{\"error\": \"Rust library not available, using Java implementation\", \"fallback\": true}";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|