capacitor-dex-editor 0.0.71 → 0.0.72
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(
|
|
@@ -562,21 +562,42 @@ public class DexManager {
|
|
|
562
562
|
}
|
|
563
563
|
|
|
564
564
|
/**
|
|
565
|
-
* 获取方法的 Smali
|
|
565
|
+
* 获取方法的 Smali 代码(优先使用 C++ 实现)
|
|
566
566
|
*/
|
|
567
567
|
public JSObject getMethodSmali(String sessionId, String className,
|
|
568
568
|
String methodName, String methodSignature) throws Exception {
|
|
569
569
|
DexSession session = getSession(sessionId);
|
|
570
570
|
|
|
571
|
-
//
|
|
572
|
-
|
|
571
|
+
// 优先使用 C++ 实现
|
|
572
|
+
if (CppDex.isAvailable() && session.dexBytes != null) {
|
|
573
|
+
try {
|
|
574
|
+
String jsonResult = CppDex.getMethodSmali(session.dexBytes, className, methodName, methodSignature);
|
|
575
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
576
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
577
|
+
String smali = cppResult.optString("smali", "");
|
|
578
|
+
if (!smali.isEmpty()) {
|
|
579
|
+
JSObject result = new JSObject();
|
|
580
|
+
result.put("className", className);
|
|
581
|
+
result.put("methodName", methodName);
|
|
582
|
+
result.put("methodSignature", methodSignature);
|
|
583
|
+
result.put("smali", smali);
|
|
584
|
+
result.put("engine", "cpp");
|
|
585
|
+
return result;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
} catch (Exception e) {
|
|
589
|
+
Log.w(TAG, "C++ getMethodSmali failed, fallback to Java", e);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
573
592
|
|
|
574
|
-
//
|
|
593
|
+
// Java 回退实现
|
|
594
|
+
String classSmali = classToSmali(sessionId, className).getString("smali");
|
|
575
595
|
JSObject result = new JSObject();
|
|
576
596
|
result.put("className", className);
|
|
577
597
|
result.put("methodName", methodName);
|
|
578
598
|
result.put("methodSignature", methodSignature);
|
|
579
599
|
result.put("smali", extractMethodSmali(classSmali, methodName, methodSignature));
|
|
600
|
+
result.put("engine", "java");
|
|
580
601
|
return result;
|
|
581
602
|
}
|
|
582
603
|
|
|
@@ -782,21 +803,40 @@ public class DexManager {
|
|
|
782
803
|
// ==================== Smali 操作 ====================
|
|
783
804
|
|
|
784
805
|
/**
|
|
785
|
-
* 将类转换为 Smali
|
|
806
|
+
* 将类转换为 Smali 代码(优先使用 C++ 实现)
|
|
786
807
|
*/
|
|
787
808
|
public JSObject classToSmali(String sessionId, String className) throws Exception {
|
|
788
809
|
DexSession session = getSession(sessionId);
|
|
810
|
+
|
|
811
|
+
// 优先使用 C++ 实现
|
|
812
|
+
if (CppDex.isAvailable() && session.dexBytes != null) {
|
|
813
|
+
try {
|
|
814
|
+
String jsonResult = CppDex.getClassSmali(session.dexBytes, className);
|
|
815
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
816
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
817
|
+
String smali = cppResult.optString("smali", "");
|
|
818
|
+
if (!smali.isEmpty()) {
|
|
819
|
+
JSObject result = new JSObject();
|
|
820
|
+
result.put("className", className);
|
|
821
|
+
result.put("smali", smali);
|
|
822
|
+
result.put("engine", "cpp");
|
|
823
|
+
return result;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
} catch (Exception e) {
|
|
827
|
+
Log.w(TAG, "C++ classToSmali failed, fallback to Java", e);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Java 回退实现
|
|
789
832
|
ClassDef classDef = findClass(session, className);
|
|
790
|
-
|
|
791
833
|
if (classDef == null) {
|
|
792
834
|
throw new IllegalArgumentException("Class not found: " + className);
|
|
793
835
|
}
|
|
794
836
|
|
|
795
|
-
// 使用 baksmali 转换
|
|
796
837
|
StringWriter writer = new StringWriter();
|
|
797
838
|
BaksmaliOptions options = new BaksmaliOptions();
|
|
798
839
|
|
|
799
|
-
// 创建临时 DEX 只包含该类
|
|
800
840
|
List<ClassDef> singleClass = new ArrayList<>();
|
|
801
841
|
singleClass.add(classDef);
|
|
802
842
|
ImmutableDexFile singleDex = new ImmutableDexFile(
|
|
@@ -804,7 +844,6 @@ public class DexManager {
|
|
|
804
844
|
singleClass
|
|
805
845
|
);
|
|
806
846
|
|
|
807
|
-
// 使用临时目录输出
|
|
808
847
|
File tempDir = File.createTempFile("smali_", "_temp");
|
|
809
848
|
tempDir.delete();
|
|
810
849
|
tempDir.mkdirs();
|
|
@@ -812,7 +851,6 @@ public class DexManager {
|
|
|
812
851
|
try {
|
|
813
852
|
Baksmali.disassembleDexFile(singleDex, tempDir, 1, options);
|
|
814
853
|
|
|
815
|
-
// 读取生成的 smali 文件
|
|
816
854
|
String smaliPath = className.substring(1, className.length() - 1) + ".smali";
|
|
817
855
|
File smaliFile = new File(tempDir, smaliPath);
|
|
818
856
|
|
|
@@ -821,6 +859,7 @@ public class DexManager {
|
|
|
821
859
|
JSObject result = new JSObject();
|
|
822
860
|
result.put("className", className);
|
|
823
861
|
result.put("smali", smali);
|
|
862
|
+
result.put("engine", "java");
|
|
824
863
|
return result;
|
|
825
864
|
} else {
|
|
826
865
|
throw new IOException("Failed to generate smali for: " + className);
|
|
@@ -887,30 +926,51 @@ public class DexManager {
|
|
|
887
926
|
// ==================== 搜索操作 ====================
|
|
888
927
|
|
|
889
928
|
/**
|
|
890
|
-
*
|
|
929
|
+
* 搜索字符串(优先使用 C++ 实现)
|
|
891
930
|
*/
|
|
892
931
|
public JSArray searchString(String sessionId, String query,
|
|
893
932
|
boolean regex, boolean caseSensitive) throws Exception {
|
|
894
933
|
DexSession session = getSession(sessionId);
|
|
934
|
+
|
|
935
|
+
// 优先使用 C++ 实现
|
|
936
|
+
if (CppDex.isAvailable() && session.dexBytes != null && !regex) {
|
|
937
|
+
try {
|
|
938
|
+
String jsonResult = CppDex.searchInDex(session.dexBytes, query, "string", caseSensitive, 1000);
|
|
939
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
940
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
941
|
+
org.json.JSONArray cppResults = cppResult.optJSONArray("results");
|
|
942
|
+
if (cppResults != null) {
|
|
943
|
+
JSArray results = new JSArray();
|
|
944
|
+
for (int i = 0; i < cppResults.length(); i++) {
|
|
945
|
+
org.json.JSONObject r = cppResults.getJSONObject(i);
|
|
946
|
+
JSObject item = new JSObject();
|
|
947
|
+
item.put("value", r.optString("value"));
|
|
948
|
+
item.put("index", r.optInt("index"));
|
|
949
|
+
results.put(item);
|
|
950
|
+
}
|
|
951
|
+
return results;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
} catch (Exception e) {
|
|
955
|
+
Log.w(TAG, "C++ searchString failed, fallback to Java", e);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Java 回退实现
|
|
895
960
|
JSArray results = new JSArray();
|
|
896
|
-
|
|
897
961
|
Pattern pattern = null;
|
|
898
962
|
if (regex) {
|
|
899
963
|
int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
|
|
900
964
|
pattern = Pattern.compile(query, flags);
|
|
901
965
|
}
|
|
902
966
|
|
|
903
|
-
// 遍历所有类中的字符串引用进行搜索
|
|
904
967
|
Set<String> searchedStrings = new HashSet<>();
|
|
905
968
|
for (ClassDef classDef : session.originalDexFile.getClasses()) {
|
|
906
|
-
// 类名
|
|
907
969
|
checkAndAddString(classDef.getType(), query, regex, caseSensitive, pattern, searchedStrings, results);
|
|
908
|
-
// 父类
|
|
909
970
|
if (classDef.getSuperclass() != null) {
|
|
910
971
|
checkAndAddString(classDef.getSuperclass(), query, regex, caseSensitive, pattern, searchedStrings, results);
|
|
911
972
|
}
|
|
912
973
|
}
|
|
913
|
-
|
|
914
974
|
return results;
|
|
915
975
|
}
|
|
916
976
|
|
|
@@ -945,16 +1005,41 @@ public class DexManager {
|
|
|
945
1005
|
}
|
|
946
1006
|
|
|
947
1007
|
/**
|
|
948
|
-
*
|
|
1008
|
+
* 搜索方法(优先使用 C++ 实现)
|
|
949
1009
|
*/
|
|
950
1010
|
public JSArray searchMethod(String sessionId, String query) throws Exception {
|
|
951
1011
|
DexSession session = getSession(sessionId);
|
|
1012
|
+
|
|
1013
|
+
// 优先使用 C++ 实现
|
|
1014
|
+
if (CppDex.isAvailable() && session.dexBytes != null) {
|
|
1015
|
+
try {
|
|
1016
|
+
String jsonResult = CppDex.searchInDex(session.dexBytes, query, "method", false, 1000);
|
|
1017
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1018
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
1019
|
+
org.json.JSONArray cppResults = cppResult.optJSONArray("results");
|
|
1020
|
+
if (cppResults != null) {
|
|
1021
|
+
JSArray results = new JSArray();
|
|
1022
|
+
for (int i = 0; i < cppResults.length(); i++) {
|
|
1023
|
+
org.json.JSONObject r = cppResults.getJSONObject(i);
|
|
1024
|
+
JSObject item = new JSObject();
|
|
1025
|
+
item.put("className", r.optString("className"));
|
|
1026
|
+
item.put("methodName", r.optString("name"));
|
|
1027
|
+
item.put("returnType", r.optString("returnType", ""));
|
|
1028
|
+
results.put(item);
|
|
1029
|
+
}
|
|
1030
|
+
return results;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
} catch (Exception e) {
|
|
1034
|
+
Log.w(TAG, "C++ searchMethod failed, fallback to Java", e);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Java 回退实现
|
|
952
1039
|
JSArray results = new JSArray();
|
|
953
1040
|
String queryLower = query.toLowerCase();
|
|
954
|
-
|
|
955
1041
|
for (ClassDef classDef : session.originalDexFile.getClasses()) {
|
|
956
1042
|
if (session.removedClasses.contains(classDef.getType())) continue;
|
|
957
|
-
|
|
958
1043
|
for (Method method : classDef.getMethods()) {
|
|
959
1044
|
if (method.getName().toLowerCase().contains(queryLower)) {
|
|
960
1045
|
JSObject item = new JSObject();
|
|
@@ -965,21 +1050,45 @@ public class DexManager {
|
|
|
965
1050
|
}
|
|
966
1051
|
}
|
|
967
1052
|
}
|
|
968
|
-
|
|
969
1053
|
return results;
|
|
970
1054
|
}
|
|
971
1055
|
|
|
972
1056
|
/**
|
|
973
|
-
*
|
|
1057
|
+
* 搜索字段(优先使用 C++ 实现)
|
|
974
1058
|
*/
|
|
975
1059
|
public JSArray searchField(String sessionId, String query) throws Exception {
|
|
976
1060
|
DexSession session = getSession(sessionId);
|
|
1061
|
+
|
|
1062
|
+
// 优先使用 C++ 实现
|
|
1063
|
+
if (CppDex.isAvailable() && session.dexBytes != null) {
|
|
1064
|
+
try {
|
|
1065
|
+
String jsonResult = CppDex.searchInDex(session.dexBytes, query, "field", false, 1000);
|
|
1066
|
+
if (jsonResult != null && !jsonResult.contains("\"error\"")) {
|
|
1067
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
1068
|
+
org.json.JSONArray cppResults = cppResult.optJSONArray("results");
|
|
1069
|
+
if (cppResults != null) {
|
|
1070
|
+
JSArray results = new JSArray();
|
|
1071
|
+
for (int i = 0; i < cppResults.length(); i++) {
|
|
1072
|
+
org.json.JSONObject r = cppResults.getJSONObject(i);
|
|
1073
|
+
JSObject item = new JSObject();
|
|
1074
|
+
item.put("className", r.optString("className"));
|
|
1075
|
+
item.put("fieldName", r.optString("name"));
|
|
1076
|
+
item.put("fieldType", r.optString("type", ""));
|
|
1077
|
+
results.put(item);
|
|
1078
|
+
}
|
|
1079
|
+
return results;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
} catch (Exception e) {
|
|
1083
|
+
Log.w(TAG, "C++ searchField failed, fallback to Java", e);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Java 回退实现
|
|
977
1088
|
JSArray results = new JSArray();
|
|
978
1089
|
String queryLower = query.toLowerCase();
|
|
979
|
-
|
|
980
1090
|
for (ClassDef classDef : session.originalDexFile.getClasses()) {
|
|
981
1091
|
if (session.removedClasses.contains(classDef.getType())) continue;
|
|
982
|
-
|
|
983
1092
|
for (Field field : classDef.getFields()) {
|
|
984
1093
|
if (field.getName().toLowerCase().contains(queryLower)) {
|
|
985
1094
|
JSObject item = new JSObject();
|
|
@@ -990,10 +1099,109 @@ public class DexManager {
|
|
|
990
1099
|
}
|
|
991
1100
|
}
|
|
992
1101
|
}
|
|
993
|
-
|
|
994
1102
|
return results;
|
|
995
1103
|
}
|
|
996
1104
|
|
|
1105
|
+
// ==================== 交叉引用分析(C++ 实现)====================
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* 查找方法的交叉引用
|
|
1109
|
+
*/
|
|
1110
|
+
public JSObject findMethodXrefs(String sessionId, String className, String methodName) throws Exception {
|
|
1111
|
+
DexSession session = getSession(sessionId);
|
|
1112
|
+
|
|
1113
|
+
if (!CppDex.isAvailable() || session.dexBytes == null) {
|
|
1114
|
+
throw new UnsupportedOperationException("C++ library not available for xref analysis");
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
String jsonResult = CppDex.findMethodXrefs(session.dexBytes, className, methodName);
|
|
1118
|
+
if (jsonResult == null || jsonResult.contains("\"error\"")) {
|
|
1119
|
+
throw new Exception("Failed to find method xrefs");
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
1123
|
+
JSObject result = new JSObject();
|
|
1124
|
+
result.put("className", className);
|
|
1125
|
+
result.put("methodName", methodName);
|
|
1126
|
+
|
|
1127
|
+
org.json.JSONArray xrefs = cppResult.optJSONArray("xrefs");
|
|
1128
|
+
JSArray xrefArray = new JSArray();
|
|
1129
|
+
if (xrefs != null) {
|
|
1130
|
+
for (int i = 0; i < xrefs.length(); i++) {
|
|
1131
|
+
org.json.JSONObject x = xrefs.getJSONObject(i);
|
|
1132
|
+
JSObject xref = new JSObject();
|
|
1133
|
+
xref.put("callerClass", x.optString("callerClass"));
|
|
1134
|
+
xref.put("callerMethod", x.optString("callerMethod"));
|
|
1135
|
+
xref.put("offset", x.optInt("offset"));
|
|
1136
|
+
xrefArray.put(xref);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
result.put("xrefs", xrefArray);
|
|
1140
|
+
result.put("count", xrefArray.length());
|
|
1141
|
+
return result;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
/**
|
|
1145
|
+
* 查找字段的交叉引用
|
|
1146
|
+
*/
|
|
1147
|
+
public JSObject findFieldXrefs(String sessionId, String className, String fieldName) throws Exception {
|
|
1148
|
+
DexSession session = getSession(sessionId);
|
|
1149
|
+
|
|
1150
|
+
if (!CppDex.isAvailable() || session.dexBytes == null) {
|
|
1151
|
+
throw new UnsupportedOperationException("C++ library not available for xref analysis");
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
String jsonResult = CppDex.findFieldXrefs(session.dexBytes, className, fieldName);
|
|
1155
|
+
if (jsonResult == null || jsonResult.contains("\"error\"")) {
|
|
1156
|
+
throw new Exception("Failed to find field xrefs");
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
org.json.JSONObject cppResult = new org.json.JSONObject(jsonResult);
|
|
1160
|
+
JSObject result = new JSObject();
|
|
1161
|
+
result.put("className", className);
|
|
1162
|
+
result.put("fieldName", fieldName);
|
|
1163
|
+
|
|
1164
|
+
org.json.JSONArray xrefs = cppResult.optJSONArray("xrefs");
|
|
1165
|
+
JSArray xrefArray = new JSArray();
|
|
1166
|
+
if (xrefs != null) {
|
|
1167
|
+
for (int i = 0; i < xrefs.length(); i++) {
|
|
1168
|
+
org.json.JSONObject x = xrefs.getJSONObject(i);
|
|
1169
|
+
JSObject xref = new JSObject();
|
|
1170
|
+
xref.put("accessorClass", x.optString("accessorClass"));
|
|
1171
|
+
xref.put("accessorMethod", x.optString("accessorMethod"));
|
|
1172
|
+
xref.put("accessType", x.optString("accessType"));
|
|
1173
|
+
xrefArray.put(xref);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
result.put("xrefs", xrefArray);
|
|
1177
|
+
result.put("count", xrefArray.length());
|
|
1178
|
+
return result;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// ==================== Smali 转 Java(C++ 实现)====================
|
|
1182
|
+
|
|
1183
|
+
/**
|
|
1184
|
+
* 将 Smali 代码转换为 Java 伪代码
|
|
1185
|
+
*/
|
|
1186
|
+
public JSObject smaliToJava(String sessionId, String className) throws Exception {
|
|
1187
|
+
DexSession session = getSession(sessionId);
|
|
1188
|
+
|
|
1189
|
+
if (!CppDex.isAvailable() || session.dexBytes == null) {
|
|
1190
|
+
throw new UnsupportedOperationException("C++ library not available for smali to java conversion");
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
String jsonResult = CppDex.smaliToJava(session.dexBytes, className);
|
|
1194
|
+
if (jsonResult == null || jsonResult.contains("\"error\"")) {
|
|
1195
|
+
throw new Exception("Failed to convert smali to java");
|
|
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("java", cppResult.optString("java", ""));
|
|
1202
|
+
return result;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
997
1205
|
// ==================== 工具操作 ====================
|
|
998
1206
|
|
|
999
1207
|
/**
|