capacitor-dex-editor 0.0.56 → 0.0.57
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.
|
@@ -537,6 +537,40 @@ public class DexEditorPluginPlugin extends Plugin {
|
|
|
537
537
|
dexManager.closeMultiDexSession(params.getString("sessionId"));
|
|
538
538
|
break;
|
|
539
539
|
|
|
540
|
+
case "addClassToSession":
|
|
541
|
+
dexManager.addClassToSession(
|
|
542
|
+
params.getString("sessionId"),
|
|
543
|
+
params.getString("className"),
|
|
544
|
+
params.getString("smaliContent")
|
|
545
|
+
);
|
|
546
|
+
break;
|
|
547
|
+
|
|
548
|
+
case "deleteClassFromSession":
|
|
549
|
+
dexManager.deleteClassFromSession(
|
|
550
|
+
params.getString("sessionId"),
|
|
551
|
+
params.getString("className")
|
|
552
|
+
);
|
|
553
|
+
break;
|
|
554
|
+
|
|
555
|
+
case "getMethodFromSession":
|
|
556
|
+
result.put("data", dexManager.getMethodFromSession(
|
|
557
|
+
params.getString("sessionId"),
|
|
558
|
+
params.getString("className"),
|
|
559
|
+
params.getString("methodName"),
|
|
560
|
+
params.optString("methodSignature", "")
|
|
561
|
+
));
|
|
562
|
+
break;
|
|
563
|
+
|
|
564
|
+
case "modifyMethodInSession":
|
|
565
|
+
dexManager.modifyMethodInSession(
|
|
566
|
+
params.getString("sessionId"),
|
|
567
|
+
params.getString("className"),
|
|
568
|
+
params.getString("methodName"),
|
|
569
|
+
params.optString("methodSignature", ""),
|
|
570
|
+
params.getString("newMethodCode")
|
|
571
|
+
);
|
|
572
|
+
break;
|
|
573
|
+
|
|
540
574
|
case "listSessions":
|
|
541
575
|
result.put("data", dexManager.listAllSessions());
|
|
542
576
|
break;
|
|
@@ -1983,6 +1983,194 @@ public class DexManager {
|
|
|
1983
1983
|
Log.d(TAG, "Modified class in session: " + className);
|
|
1984
1984
|
}
|
|
1985
1985
|
|
|
1986
|
+
/**
|
|
1987
|
+
* 添加新类到会话
|
|
1988
|
+
*/
|
|
1989
|
+
public void addClassToSession(String sessionId, String className, String smaliContent) throws Exception {
|
|
1990
|
+
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
1991
|
+
if (session == null) {
|
|
1992
|
+
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
// 编译 Smali
|
|
1996
|
+
ClassDef newClassDef = compileSmaliToClass(smaliContent, Opcodes.getDefault());
|
|
1997
|
+
|
|
1998
|
+
// 添加到第一个 DEX(默认 classes.dex)
|
|
1999
|
+
String targetDex = "classes.dex";
|
|
2000
|
+
if (!session.dexFiles.containsKey(targetDex) && !session.dexFiles.isEmpty()) {
|
|
2001
|
+
targetDex = session.dexFiles.keySet().iterator().next();
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
session.modifiedClasses.put(targetDex + "|" + className, newClassDef);
|
|
2005
|
+
session.modified = true;
|
|
2006
|
+
|
|
2007
|
+
Log.d(TAG, "Added class to session: " + className);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
/**
|
|
2011
|
+
* 从会话中删除类
|
|
2012
|
+
*/
|
|
2013
|
+
public void deleteClassFromSession(String sessionId, String className) throws Exception {
|
|
2014
|
+
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
2015
|
+
if (session == null) {
|
|
2016
|
+
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
String targetType = convertClassNameToType(className);
|
|
2020
|
+
|
|
2021
|
+
// 找到类所在的 DEX 并标记为删除
|
|
2022
|
+
String targetDex = null;
|
|
2023
|
+
for (Map.Entry<String, DexBackedDexFile> entry : session.dexFiles.entrySet()) {
|
|
2024
|
+
for (ClassDef classDef : entry.getValue().getClasses()) {
|
|
2025
|
+
if (classDef.getType().equals(targetType)) {
|
|
2026
|
+
targetDex = entry.getKey();
|
|
2027
|
+
break;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
if (targetDex != null) break;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
if (targetDex == null) {
|
|
2034
|
+
throw new IllegalArgumentException("Class not found: " + className);
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
// 用 null 标记删除
|
|
2038
|
+
session.modifiedClasses.put(targetDex + "|" + className, null);
|
|
2039
|
+
session.modified = true;
|
|
2040
|
+
|
|
2041
|
+
Log.d(TAG, "Deleted class from session: " + className);
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
2045
|
+
* 从会话中获取单个方法的 Smali 代码
|
|
2046
|
+
*/
|
|
2047
|
+
public JSObject getMethodFromSession(String sessionId, String className, String methodName, String methodSignature) throws Exception {
|
|
2048
|
+
JSObject result = new JSObject();
|
|
2049
|
+
|
|
2050
|
+
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
2051
|
+
if (session == null) {
|
|
2052
|
+
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
// 先获取整个类的 Smali
|
|
2056
|
+
JSObject classResult = getClassSmaliFromSession(sessionId, className);
|
|
2057
|
+
String smaliContent = classResult.optString("smaliContent", "");
|
|
2058
|
+
|
|
2059
|
+
if (smaliContent.isEmpty()) {
|
|
2060
|
+
result.put("methodCode", "# 类未找到: " + className);
|
|
2061
|
+
return result;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
// 解析并提取方法
|
|
2065
|
+
String methodCode = extractMethodFromSmali(smaliContent, methodName, methodSignature);
|
|
2066
|
+
result.put("methodCode", methodCode);
|
|
2067
|
+
result.put("className", className);
|
|
2068
|
+
result.put("methodName", methodName);
|
|
2069
|
+
|
|
2070
|
+
return result;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* 修改会话中的单个方法
|
|
2075
|
+
*/
|
|
2076
|
+
public void modifyMethodInSession(String sessionId, String className, String methodName, String methodSignature, String newMethodCode) throws Exception {
|
|
2077
|
+
MultiDexSession session = multiDexSessions.get(sessionId);
|
|
2078
|
+
if (session == null) {
|
|
2079
|
+
throw new IllegalArgumentException("Session not found: " + sessionId);
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// 获取整个类的 Smali
|
|
2083
|
+
JSObject classResult = getClassSmaliFromSession(sessionId, className);
|
|
2084
|
+
String smaliContent = classResult.optString("smaliContent", "");
|
|
2085
|
+
|
|
2086
|
+
if (smaliContent.isEmpty()) {
|
|
2087
|
+
throw new IllegalArgumentException("Class not found: " + className);
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
// 替换方法
|
|
2091
|
+
String newSmaliContent = replaceMethodInSmali(smaliContent, methodName, methodSignature, newMethodCode);
|
|
2092
|
+
|
|
2093
|
+
// 保存修改后的类
|
|
2094
|
+
modifyClassInSession(sessionId, className, newSmaliContent);
|
|
2095
|
+
|
|
2096
|
+
Log.d(TAG, "Modified method in session: " + className + "." + methodName);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* 从 Smali 代码中提取指定方法
|
|
2101
|
+
*/
|
|
2102
|
+
private String extractMethodFromSmali(String smaliContent, String methodName, String methodSignature) {
|
|
2103
|
+
String[] lines = smaliContent.split("\n");
|
|
2104
|
+
StringBuilder methodCode = new StringBuilder();
|
|
2105
|
+
boolean inMethod = false;
|
|
2106
|
+
boolean found = false;
|
|
2107
|
+
|
|
2108
|
+
for (String line : lines) {
|
|
2109
|
+
if (line.startsWith(".method ")) {
|
|
2110
|
+
// 检查是否是目标方法
|
|
2111
|
+
if (line.contains(" " + methodName + "(") || line.contains(" " + methodName + ";")) {
|
|
2112
|
+
// 如果指定了签名,进一步匹配
|
|
2113
|
+
if (methodSignature == null || methodSignature.isEmpty() || line.contains(methodSignature)) {
|
|
2114
|
+
inMethod = true;
|
|
2115
|
+
found = true;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
if (inMethod) {
|
|
2121
|
+
methodCode.append(line).append("\n");
|
|
2122
|
+
if (line.equals(".end method")) {
|
|
2123
|
+
break;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
if (!found) {
|
|
2129
|
+
return "# 方法未找到: " + methodName + (methodSignature != null ? methodSignature : "");
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
return methodCode.toString();
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
/**
|
|
2136
|
+
* 替换 Smali 代码中的指定方法
|
|
2137
|
+
*/
|
|
2138
|
+
private String replaceMethodInSmali(String smaliContent, String methodName, String methodSignature, String newMethodCode) {
|
|
2139
|
+
String[] lines = smaliContent.split("\n");
|
|
2140
|
+
StringBuilder result = new StringBuilder();
|
|
2141
|
+
boolean inMethod = false;
|
|
2142
|
+
boolean replaced = false;
|
|
2143
|
+
|
|
2144
|
+
for (String line : lines) {
|
|
2145
|
+
if (line.startsWith(".method ")) {
|
|
2146
|
+
if (line.contains(" " + methodName + "(") || line.contains(" " + methodName + ";")) {
|
|
2147
|
+
if (methodSignature == null || methodSignature.isEmpty() || line.contains(methodSignature)) {
|
|
2148
|
+
// 插入新方法代码
|
|
2149
|
+
result.append(newMethodCode.trim()).append("\n");
|
|
2150
|
+
inMethod = true;
|
|
2151
|
+
replaced = true;
|
|
2152
|
+
continue;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
if (inMethod) {
|
|
2158
|
+
if (line.equals(".end method")) {
|
|
2159
|
+
inMethod = false;
|
|
2160
|
+
}
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
result.append(line).append("\n");
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
if (!replaced) {
|
|
2168
|
+
throw new IllegalArgumentException("Method not found: " + methodName);
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
return result.toString();
|
|
2172
|
+
}
|
|
2173
|
+
|
|
1986
2174
|
/**
|
|
1987
2175
|
* 保存多 DEX 会话的修改到 APK
|
|
1988
2176
|
*/
|