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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
572
|
-
|
|
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
|
-
//
|
|
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
|
/**
|