capacitor-dex-editor 0.0.71 → 0.0.73

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.
@@ -307,6 +307,31 @@ public class DexEditorPluginPlugin extends Plugin {
307
307
  ));
308
308
  break;
309
309
 
310
+ // ============ 交叉引用分析(C++ 实现)============
311
+ case "findMethodXrefs":
312
+ result.put("data", dexManager.findMethodXrefs(
313
+ params.getString("sessionId"),
314
+ params.getString("className"),
315
+ params.getString("methodName")
316
+ ));
317
+ break;
318
+
319
+ case "findFieldXrefs":
320
+ result.put("data", dexManager.findFieldXrefs(
321
+ params.getString("sessionId"),
322
+ params.getString("className"),
323
+ params.getString("fieldName")
324
+ ));
325
+ break;
326
+
327
+ // ============ Smali 转 Java(C++ 实现)============
328
+ case "smaliToJava":
329
+ result.put("data", dexManager.smaliToJava(
330
+ params.getString("sessionId"),
331
+ params.getString("className")
332
+ ));
333
+ break;
334
+
310
335
  // ============ 工具操作 ============
311
336
  case "fixDex":
312
337
  dexManager.fixDex(
@@ -213,15 +213,29 @@ public class DexManager {
213
213
  }
214
214
 
215
215
  /**
216
- * 保存 DEX 文件
216
+ * 保存 DEX 文件(优先使用 C++ 修改的字节数据)
217
217
  */
218
218
  public void saveDex(String sessionId, String outputPath) throws Exception {
219
219
  DexSession session = getSession(sessionId);
220
+
221
+ File outputFile = new File(outputPath);
222
+ if (outputFile.getParentFile() != null) {
223
+ outputFile.getParentFile().mkdirs();
224
+ }
220
225
 
221
- // 创建新的 DEX 文件
226
+ // 如果使用 C++ 修改了 dexBytes,直接保存
227
+ if (session.dexBytes != null && session.modified &&
228
+ session.modifiedClasses.isEmpty() && session.removedClasses.isEmpty()) {
229
+ try (java.io.FileOutputStream fos = new java.io.FileOutputStream(outputFile)) {
230
+ fos.write(session.dexBytes);
231
+ }
232
+ Log.d(TAG, "Saved DEX (C++ modified) to: " + outputPath);
233
+ return;
234
+ }
235
+
236
+ // Java 回退实现
222
237
  DexPool dexPool = new DexPool(session.originalDexFile.getOpcodes());
223
238
 
224
- // 添加所有类(排除已删除的,使用修改后的版本)
225
239
  Set<String> modifiedClassTypes = new HashSet<>();
226
240
  for (ClassDef modifiedClass : session.modifiedClasses) {
227
241
  modifiedClassTypes.add(modifiedClass.getType());
@@ -235,13 +249,6 @@ public class DexManager {
235
249
  }
236
250
  }
237
251
 
238
- // 写入文件 (使用官方推荐方式)
239
- File outputFile = new File(outputPath);
240
- if (outputFile.getParentFile() != null) {
241
- outputFile.getParentFile().mkdirs();
242
- }
243
-
244
- // 创建临时 DexFile 用于写入
245
252
  List<ClassDef> allClasses = new ArrayList<>();
246
253
  for (ClassDef c : session.modifiedClasses) {
247
254
  allClasses.add(c);
@@ -404,12 +411,27 @@ public class DexManager {
404
411
  }
405
412
 
406
413
  /**
407
- * 添加类
414
+ * 添加类(优先使用 C++ 实现)
408
415
  */
409
416
  public void addClass(String sessionId, String smaliCode) throws Exception {
410
417
  DexSession session = getSession(sessionId);
411
418
 
412
- // Smali 代码编译为 ClassDef
419
+ // 优先使用 C++ 实现
420
+ if (CppDex.isAvailable() && session.dexBytes != null) {
421
+ try {
422
+ byte[] newDexBytes = CppDex.addClass(session.dexBytes, smaliCode);
423
+ if (newDexBytes != null) {
424
+ session.dexBytes = newDexBytes;
425
+ session.modified = true;
426
+ Log.d(TAG, "Added class via C++");
427
+ return;
428
+ }
429
+ } catch (Exception e) {
430
+ Log.w(TAG, "C++ addClass failed, fallback to Java", e);
431
+ }
432
+ }
433
+
434
+ // Java 回退实现
413
435
  ClassDef newClass = compileSmaliToClass(smaliCode, session.originalDexFile.getOpcodes());
414
436
  session.modifiedClasses.add(newClass);
415
437
  session.modified = true;
@@ -418,10 +440,27 @@ public class DexManager {
418
440
  }
419
441
 
420
442
  /**
421
- * 删除类
443
+ * 删除类(优先使用 C++ 实现)
422
444
  */
423
445
  public void removeClass(String sessionId, String className) throws Exception {
424
446
  DexSession session = getSession(sessionId);
447
+
448
+ // 优先使用 C++ 实现
449
+ if (CppDex.isAvailable() && session.dexBytes != null) {
450
+ try {
451
+ byte[] newDexBytes = CppDex.deleteClass(session.dexBytes, className);
452
+ if (newDexBytes != null) {
453
+ session.dexBytes = newDexBytes;
454
+ session.modified = true;
455
+ Log.d(TAG, "Removed class via C++: " + className);
456
+ return;
457
+ }
458
+ } catch (Exception e) {
459
+ Log.w(TAG, "C++ removeClass failed, fallback to Java", e);
460
+ }
461
+ }
462
+
463
+ // Java 回退实现
425
464
  session.removedClasses.add(className);
426
465
  session.modified = true;
427
466
 
@@ -562,21 +601,42 @@ public class DexManager {
562
601
  }
563
602
 
564
603
  /**
565
- * 获取方法的 Smali 代码
604
+ * 获取方法的 Smali 代码(优先使用 C++ 实现)
566
605
  */
567
606
  public JSObject getMethodSmali(String sessionId, String className,
568
607
  String methodName, String methodSignature) throws Exception {
569
608
  DexSession session = getSession(sessionId);
570
609
 
571
- // 获取类的完整 Smali,然后提取方法部分
572
- String classSmali = classToSmali(sessionId, className).getString("smali");
610
+ // 优先使用 C++ 实现
611
+ if (CppDex.isAvailable() && session.dexBytes != null) {
612
+ try {
613
+ String jsonResult = CppDex.getMethodSmali(session.dexBytes, className, methodName, methodSignature);
614
+ if (jsonResult != null && !jsonResult.contains("\"error\"")) {
615
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
616
+ String smali = cppResult.optString("smali", "");
617
+ if (!smali.isEmpty()) {
618
+ JSObject result = new JSObject();
619
+ result.put("className", className);
620
+ result.put("methodName", methodName);
621
+ result.put("methodSignature", methodSignature);
622
+ result.put("smali", smali);
623
+ result.put("engine", "cpp");
624
+ return result;
625
+ }
626
+ }
627
+ } catch (Exception e) {
628
+ Log.w(TAG, "C++ getMethodSmali failed, fallback to Java", e);
629
+ }
630
+ }
573
631
 
574
- // 简化处理:返回整个类的 Smali(实际应该解析提取特定方法)
632
+ // Java 回退实现
633
+ String classSmali = classToSmali(sessionId, className).getString("smali");
575
634
  JSObject result = new JSObject();
576
635
  result.put("className", className);
577
636
  result.put("methodName", methodName);
578
637
  result.put("methodSignature", methodSignature);
579
638
  result.put("smali", extractMethodSmali(classSmali, methodName, methodSignature));
639
+ result.put("engine", "java");
580
640
  return result;
581
641
  }
582
642
 
@@ -782,21 +842,40 @@ public class DexManager {
782
842
  // ==================== Smali 操作 ====================
783
843
 
784
844
  /**
785
- * 将类转换为 Smali 代码
845
+ * 将类转换为 Smali 代码(优先使用 C++ 实现)
786
846
  */
787
847
  public JSObject classToSmali(String sessionId, String className) throws Exception {
788
848
  DexSession session = getSession(sessionId);
849
+
850
+ // 优先使用 C++ 实现
851
+ if (CppDex.isAvailable() && session.dexBytes != null) {
852
+ try {
853
+ String jsonResult = CppDex.getClassSmali(session.dexBytes, className);
854
+ if (jsonResult != null && !jsonResult.contains("\"error\"")) {
855
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
856
+ String smali = cppResult.optString("smali", "");
857
+ if (!smali.isEmpty()) {
858
+ JSObject result = new JSObject();
859
+ result.put("className", className);
860
+ result.put("smali", smali);
861
+ result.put("engine", "cpp");
862
+ return result;
863
+ }
864
+ }
865
+ } catch (Exception e) {
866
+ Log.w(TAG, "C++ classToSmali failed, fallback to Java", e);
867
+ }
868
+ }
869
+
870
+ // Java 回退实现
789
871
  ClassDef classDef = findClass(session, className);
790
-
791
872
  if (classDef == null) {
792
873
  throw new IllegalArgumentException("Class not found: " + className);
793
874
  }
794
875
 
795
- // 使用 baksmali 转换
796
876
  StringWriter writer = new StringWriter();
797
877
  BaksmaliOptions options = new BaksmaliOptions();
798
878
 
799
- // 创建临时 DEX 只包含该类
800
879
  List<ClassDef> singleClass = new ArrayList<>();
801
880
  singleClass.add(classDef);
802
881
  ImmutableDexFile singleDex = new ImmutableDexFile(
@@ -804,7 +883,6 @@ public class DexManager {
804
883
  singleClass
805
884
  );
806
885
 
807
- // 使用临时目录输出
808
886
  File tempDir = File.createTempFile("smali_", "_temp");
809
887
  tempDir.delete();
810
888
  tempDir.mkdirs();
@@ -812,7 +890,6 @@ public class DexManager {
812
890
  try {
813
891
  Baksmali.disassembleDexFile(singleDex, tempDir, 1, options);
814
892
 
815
- // 读取生成的 smali 文件
816
893
  String smaliPath = className.substring(1, className.length() - 1) + ".smali";
817
894
  File smaliFile = new File(tempDir, smaliPath);
818
895
 
@@ -821,6 +898,7 @@ public class DexManager {
821
898
  JSObject result = new JSObject();
822
899
  result.put("className", className);
823
900
  result.put("smali", smali);
901
+ result.put("engine", "java");
824
902
  return result;
825
903
  } else {
826
904
  throw new IOException("Failed to generate smali for: " + className);
@@ -887,30 +965,51 @@ public class DexManager {
887
965
  // ==================== 搜索操作 ====================
888
966
 
889
967
  /**
890
- * 搜索字符串
968
+ * 搜索字符串(优先使用 C++ 实现)
891
969
  */
892
970
  public JSArray searchString(String sessionId, String query,
893
971
  boolean regex, boolean caseSensitive) throws Exception {
894
972
  DexSession session = getSession(sessionId);
973
+
974
+ // 优先使用 C++ 实现
975
+ if (CppDex.isAvailable() && session.dexBytes != null && !regex) {
976
+ try {
977
+ String jsonResult = CppDex.searchInDex(session.dexBytes, query, "string", caseSensitive, 1000);
978
+ if (jsonResult != null && !jsonResult.contains("\"error\"")) {
979
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
980
+ org.json.JSONArray cppResults = cppResult.optJSONArray("results");
981
+ if (cppResults != null) {
982
+ JSArray results = new JSArray();
983
+ for (int i = 0; i < cppResults.length(); i++) {
984
+ org.json.JSONObject r = cppResults.getJSONObject(i);
985
+ JSObject item = new JSObject();
986
+ item.put("value", r.optString("value"));
987
+ item.put("index", r.optInt("index"));
988
+ results.put(item);
989
+ }
990
+ return results;
991
+ }
992
+ }
993
+ } catch (Exception e) {
994
+ Log.w(TAG, "C++ searchString failed, fallback to Java", e);
995
+ }
996
+ }
997
+
998
+ // Java 回退实现
895
999
  JSArray results = new JSArray();
896
-
897
1000
  Pattern pattern = null;
898
1001
  if (regex) {
899
1002
  int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
900
1003
  pattern = Pattern.compile(query, flags);
901
1004
  }
902
1005
 
903
- // 遍历所有类中的字符串引用进行搜索
904
1006
  Set<String> searchedStrings = new HashSet<>();
905
1007
  for (ClassDef classDef : session.originalDexFile.getClasses()) {
906
- // 类名
907
1008
  checkAndAddString(classDef.getType(), query, regex, caseSensitive, pattern, searchedStrings, results);
908
- // 父类
909
1009
  if (classDef.getSuperclass() != null) {
910
1010
  checkAndAddString(classDef.getSuperclass(), query, regex, caseSensitive, pattern, searchedStrings, results);
911
1011
  }
912
1012
  }
913
-
914
1013
  return results;
915
1014
  }
916
1015
 
@@ -945,16 +1044,41 @@ public class DexManager {
945
1044
  }
946
1045
 
947
1046
  /**
948
- * 搜索方法
1047
+ * 搜索方法(优先使用 C++ 实现)
949
1048
  */
950
1049
  public JSArray searchMethod(String sessionId, String query) throws Exception {
951
1050
  DexSession session = getSession(sessionId);
1051
+
1052
+ // 优先使用 C++ 实现
1053
+ if (CppDex.isAvailable() && session.dexBytes != null) {
1054
+ try {
1055
+ String jsonResult = CppDex.searchInDex(session.dexBytes, query, "method", false, 1000);
1056
+ if (jsonResult != null && !jsonResult.contains("\"error\"")) {
1057
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
1058
+ org.json.JSONArray cppResults = cppResult.optJSONArray("results");
1059
+ if (cppResults != null) {
1060
+ JSArray results = new JSArray();
1061
+ for (int i = 0; i < cppResults.length(); i++) {
1062
+ org.json.JSONObject r = cppResults.getJSONObject(i);
1063
+ JSObject item = new JSObject();
1064
+ item.put("className", r.optString("className"));
1065
+ item.put("methodName", r.optString("name"));
1066
+ item.put("returnType", r.optString("returnType", ""));
1067
+ results.put(item);
1068
+ }
1069
+ return results;
1070
+ }
1071
+ }
1072
+ } catch (Exception e) {
1073
+ Log.w(TAG, "C++ searchMethod failed, fallback to Java", e);
1074
+ }
1075
+ }
1076
+
1077
+ // Java 回退实现
952
1078
  JSArray results = new JSArray();
953
1079
  String queryLower = query.toLowerCase();
954
-
955
1080
  for (ClassDef classDef : session.originalDexFile.getClasses()) {
956
1081
  if (session.removedClasses.contains(classDef.getType())) continue;
957
-
958
1082
  for (Method method : classDef.getMethods()) {
959
1083
  if (method.getName().toLowerCase().contains(queryLower)) {
960
1084
  JSObject item = new JSObject();
@@ -965,21 +1089,45 @@ public class DexManager {
965
1089
  }
966
1090
  }
967
1091
  }
968
-
969
1092
  return results;
970
1093
  }
971
1094
 
972
1095
  /**
973
- * 搜索字段
1096
+ * 搜索字段(优先使用 C++ 实现)
974
1097
  */
975
1098
  public JSArray searchField(String sessionId, String query) throws Exception {
976
1099
  DexSession session = getSession(sessionId);
1100
+
1101
+ // 优先使用 C++ 实现
1102
+ if (CppDex.isAvailable() && session.dexBytes != null) {
1103
+ try {
1104
+ String jsonResult = CppDex.searchInDex(session.dexBytes, query, "field", false, 1000);
1105
+ if (jsonResult != null && !jsonResult.contains("\"error\"")) {
1106
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
1107
+ org.json.JSONArray cppResults = cppResult.optJSONArray("results");
1108
+ if (cppResults != null) {
1109
+ JSArray results = new JSArray();
1110
+ for (int i = 0; i < cppResults.length(); i++) {
1111
+ org.json.JSONObject r = cppResults.getJSONObject(i);
1112
+ JSObject item = new JSObject();
1113
+ item.put("className", r.optString("className"));
1114
+ item.put("fieldName", r.optString("name"));
1115
+ item.put("fieldType", r.optString("type", ""));
1116
+ results.put(item);
1117
+ }
1118
+ return results;
1119
+ }
1120
+ }
1121
+ } catch (Exception e) {
1122
+ Log.w(TAG, "C++ searchField failed, fallback to Java", e);
1123
+ }
1124
+ }
1125
+
1126
+ // Java 回退实现
977
1127
  JSArray results = new JSArray();
978
1128
  String queryLower = query.toLowerCase();
979
-
980
1129
  for (ClassDef classDef : session.originalDexFile.getClasses()) {
981
1130
  if (session.removedClasses.contains(classDef.getType())) continue;
982
-
983
1131
  for (Field field : classDef.getFields()) {
984
1132
  if (field.getName().toLowerCase().contains(queryLower)) {
985
1133
  JSObject item = new JSObject();
@@ -990,10 +1138,109 @@ public class DexManager {
990
1138
  }
991
1139
  }
992
1140
  }
993
-
994
1141
  return results;
995
1142
  }
996
1143
 
1144
+ // ==================== 交叉引用分析(C++ 实现)====================
1145
+
1146
+ /**
1147
+ * 查找方法的交叉引用
1148
+ */
1149
+ public JSObject findMethodXrefs(String sessionId, String className, String methodName) throws Exception {
1150
+ DexSession session = getSession(sessionId);
1151
+
1152
+ if (!CppDex.isAvailable() || session.dexBytes == null) {
1153
+ throw new UnsupportedOperationException("C++ library not available for xref analysis");
1154
+ }
1155
+
1156
+ String jsonResult = CppDex.findMethodXrefs(session.dexBytes, className, methodName);
1157
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
1158
+ throw new Exception("Failed to find method xrefs");
1159
+ }
1160
+
1161
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
1162
+ JSObject result = new JSObject();
1163
+ result.put("className", className);
1164
+ result.put("methodName", methodName);
1165
+
1166
+ org.json.JSONArray xrefs = cppResult.optJSONArray("xrefs");
1167
+ JSArray xrefArray = new JSArray();
1168
+ if (xrefs != null) {
1169
+ for (int i = 0; i < xrefs.length(); i++) {
1170
+ org.json.JSONObject x = xrefs.getJSONObject(i);
1171
+ JSObject xref = new JSObject();
1172
+ xref.put("callerClass", x.optString("callerClass"));
1173
+ xref.put("callerMethod", x.optString("callerMethod"));
1174
+ xref.put("offset", x.optInt("offset"));
1175
+ xrefArray.put(xref);
1176
+ }
1177
+ }
1178
+ result.put("xrefs", xrefArray);
1179
+ result.put("count", xrefArray.length());
1180
+ return result;
1181
+ }
1182
+
1183
+ /**
1184
+ * 查找字段的交叉引用
1185
+ */
1186
+ public JSObject findFieldXrefs(String sessionId, String className, String fieldName) throws Exception {
1187
+ DexSession session = getSession(sessionId);
1188
+
1189
+ if (!CppDex.isAvailable() || session.dexBytes == null) {
1190
+ throw new UnsupportedOperationException("C++ library not available for xref analysis");
1191
+ }
1192
+
1193
+ String jsonResult = CppDex.findFieldXrefs(session.dexBytes, className, fieldName);
1194
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
1195
+ throw new Exception("Failed to find field xrefs");
1196
+ }
1197
+
1198
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
1199
+ JSObject result = new JSObject();
1200
+ result.put("className", className);
1201
+ result.put("fieldName", fieldName);
1202
+
1203
+ org.json.JSONArray xrefs = cppResult.optJSONArray("xrefs");
1204
+ JSArray xrefArray = new JSArray();
1205
+ if (xrefs != null) {
1206
+ for (int i = 0; i < xrefs.length(); i++) {
1207
+ org.json.JSONObject x = xrefs.getJSONObject(i);
1208
+ JSObject xref = new JSObject();
1209
+ xref.put("accessorClass", x.optString("accessorClass"));
1210
+ xref.put("accessorMethod", x.optString("accessorMethod"));
1211
+ xref.put("accessType", x.optString("accessType"));
1212
+ xrefArray.put(xref);
1213
+ }
1214
+ }
1215
+ result.put("xrefs", xrefArray);
1216
+ result.put("count", xrefArray.length());
1217
+ return result;
1218
+ }
1219
+
1220
+ // ==================== Smali 转 Java(C++ 实现)====================
1221
+
1222
+ /**
1223
+ * 将 Smali 代码转换为 Java 伪代码
1224
+ */
1225
+ public JSObject smaliToJava(String sessionId, String className) throws Exception {
1226
+ DexSession session = getSession(sessionId);
1227
+
1228
+ if (!CppDex.isAvailable() || session.dexBytes == null) {
1229
+ throw new UnsupportedOperationException("C++ library not available for smali to java conversion");
1230
+ }
1231
+
1232
+ String jsonResult = CppDex.smaliToJava(session.dexBytes, className);
1233
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
1234
+ throw new Exception("Failed to convert smali to java");
1235
+ }
1236
+
1237
+ org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
1238
+ JSObject result = new JSObject();
1239
+ result.put("className", className);
1240
+ result.put("java", cppResult.optString("java", ""));
1241
+ return result;
1242
+ }
1243
+
997
1244
  // ==================== 工具操作 ====================
998
1245
 
999
1246
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-dex-editor",
3
- "version": "0.0.71",
3
+ "version": "0.0.73",
4
4
  "description": "Capacitor-plugin-for-editing-DEX-files-in-APK",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",