capacitor-dex-editor 0.0.65 → 0.0.67
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/src/main/java/com/aetherlink/dexeditor/DexManager.java +95 -211
- package/android/src/main/java/com/aetherlink/dexeditor/RustDex.java +31 -9
- 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
|
@@ -152,13 +152,6 @@ public class DexManager {
|
|
|
152
152
|
Map<String, DexBackedDexFile> dexFiles;
|
|
153
153
|
Map<String, byte[]> dexBytes; // DEX 字节数据,用于 Rust 搜索
|
|
154
154
|
Map<String, ClassDef> modifiedClasses;
|
|
155
|
-
// 使用 LRU 缓存限制内存,最多缓存 200 个类
|
|
156
|
-
Map<String, String> smaliCache = new java.util.LinkedHashMap<String, String>(200, 0.75f, true) {
|
|
157
|
-
@Override
|
|
158
|
-
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
|
|
159
|
-
return size() > 200;
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
155
|
boolean modified = false;
|
|
163
156
|
|
|
164
157
|
MultiDexSession(String sessionId, String apkPath) {
|
|
@@ -1708,7 +1701,7 @@ public class DexManager {
|
|
|
1708
1701
|
}
|
|
1709
1702
|
|
|
1710
1703
|
/**
|
|
1711
|
-
* 获取多 DEX
|
|
1704
|
+
* 获取多 DEX 会话中的类列表(Rust 实现)
|
|
1712
1705
|
*/
|
|
1713
1706
|
public JSObject getClassesFromMultiSession(String sessionId, String packageFilter, int offset, int limit) throws Exception {
|
|
1714
1707
|
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
@@ -1716,26 +1709,29 @@ public class DexManager {
|
|
|
1716
1709
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
1717
1710
|
}
|
|
1718
1711
|
|
|
1712
|
+
if (!RustDex.isAvailable() || session.dexBytes.isEmpty()) {
|
|
1713
|
+
throw new RuntimeException("Rust DEX library not available");
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1719
1716
|
JSObject result = new JSObject();
|
|
1720
1717
|
JSArray classes = new JSArray();
|
|
1721
1718
|
List<String> allClasses = new ArrayList<>();
|
|
1719
|
+
String filter = packageFilter != null ? packageFilter : "";
|
|
1722
1720
|
|
|
1723
|
-
//
|
|
1724
|
-
for (Map.Entry<String,
|
|
1721
|
+
// 使用 Rust 获取每个 DEX 的类列表
|
|
1722
|
+
for (Map.Entry<String, byte[]> entry : session.dexBytes.entrySet()) {
|
|
1725
1723
|
String dexName = entry.getKey();
|
|
1726
|
-
|
|
1724
|
+
byte[] dexData = entry.getValue();
|
|
1727
1725
|
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
if (
|
|
1733
|
-
|
|
1734
|
-
|
|
1726
|
+
String jsonResult = RustDex.listClasses(dexData, filter, 0, 100000);
|
|
1727
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1728
|
+
org.json.JSONObject rustResult = new org.json.JSONObject(jsonResult);
|
|
1729
|
+
org.json.JSONArray rustClasses = rustResult.optJSONArray("classes");
|
|
1730
|
+
if (rustClasses != null) {
|
|
1731
|
+
for (int i = 0; i < rustClasses.length(); i++) {
|
|
1732
|
+
allClasses.add(rustClasses.getString(i) + "|" + dexName);
|
|
1735
1733
|
}
|
|
1736
1734
|
}
|
|
1737
|
-
|
|
1738
|
-
allClasses.add(className + "|" + dexName);
|
|
1739
1735
|
}
|
|
1740
1736
|
}
|
|
1741
1737
|
|
|
@@ -1759,13 +1755,13 @@ public class DexManager {
|
|
|
1759
1755
|
result.put("limit", limit);
|
|
1760
1756
|
result.put("classes", classes);
|
|
1761
1757
|
result.put("hasMore", end < total);
|
|
1758
|
+
result.put("engine", "rust");
|
|
1762
1759
|
|
|
1763
1760
|
return result;
|
|
1764
1761
|
}
|
|
1765
1762
|
|
|
1766
1763
|
/**
|
|
1767
|
-
* 在多 DEX
|
|
1768
|
-
* 优先使用 Rust 实现,如果不可用则回退到 Java 实现
|
|
1764
|
+
* 在多 DEX 会话中搜索(Rust 实现)
|
|
1769
1765
|
*/
|
|
1770
1766
|
public JSObject searchInMultiSession(String sessionId, String query, String searchType,
|
|
1771
1767
|
boolean caseSensitive, int maxResults) throws Exception {
|
|
@@ -1774,137 +1770,14 @@ public class DexManager {
|
|
|
1774
1770
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
1775
1771
|
}
|
|
1776
1772
|
|
|
1777
|
-
|
|
1778
|
-
|
|
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
|
-
}
|
|
1773
|
+
if (!RustDex.isAvailable()) {
|
|
1774
|
+
throw new RuntimeException("Rust DEX library not available");
|
|
1784
1775
|
}
|
|
1785
1776
|
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
JSArray results = new JSArray();
|
|
1789
|
-
String queryMatch = caseSensitive ? query : query.toLowerCase();
|
|
1790
|
-
|
|
1791
|
-
outerLoop:
|
|
1792
|
-
for (Map.Entry<String, DexBackedDexFile> entry : session.dexFiles.entrySet()) {
|
|
1793
|
-
String dexName = entry.getKey();
|
|
1794
|
-
DexBackedDexFile dexFile = entry.getValue();
|
|
1795
|
-
|
|
1796
|
-
for (ClassDef classDef : dexFile.getClasses()) {
|
|
1797
|
-
if (results.length() >= maxResults) break outerLoop;
|
|
1798
|
-
|
|
1799
|
-
String className = convertTypeToClassName(classDef.getType());
|
|
1800
|
-
String classNameMatch = caseSensitive ? className : className.toLowerCase();
|
|
1801
|
-
|
|
1802
|
-
switch (searchType) {
|
|
1803
|
-
case "class":
|
|
1804
|
-
if (classNameMatch.contains(queryMatch)) {
|
|
1805
|
-
JSObject item = new JSObject();
|
|
1806
|
-
item.put("type", "class");
|
|
1807
|
-
item.put("className", className);
|
|
1808
|
-
item.put("dexFile", dexName);
|
|
1809
|
-
results.put(item);
|
|
1810
|
-
}
|
|
1811
|
-
break;
|
|
1812
|
-
|
|
1813
|
-
case "package":
|
|
1814
|
-
if (classNameMatch.startsWith(queryMatch)) {
|
|
1815
|
-
JSObject item = new JSObject();
|
|
1816
|
-
item.put("type", "package");
|
|
1817
|
-
item.put("className", className);
|
|
1818
|
-
item.put("dexFile", dexName);
|
|
1819
|
-
results.put(item);
|
|
1820
|
-
}
|
|
1821
|
-
break;
|
|
1822
|
-
|
|
1823
|
-
case "method":
|
|
1824
|
-
for (Method method : classDef.getMethods()) {
|
|
1825
|
-
if (results.length() >= maxResults) break outerLoop;
|
|
1826
|
-
String methodName = method.getName();
|
|
1827
|
-
String methodMatch = caseSensitive ? methodName : methodName.toLowerCase();
|
|
1828
|
-
if (methodMatch.contains(queryMatch)) {
|
|
1829
|
-
JSObject item = new JSObject();
|
|
1830
|
-
item.put("type", "method");
|
|
1831
|
-
item.put("className", className);
|
|
1832
|
-
item.put("methodName", methodName);
|
|
1833
|
-
item.put("dexFile", dexName);
|
|
1834
|
-
results.put(item);
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
break;
|
|
1838
|
-
|
|
1839
|
-
case "field":
|
|
1840
|
-
for (Field field : classDef.getFields()) {
|
|
1841
|
-
if (results.length() >= maxResults) break outerLoop;
|
|
1842
|
-
String fieldName = field.getName();
|
|
1843
|
-
String fieldMatch = caseSensitive ? fieldName : fieldName.toLowerCase();
|
|
1844
|
-
if (fieldMatch.contains(queryMatch)) {
|
|
1845
|
-
JSObject item = new JSObject();
|
|
1846
|
-
item.put("type", "field");
|
|
1847
|
-
item.put("className", className);
|
|
1848
|
-
item.put("fieldName", fieldName);
|
|
1849
|
-
item.put("dexFile", dexName);
|
|
1850
|
-
results.put(item);
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
break;
|
|
1854
|
-
|
|
1855
|
-
case "string":
|
|
1856
|
-
case "code":
|
|
1857
|
-
// 使用缓存的 smali 搜索
|
|
1858
|
-
String smali = getCachedSmali(session, className, dexFile, classDef);
|
|
1859
|
-
String smaliMatch = caseSensitive ? smali : smali.toLowerCase();
|
|
1860
|
-
if (smaliMatch.contains(queryMatch)) {
|
|
1861
|
-
JSObject item = new JSObject();
|
|
1862
|
-
item.put("type", searchType);
|
|
1863
|
-
item.put("className", className);
|
|
1864
|
-
item.put("dexFile", dexName);
|
|
1865
|
-
// 找到匹配的行
|
|
1866
|
-
String[] lines = smali.split("\n");
|
|
1867
|
-
for (int i = 0; i < lines.length; i++) {
|
|
1868
|
-
String lineMatch = caseSensitive ? lines[i] : lines[i].toLowerCase();
|
|
1869
|
-
if (lineMatch.contains(queryMatch)) {
|
|
1870
|
-
item.put("line", i + 1);
|
|
1871
|
-
item.put("content", lines[i].trim());
|
|
1872
|
-
break;
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
results.put(item);
|
|
1876
|
-
}
|
|
1877
|
-
break;
|
|
1878
|
-
|
|
1879
|
-
case "int":
|
|
1880
|
-
// 搜索整数常量(使用缓存)
|
|
1881
|
-
String smaliForInt = getCachedSmali(session, className, dexFile, classDef);
|
|
1882
|
-
if (smaliForInt.contains("0x" + query) || smaliForInt.contains(" " + query + "\n") ||
|
|
1883
|
-
smaliForInt.contains(" " + query + " ")) {
|
|
1884
|
-
JSObject item = new JSObject();
|
|
1885
|
-
item.put("type", "int");
|
|
1886
|
-
item.put("className", className);
|
|
1887
|
-
item.put("dexFile", dexName);
|
|
1888
|
-
results.put(item);
|
|
1889
|
-
}
|
|
1890
|
-
break;
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1777
|
+
if (session.dexBytes.isEmpty()) {
|
|
1778
|
+
throw new RuntimeException("No DEX data loaded");
|
|
1893
1779
|
}
|
|
1894
1780
|
|
|
1895
|
-
result.put("query", query);
|
|
1896
|
-
result.put("searchType", searchType);
|
|
1897
|
-
result.put("total", results.length());
|
|
1898
|
-
result.put("results", results);
|
|
1899
|
-
|
|
1900
|
-
return result;
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
/**
|
|
1904
|
-
* 使用 Rust 实现搜索(高性能)
|
|
1905
|
-
*/
|
|
1906
|
-
private JSObject searchWithRust(MultiDexSession session, String query, String searchType,
|
|
1907
|
-
boolean caseSensitive, int maxResults) throws Exception {
|
|
1908
1781
|
JSObject result = new JSObject();
|
|
1909
1782
|
JSArray allResults = new JSArray();
|
|
1910
1783
|
|
|
@@ -1912,11 +1785,9 @@ public class DexManager {
|
|
|
1912
1785
|
String dexName = entry.getKey();
|
|
1913
1786
|
byte[] dexData = entry.getValue();
|
|
1914
1787
|
|
|
1915
|
-
// 调用 Rust 搜索
|
|
1916
1788
|
String jsonResult = RustDex.searchInDex(dexData, query, searchType, caseSensitive, maxResults);
|
|
1917
1789
|
|
|
1918
1790
|
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1919
|
-
// 解析 Rust 返回的 JSON
|
|
1920
1791
|
org.json.JSONObject rustResult = new org.json.JSONObject(jsonResult);
|
|
1921
1792
|
org.json.JSONArray rustResults = rustResult.optJSONArray("results");
|
|
1922
1793
|
|
|
@@ -1967,23 +1838,9 @@ public class DexManager {
|
|
|
1967
1838
|
}
|
|
1968
1839
|
}
|
|
1969
1840
|
|
|
1970
|
-
/**
|
|
1971
|
-
* 获取缓存的 Smali 代码(用于搜索优化)
|
|
1972
|
-
*/
|
|
1973
|
-
private String getCachedSmali(MultiDexSession session, String className, DexBackedDexFile dexFile, ClassDef classDef) {
|
|
1974
|
-
// 先查缓存
|
|
1975
|
-
String cached = session.smaliCache.get(className);
|
|
1976
|
-
if (cached != null) {
|
|
1977
|
-
return cached;
|
|
1978
|
-
}
|
|
1979
|
-
// 缓存未命中,反编译并缓存
|
|
1980
|
-
String smali = getSmaliForClass(dexFile, classDef);
|
|
1981
|
-
session.smaliCache.put(className, smali);
|
|
1982
|
-
return smali;
|
|
1983
|
-
}
|
|
1984
1841
|
|
|
1985
1842
|
/**
|
|
1986
|
-
* 从多 DEX 会话获取类的 Smali
|
|
1843
|
+
* 从多 DEX 会话获取类的 Smali 代码(Rust 实现)
|
|
1987
1844
|
*/
|
|
1988
1845
|
public JSObject getClassSmaliFromSession(String sessionId, String className) throws Exception {
|
|
1989
1846
|
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
@@ -1991,20 +1848,24 @@ public class DexManager {
|
|
|
1991
1848
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
1992
1849
|
}
|
|
1993
1850
|
|
|
1994
|
-
|
|
1851
|
+
if (!RustDex.isAvailable()) {
|
|
1852
|
+
throw new RuntimeException("Rust DEX library not available");
|
|
1853
|
+
}
|
|
1995
1854
|
|
|
1996
|
-
|
|
1855
|
+
// 使用 Rust 获取 Smali
|
|
1856
|
+
for (Map.Entry<String, byte[]> entry : session.dexBytes.entrySet()) {
|
|
1997
1857
|
String dexName = entry.getKey();
|
|
1998
|
-
|
|
1858
|
+
byte[] dexData = entry.getValue();
|
|
1999
1859
|
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
1860
|
+
String jsonResult = RustDex.getClassSmali(dexData, className);
|
|
1861
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1862
|
+
org.json.JSONObject rustResult = new org.json.JSONObject(jsonResult);
|
|
1863
|
+
JSObject result = new JSObject();
|
|
1864
|
+
result.put("className", className);
|
|
1865
|
+
result.put("dexFile", dexName);
|
|
1866
|
+
result.put("smaliContent", rustResult.optString("smaliContent", ""));
|
|
1867
|
+
result.put("engine", "rust");
|
|
1868
|
+
return result;
|
|
2008
1869
|
}
|
|
2009
1870
|
}
|
|
2010
1871
|
|
|
@@ -2012,7 +1873,7 @@ public class DexManager {
|
|
|
2012
1873
|
}
|
|
2013
1874
|
|
|
2014
1875
|
/**
|
|
2015
|
-
* 修改类并保存到多 DEX
|
|
1876
|
+
* 修改类并保存到多 DEX 会话(Rust 实现)
|
|
2016
1877
|
*/
|
|
2017
1878
|
public void modifyClassInSession(String sessionId, String className, String smaliContent) throws Exception {
|
|
2018
1879
|
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
@@ -2020,36 +1881,41 @@ public class DexManager {
|
|
|
2020
1881
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
2021
1882
|
}
|
|
2022
1883
|
|
|
2023
|
-
|
|
1884
|
+
if (!RustDex.isAvailable()) {
|
|
1885
|
+
throw new RuntimeException("Rust DEX library not available");
|
|
1886
|
+
}
|
|
2024
1887
|
|
|
2025
1888
|
// 找到类所在的 DEX
|
|
2026
1889
|
String targetDex = null;
|
|
2027
|
-
for (Map.Entry<String,
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
}
|
|
1890
|
+
for (Map.Entry<String, byte[]> entry : session.dexBytes.entrySet()) {
|
|
1891
|
+
String jsonResult = RustDex.getClassSmali(entry.getValue(), className);
|
|
1892
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1893
|
+
targetDex = entry.getKey();
|
|
1894
|
+
break;
|
|
2033
1895
|
}
|
|
2034
|
-
if (targetDex != null) break;
|
|
2035
1896
|
}
|
|
2036
1897
|
|
|
2037
1898
|
if (targetDex == null) {
|
|
2038
1899
|
throw new IllegalArgumentException("Class not found: " + className);
|
|
2039
1900
|
}
|
|
2040
1901
|
|
|
2041
|
-
//
|
|
2042
|
-
|
|
1902
|
+
// 使用 Rust 修改类
|
|
1903
|
+
byte[] originalDex = session.dexBytes.get(targetDex);
|
|
1904
|
+
byte[] modifiedDex = RustDex.modifyClass(originalDex, className, smaliContent);
|
|
1905
|
+
|
|
1906
|
+
if (modifiedDex == null) {
|
|
1907
|
+
throw new RuntimeException("Failed to modify class: " + className);
|
|
1908
|
+
}
|
|
2043
1909
|
|
|
2044
|
-
//
|
|
2045
|
-
session.
|
|
1910
|
+
// 更新 DEX 字节数据
|
|
1911
|
+
session.dexBytes.put(targetDex, modifiedDex);
|
|
2046
1912
|
session.modified = true;
|
|
2047
1913
|
|
|
2048
|
-
Log.d(TAG, "Modified class in session: " + className);
|
|
1914
|
+
Log.d(TAG, "Modified class in session (Rust): " + className);
|
|
2049
1915
|
}
|
|
2050
1916
|
|
|
2051
1917
|
/**
|
|
2052
|
-
*
|
|
1918
|
+
* 添加新类到会话(Rust 实现)
|
|
2053
1919
|
*/
|
|
2054
1920
|
public void addClassToSession(String sessionId, String className, String smaliContent) throws Exception {
|
|
2055
1921
|
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
@@ -2057,23 +1923,33 @@ public class DexManager {
|
|
|
2057
1923
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
2058
1924
|
}
|
|
2059
1925
|
|
|
2060
|
-
|
|
2061
|
-
|
|
1926
|
+
if (!RustDex.isAvailable()) {
|
|
1927
|
+
throw new RuntimeException("Rust DEX library not available");
|
|
1928
|
+
}
|
|
2062
1929
|
|
|
2063
1930
|
// 添加到第一个 DEX(默认 classes.dex)
|
|
2064
1931
|
String targetDex = "classes.dex";
|
|
2065
|
-
if (!session.
|
|
2066
|
-
targetDex = session.
|
|
1932
|
+
if (!session.dexBytes.containsKey(targetDex) && !session.dexBytes.isEmpty()) {
|
|
1933
|
+
targetDex = session.dexBytes.keySet().iterator().next();
|
|
2067
1934
|
}
|
|
2068
1935
|
|
|
2069
|
-
|
|
1936
|
+
// 使用 Rust 添加类
|
|
1937
|
+
byte[] originalDex = session.dexBytes.get(targetDex);
|
|
1938
|
+
byte[] modifiedDex = RustDex.addClass(originalDex, smaliContent);
|
|
1939
|
+
|
|
1940
|
+
if (modifiedDex == null) {
|
|
1941
|
+
throw new RuntimeException("Failed to add class: " + className);
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
// 更新 DEX 字节数据
|
|
1945
|
+
session.dexBytes.put(targetDex, modifiedDex);
|
|
2070
1946
|
session.modified = true;
|
|
2071
1947
|
|
|
2072
|
-
Log.d(TAG, "Added class to session: " + className);
|
|
1948
|
+
Log.d(TAG, "Added class to session (Rust): " + className);
|
|
2073
1949
|
}
|
|
2074
1950
|
|
|
2075
1951
|
/**
|
|
2076
|
-
*
|
|
1952
|
+
* 从会话中删除类(Rust 实现)
|
|
2077
1953
|
*/
|
|
2078
1954
|
public void deleteClassFromSession(String sessionId, String className) throws Exception {
|
|
2079
1955
|
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
@@ -2081,29 +1957,37 @@ public class DexManager {
|
|
|
2081
1957
|
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
2082
1958
|
}
|
|
2083
1959
|
|
|
2084
|
-
|
|
1960
|
+
if (!RustDex.isAvailable()) {
|
|
1961
|
+
throw new RuntimeException("Rust DEX library not available");
|
|
1962
|
+
}
|
|
2085
1963
|
|
|
2086
|
-
// 找到类所在的 DEX
|
|
1964
|
+
// 找到类所在的 DEX
|
|
2087
1965
|
String targetDex = null;
|
|
2088
|
-
for (Map.Entry<String,
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
}
|
|
1966
|
+
for (Map.Entry<String, byte[]> entry : session.dexBytes.entrySet()) {
|
|
1967
|
+
String jsonResult = RustDex.getClassSmali(entry.getValue(), className);
|
|
1968
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1969
|
+
targetDex = entry.getKey();
|
|
1970
|
+
break;
|
|
2094
1971
|
}
|
|
2095
|
-
if (targetDex != null) break;
|
|
2096
1972
|
}
|
|
2097
1973
|
|
|
2098
1974
|
if (targetDex == null) {
|
|
2099
1975
|
throw new IllegalArgumentException("Class not found: " + className);
|
|
2100
1976
|
}
|
|
2101
1977
|
|
|
2102
|
-
//
|
|
2103
|
-
session.
|
|
1978
|
+
// 使用 Rust 删除类
|
|
1979
|
+
byte[] originalDex = session.dexBytes.get(targetDex);
|
|
1980
|
+
byte[] modifiedDex = RustDex.deleteClass(originalDex, className);
|
|
1981
|
+
|
|
1982
|
+
if (modifiedDex == null) {
|
|
1983
|
+
throw new RuntimeException("Failed to delete class: " + className);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// 更新 DEX 字节数据
|
|
1987
|
+
session.dexBytes.put(targetDex, modifiedDex);
|
|
2104
1988
|
session.modified = true;
|
|
2105
1989
|
|
|
2106
|
-
Log.d(TAG, "Deleted class from session: " + className);
|
|
1990
|
+
Log.d(TAG, "Deleted class from session (Rust): " + className);
|
|
2107
1991
|
}
|
|
2108
1992
|
|
|
2109
1993
|
/**
|
|
@@ -72,15 +72,37 @@ public class RustDex {
|
|
|
72
72
|
);
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
75
|
+
* 修改 DEX 中的类
|
|
76
|
+
* @param dexBytes DEX 文件字节数组
|
|
77
|
+
* @param className 类名
|
|
78
|
+
* @param newSmali 新的 Smali 代码
|
|
79
|
+
* @return 修改后的 DEX 字节数组,失败返回 null
|
|
76
80
|
*/
|
|
77
|
-
public static
|
|
81
|
+
public static native byte[] modifyClass(
|
|
78
82
|
byte[] dexBytes,
|
|
79
|
-
String
|
|
80
|
-
String
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
String className,
|
|
84
|
+
String newSmali
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 添加新类到 DEX
|
|
89
|
+
* @param dexBytes DEX 文件字节数组
|
|
90
|
+
* @param newSmali 新类的 Smali 代码
|
|
91
|
+
* @return 修改后的 DEX 字节数组,失败返回 null
|
|
92
|
+
*/
|
|
93
|
+
public static native byte[] addClass(
|
|
94
|
+
byte[] dexBytes,
|
|
95
|
+
String newSmali
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 从 DEX 中删除类
|
|
100
|
+
* @param dexBytes DEX 文件字节数组
|
|
101
|
+
* @param className 要删除的类名
|
|
102
|
+
* @return 修改后的 DEX 字节数组,失败返回 null
|
|
103
|
+
*/
|
|
104
|
+
public static native byte[] deleteClass(
|
|
105
|
+
byte[] dexBytes,
|
|
106
|
+
String className
|
|
107
|
+
);
|
|
86
108
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|