capacitor-dex-editor 0.0.68 → 0.0.70

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.
Files changed (40) hide show
  1. package/android/build.gradle +22 -0
  2. package/android/src/main/cpp/CMakeLists.txt +57 -0
  3. package/android/src/main/cpp/apk/apk_handler.cpp +121 -0
  4. package/android/src/main/cpp/apk/zip_utils.cpp +425 -0
  5. package/android/src/main/cpp/arsc/arsc_parser.cpp +390 -0
  6. package/android/src/main/cpp/dex/dex_builder.cpp +752 -0
  7. package/android/src/main/cpp/dex/dex_parser.cpp +620 -0
  8. package/android/src/main/cpp/dex/smali_disasm.cpp +1223 -0
  9. package/android/src/main/cpp/dex/smali_to_java.cpp +576 -0
  10. package/android/src/main/cpp/include/apk/apk_handler.h +41 -0
  11. package/android/src/main/cpp/include/apk/zip_utils.h +57 -0
  12. package/android/src/main/cpp/include/arsc/arsc_parser.h +98 -0
  13. package/android/src/main/cpp/include/dex/dex_builder.h +189 -0
  14. package/android/src/main/cpp/include/dex/dex_parser.h +137 -0
  15. package/android/src/main/cpp/include/dex/smali_disasm.h +127 -0
  16. package/android/src/main/cpp/include/dex/smali_to_java.h +50 -0
  17. package/android/src/main/cpp/include/xml/android_resources.h +495 -0
  18. package/android/src/main/cpp/include/xml/axml_parser.h +147 -0
  19. package/android/src/main/cpp/jni_bridge.cpp +872 -0
  20. package/android/src/main/cpp/third_party/miniz.c +646 -0
  21. package/android/src/main/cpp/third_party/miniz.h +605 -0
  22. package/android/src/main/cpp/third_party/miniz_common.h +97 -0
  23. package/android/src/main/cpp/third_party/miniz_export.h +6 -0
  24. package/android/src/main/cpp/third_party/miniz_tdef.c +1597 -0
  25. package/android/src/main/cpp/third_party/miniz_tdef.h +199 -0
  26. package/android/src/main/cpp/third_party/miniz_tinfl.c +770 -0
  27. package/android/src/main/cpp/third_party/miniz_tinfl.h +150 -0
  28. package/android/src/main/cpp/third_party/miniz_zip.c +4895 -0
  29. package/android/src/main/cpp/third_party/miniz_zip.h +454 -0
  30. package/android/src/main/cpp/third_party/nlohmann_json/CMakeLists.txt +0 -0
  31. package/android/src/main/cpp/third_party/nlohmann_json/single_include/nlohmann/json.hpp +24765 -0
  32. package/android/src/main/cpp/xml/axml_parser.cpp +1701 -0
  33. package/android/src/main/java/com/aetherlink/dexeditor/CppDex.java +295 -0
  34. package/android/src/main/java/com/aetherlink/dexeditor/DexManager.java +20 -20
  35. package/package.json +1 -1
  36. package/android/src/main/java/com/aetherlink/dexeditor/RustDex.java +0 -108
  37. package/android/src/main/jniLibs/arm64-v8a/libdex_rust.so +0 -0
  38. package/android/src/main/jniLibs/armeabi-v7a/libdex_rust.so +0 -0
  39. package/android/src/main/jniLibs/x86/libdex_rust.so +0 -0
  40. package/android/src/main/jniLibs/x86_64/libdex_rust.so +0 -0
@@ -0,0 +1,872 @@
1
+ #include <jni.h>
2
+ #include <string>
3
+ #include <vector>
4
+ #include <android/log.h>
5
+
6
+ #include "dex/dex_parser.h"
7
+ #include "dex/dex_builder.h"
8
+ #include "dex/smali_disasm.h"
9
+ #include "dex/smali_to_java.h"
10
+ #include "xml/axml_parser.h"
11
+ #include "arsc/arsc_parser.h"
12
+ #include "apk/apk_handler.h"
13
+
14
+ #include <nlohmann/json.hpp>
15
+
16
+ #define LOG_TAG "CppDex"
17
+ #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
18
+ #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
19
+
20
+ using json = nlohmann::json;
21
+
22
+ // Helper: Convert jbyteArray to std::vector<uint8_t>
23
+ static std::vector<uint8_t> jbyteArray_to_vector(JNIEnv* env, jbyteArray array) {
24
+ if (!array) return {};
25
+ jsize len = env->GetArrayLength(array);
26
+ std::vector<uint8_t> result(len);
27
+ env->GetByteArrayRegion(array, 0, len, reinterpret_cast<jbyte*>(result.data()));
28
+ return result;
29
+ }
30
+
31
+ // Helper: Convert std::vector<uint8_t> to jbyteArray
32
+ static jbyteArray vector_to_jbyteArray(JNIEnv* env, const std::vector<uint8_t>& data) {
33
+ jbyteArray result = env->NewByteArray(static_cast<jsize>(data.size()));
34
+ if (result) {
35
+ env->SetByteArrayRegion(result, 0, static_cast<jsize>(data.size()),
36
+ reinterpret_cast<const jbyte*>(data.data()));
37
+ }
38
+ return result;
39
+ }
40
+
41
+ // Helper: Convert jstring to std::string
42
+ static std::string jstring_to_string(JNIEnv* env, jstring str) {
43
+ if (!str) return "";
44
+ const char* chars = env->GetStringUTFChars(str, nullptr);
45
+ std::string result(chars);
46
+ env->ReleaseStringUTFChars(str, chars);
47
+ return result;
48
+ }
49
+
50
+ // Helper: Convert std::string to jstring
51
+ static jstring string_to_jstring(JNIEnv* env, const std::string& str) {
52
+ return env->NewStringUTF(str.c_str());
53
+ }
54
+
55
+ extern "C" {
56
+
57
+ // ==================== DEX 解析操作 ====================
58
+
59
+ JNIEXPORT jstring JNICALL
60
+ Java_com_aetherlink_dexeditor_CppDex_getDexInfo(JNIEnv* env, jclass, jbyteArray dexBytes) {
61
+ auto data = jbyteArray_to_vector(env, dexBytes);
62
+
63
+ dex::DexParser parser;
64
+ if (!parser.parse(data)) {
65
+ json error = {{"error", "Failed to parse DEX"}};
66
+ return string_to_jstring(env, error.dump());
67
+ }
68
+
69
+ const auto& header = parser.header();
70
+ json result = {
71
+ {"version", std::string(reinterpret_cast<const char*>(header.magic + 4), 3)},
72
+ {"file_size", header.file_size},
73
+ {"strings_count", header.string_ids_size},
74
+ {"types_count", header.type_ids_size},
75
+ {"protos_count", header.proto_ids_size},
76
+ {"fields_count", header.field_ids_size},
77
+ {"methods_count", header.method_ids_size},
78
+ {"classes_count", header.class_defs_size}
79
+ };
80
+
81
+ return string_to_jstring(env, result.dump());
82
+ }
83
+
84
+ JNIEXPORT jstring JNICALL
85
+ Java_com_aetherlink_dexeditor_CppDex_listClasses(JNIEnv* env, jclass, jbyteArray dexBytes,
86
+ jstring packageFilter, jint offset, jint limit) {
87
+ auto data = jbyteArray_to_vector(env, dexBytes);
88
+ std::string filter = jstring_to_string(env, packageFilter);
89
+
90
+ dex::DexParser parser;
91
+ if (!parser.parse(data)) {
92
+ json error = {{"error", "Failed to parse DEX"}};
93
+ return string_to_jstring(env, error.dump());
94
+ }
95
+
96
+ json class_list = json::array();
97
+ const auto& classes = parser.classes();
98
+ int count = 0;
99
+ int matched = 0;
100
+
101
+ for (const auto& cls : classes) {
102
+ std::string class_name = parser.get_class_name(cls.class_idx);
103
+
104
+ if (!filter.empty() && class_name.find(filter) == std::string::npos) {
105
+ continue;
106
+ }
107
+
108
+ matched++;
109
+ if (matched > offset && count < limit) {
110
+ class_list.push_back(class_name);
111
+ count++;
112
+ }
113
+ }
114
+
115
+ json result = {
116
+ {"classes", class_list},
117
+ {"shown", class_list.size()},
118
+ {"total", matched}
119
+ };
120
+
121
+ return string_to_jstring(env, result.dump());
122
+ }
123
+
124
+ JNIEXPORT jstring JNICALL
125
+ Java_com_aetherlink_dexeditor_CppDex_searchInDex(JNIEnv* env, jclass, jbyteArray dexBytes,
126
+ jstring query, jstring searchType,
127
+ jboolean caseSensitive, jint maxResults) {
128
+ auto data = jbyteArray_to_vector(env, dexBytes);
129
+ std::string q = jstring_to_string(env, query);
130
+ std::string type = jstring_to_string(env, searchType);
131
+
132
+ dex::DexParser parser;
133
+ if (!parser.parse(data)) {
134
+ json error = {{"error", "Failed to parse DEX"}};
135
+ return string_to_jstring(env, error.dump());
136
+ }
137
+
138
+ json results = json::array();
139
+ int count = 0;
140
+
141
+ // 转换为小写用于不区分大小写搜索
142
+ std::string q_lower = q;
143
+ if (!caseSensitive) {
144
+ std::transform(q_lower.begin(), q_lower.end(), q_lower.begin(), ::tolower);
145
+ }
146
+
147
+ if (type == "string") {
148
+ for (const auto& s : parser.strings()) {
149
+ if (count >= maxResults) break;
150
+
151
+ std::string s_check = caseSensitive ? s : s;
152
+ if (!caseSensitive) {
153
+ s_check.resize(s.size());
154
+ std::transform(s.begin(), s.end(), s_check.begin(), ::tolower);
155
+ }
156
+
157
+ if (s_check.find(q_lower) != std::string::npos) {
158
+ results.push_back({{"type", "string"}, {"value", s}});
159
+ count++;
160
+ }
161
+ }
162
+ } else if (type == "class") {
163
+ for (const auto& cls : parser.classes()) {
164
+ if (count >= maxResults) break;
165
+ std::string class_name = parser.get_class_name(cls.class_idx);
166
+
167
+ std::string check = caseSensitive ? class_name : class_name;
168
+ if (!caseSensitive) {
169
+ check.resize(class_name.size());
170
+ std::transform(class_name.begin(), class_name.end(), check.begin(), ::tolower);
171
+ }
172
+
173
+ if (check.find(q_lower) != std::string::npos) {
174
+ results.push_back({{"type", "class"}, {"name", class_name}});
175
+ count++;
176
+ }
177
+ }
178
+ } else if (type == "method") {
179
+ auto methods = parser.get_methods();
180
+ for (const auto& m : methods) {
181
+ if (count >= maxResults) break;
182
+
183
+ std::string check = caseSensitive ? m.method_name : m.method_name;
184
+ if (!caseSensitive) {
185
+ check.resize(m.method_name.size());
186
+ std::transform(m.method_name.begin(), m.method_name.end(), check.begin(), ::tolower);
187
+ }
188
+
189
+ if (check.find(q_lower) != std::string::npos) {
190
+ results.push_back({
191
+ {"type", "method"},
192
+ {"class", m.class_name},
193
+ {"name", m.method_name},
194
+ {"prototype", m.prototype}
195
+ });
196
+ count++;
197
+ }
198
+ }
199
+ } else if (type == "field") {
200
+ auto fields = parser.get_fields();
201
+ for (const auto& f : fields) {
202
+ if (count >= maxResults) break;
203
+
204
+ std::string check = caseSensitive ? f.field_name : f.field_name;
205
+ if (!caseSensitive) {
206
+ check.resize(f.field_name.size());
207
+ std::transform(f.field_name.begin(), f.field_name.end(), check.begin(), ::tolower);
208
+ }
209
+
210
+ if (check.find(q_lower) != std::string::npos) {
211
+ results.push_back({
212
+ {"type", "field"},
213
+ {"class", f.class_name},
214
+ {"name", f.field_name},
215
+ {"fieldType", f.type_name}
216
+ });
217
+ count++;
218
+ }
219
+ }
220
+ }
221
+
222
+ json result = {
223
+ {"query", q},
224
+ {"searchType", type},
225
+ {"results", results},
226
+ {"count", results.size()}
227
+ };
228
+
229
+ return string_to_jstring(env, result.dump());
230
+ }
231
+
232
+ JNIEXPORT jstring JNICALL
233
+ Java_com_aetherlink_dexeditor_CppDex_getClassSmali(JNIEnv* env, jclass, jbyteArray dexBytes,
234
+ jstring className) {
235
+ auto data = jbyteArray_to_vector(env, dexBytes);
236
+ std::string class_name = jstring_to_string(env, className);
237
+
238
+ dex::DexParser parser;
239
+ if (!parser.parse(data)) {
240
+ json error = {{"error", "Failed to parse DEX"}};
241
+ return string_to_jstring(env, error.dump());
242
+ }
243
+
244
+ // 设置反汇编器上下文
245
+ dex::SmaliDisassembler disasm;
246
+ disasm.set_strings(parser.strings());
247
+ disasm.set_types(parser.types());
248
+ disasm.set_methods(parser.get_method_signatures());
249
+ disasm.set_fields(parser.get_field_signatures());
250
+
251
+ // 查找类并反汇编所有方法
252
+ std::stringstream smali;
253
+ bool found = false;
254
+
255
+ for (const auto& cls : parser.classes()) {
256
+ if (parser.get_class_name(cls.class_idx) == class_name) {
257
+ found = true;
258
+
259
+ // 输出类声明
260
+ smali << ".class public " << class_name << "\n";
261
+ smali << ".super Ljava/lang/Object;\n\n";
262
+
263
+ // 获取该类的所有方法
264
+ auto methods = parser.get_methods();
265
+ for (const auto& m : methods) {
266
+ if (m.class_name == class_name) {
267
+ dex::CodeItem code;
268
+ if (parser.get_method_code(class_name, m.method_name, code)) {
269
+ auto insns = disasm.disassemble_method(code.insns.data(), code.insns.size());
270
+
271
+ smali << ".method public " << m.method_name << m.prototype << "\n";
272
+ smali << " .registers " << code.registers_size << "\n";
273
+ smali << disasm.to_smali(insns);
274
+ smali << ".end method\n\n";
275
+ }
276
+ }
277
+ }
278
+ break;
279
+ }
280
+ }
281
+
282
+ if (!found) {
283
+ json error = {{"error", "Class not found: " + class_name}};
284
+ return string_to_jstring(env, error.dump());
285
+ }
286
+
287
+ json result = {
288
+ {"className", class_name},
289
+ {"smali", smali.str()}
290
+ };
291
+
292
+ return string_to_jstring(env, result.dump());
293
+ }
294
+
295
+ JNIEXPORT jstring JNICALL
296
+ Java_com_aetherlink_dexeditor_CppDex_getMethodSmali(JNIEnv* env, jclass, jbyteArray dexBytes,
297
+ jstring className, jstring methodName,
298
+ jstring methodSignature) {
299
+ auto data = jbyteArray_to_vector(env, dexBytes);
300
+ std::string class_name = jstring_to_string(env, className);
301
+ std::string method_name = jstring_to_string(env, methodName);
302
+ std::string method_sig = jstring_to_string(env, methodSignature);
303
+
304
+ dex::DexParser parser;
305
+ if (!parser.parse(data)) {
306
+ json error = {{"error", "Failed to parse DEX"}};
307
+ return string_to_jstring(env, error.dump());
308
+ }
309
+
310
+ dex::CodeItem code;
311
+ if (!parser.get_method_code(class_name, method_name, code)) {
312
+ json error = {{"error", "Method not found or has no code"}};
313
+ return string_to_jstring(env, error.dump());
314
+ }
315
+
316
+ dex::SmaliDisassembler disasm;
317
+ disasm.set_strings(parser.strings());
318
+ disasm.set_types(parser.types());
319
+ disasm.set_methods(parser.get_method_signatures());
320
+ disasm.set_fields(parser.get_field_signatures());
321
+
322
+ auto insns = disasm.disassemble_method(code.insns.data(), code.insns.size());
323
+ std::string smali_code = disasm.to_smali(insns);
324
+
325
+ json result = {
326
+ {"className", class_name},
327
+ {"methodName", method_name},
328
+ {"registers", code.registers_size},
329
+ {"smali", smali_code}
330
+ };
331
+
332
+ return string_to_jstring(env, result.dump());
333
+ }
334
+
335
+ // ==================== Smali 转 Java ====================
336
+
337
+ JNIEXPORT jstring JNICALL
338
+ Java_com_aetherlink_dexeditor_CppDex_smaliToJava(JNIEnv* env, jclass, jbyteArray dexBytes,
339
+ jstring className) {
340
+ auto data = jbyteArray_to_vector(env, dexBytes);
341
+ std::string class_name = jstring_to_string(env, className);
342
+
343
+ dex::DexParser parser;
344
+ if (!parser.parse(data)) {
345
+ json error = {{"error", "Failed to parse DEX"}};
346
+ return string_to_jstring(env, error.dump());
347
+ }
348
+
349
+ // 先获取类的 Smali 代码
350
+ dex::SmaliDisassembler disasm;
351
+ disasm.set_strings(parser.strings());
352
+ disasm.set_types(parser.types());
353
+ disasm.set_methods(parser.get_method_signatures());
354
+ disasm.set_fields(parser.get_field_signatures());
355
+
356
+ std::stringstream smali;
357
+ bool found = false;
358
+
359
+ for (const auto& cls : parser.classes()) {
360
+ if (parser.get_class_name(cls.class_idx) == class_name) {
361
+ found = true;
362
+ smali << ".class public " << class_name << "\n";
363
+ smali << ".super Ljava/lang/Object;\n\n";
364
+
365
+ auto methods = parser.get_methods();
366
+ for (const auto& m : methods) {
367
+ if (m.class_name == class_name) {
368
+ dex::CodeItem code;
369
+ if (parser.get_method_code(class_name, m.method_name, code)) {
370
+ auto insns = disasm.disassemble_method(code.insns.data(), code.insns.size());
371
+ smali << ".method public " << m.method_name << m.prototype << "\n";
372
+ smali << " .registers " << code.registers_size << "\n";
373
+ smali << disasm.to_smali(insns);
374
+ smali << ".end method\n\n";
375
+ }
376
+ }
377
+ }
378
+ break;
379
+ }
380
+ }
381
+
382
+ if (!found) {
383
+ json error = {{"error", "Class not found: " + class_name}};
384
+ return string_to_jstring(env, error.dump());
385
+ }
386
+
387
+ // 转换为 Java 伪代码
388
+ dex::SmaliToJava converter;
389
+ std::string java_code = converter.convert(smali.str());
390
+
391
+ if (java_code.empty()) {
392
+ json error = {{"error", "Failed to convert class: " + class_name}};
393
+ return string_to_jstring(env, error.dump());
394
+ }
395
+
396
+ json result = {
397
+ {"className", class_name},
398
+ {"java", java_code}
399
+ };
400
+
401
+ return string_to_jstring(env, result.dump());
402
+ }
403
+
404
+ // ==================== DEX 修改操作 ====================
405
+
406
+ JNIEXPORT jbyteArray JNICALL
407
+ Java_com_aetherlink_dexeditor_CppDex_modifyClass(JNIEnv* env, jclass, jbyteArray dexBytes,
408
+ jstring className, jstring newSmali) {
409
+ auto data = jbyteArray_to_vector(env, dexBytes);
410
+ std::string class_name = jstring_to_string(env, className);
411
+ std::string smali_code = jstring_to_string(env, newSmali);
412
+
413
+ dex::DexBuilder builder;
414
+ if (!builder.load(data)) {
415
+ LOGE("Failed to load DEX for modification");
416
+ return nullptr;
417
+ }
418
+
419
+ // TODO: 实现类修改逻辑
420
+ // 这需要解析 smali_code 并修改 builder
421
+
422
+ auto result = builder.build();
423
+ if (result.empty()) {
424
+ LOGE("Failed to build modified DEX");
425
+ return nullptr;
426
+ }
427
+
428
+ return vector_to_jbyteArray(env, result);
429
+ }
430
+
431
+ JNIEXPORT jbyteArray JNICALL
432
+ Java_com_aetherlink_dexeditor_CppDex_addClass(JNIEnv* env, jclass, jbyteArray dexBytes,
433
+ jstring newSmali) {
434
+ auto data = jbyteArray_to_vector(env, dexBytes);
435
+ std::string smali_code = jstring_to_string(env, newSmali);
436
+
437
+ dex::DexBuilder builder;
438
+ if (!builder.load(data)) {
439
+ LOGE("Failed to load DEX");
440
+ return nullptr;
441
+ }
442
+
443
+ // TODO: 解析 smali_code 并添加类
444
+
445
+ auto result = builder.build();
446
+ if (result.empty()) {
447
+ return nullptr;
448
+ }
449
+
450
+ return vector_to_jbyteArray(env, result);
451
+ }
452
+
453
+ JNIEXPORT jbyteArray JNICALL
454
+ Java_com_aetherlink_dexeditor_CppDex_deleteClass(JNIEnv* env, jclass, jbyteArray dexBytes,
455
+ jstring className) {
456
+ auto data = jbyteArray_to_vector(env, dexBytes);
457
+ std::string class_name = jstring_to_string(env, className);
458
+
459
+ // TODO: 实现删除类逻辑
460
+
461
+ return nullptr;
462
+ }
463
+
464
+ // ==================== 方法级操作 ====================
465
+
466
+ JNIEXPORT jstring JNICALL
467
+ Java_com_aetherlink_dexeditor_CppDex_listMethods(JNIEnv* env, jclass, jbyteArray dexBytes,
468
+ jstring className) {
469
+ auto data = jbyteArray_to_vector(env, dexBytes);
470
+ std::string class_name = jstring_to_string(env, className);
471
+
472
+ dex::DexParser parser;
473
+ if (!parser.parse(data)) {
474
+ json error = {{"error", "Failed to parse DEX"}};
475
+ return string_to_jstring(env, error.dump());
476
+ }
477
+
478
+ json method_list = json::array();
479
+ auto methods = parser.get_methods();
480
+
481
+ for (const auto& m : methods) {
482
+ if (m.class_name == class_name) {
483
+ method_list.push_back({
484
+ {"name", m.method_name},
485
+ {"prototype", m.prototype},
486
+ {"accessFlags", m.access_flags}
487
+ });
488
+ }
489
+ }
490
+
491
+ json result = {
492
+ {"className", class_name},
493
+ {"methods", method_list},
494
+ {"count", method_list.size()}
495
+ };
496
+
497
+ return string_to_jstring(env, result.dump());
498
+ }
499
+
500
+ JNIEXPORT jstring JNICALL
501
+ Java_com_aetherlink_dexeditor_CppDex_listFields(JNIEnv* env, jclass, jbyteArray dexBytes,
502
+ jstring className) {
503
+ auto data = jbyteArray_to_vector(env, dexBytes);
504
+ std::string class_name = jstring_to_string(env, className);
505
+
506
+ dex::DexParser parser;
507
+ if (!parser.parse(data)) {
508
+ json error = {{"error", "Failed to parse DEX"}};
509
+ return string_to_jstring(env, error.dump());
510
+ }
511
+
512
+ json field_list = json::array();
513
+ auto fields = parser.get_fields();
514
+
515
+ for (const auto& f : fields) {
516
+ if (f.class_name == class_name) {
517
+ field_list.push_back({
518
+ {"name", f.field_name},
519
+ {"type", f.type_name},
520
+ {"accessFlags", f.access_flags}
521
+ });
522
+ }
523
+ }
524
+
525
+ json result = {
526
+ {"className", class_name},
527
+ {"fields", field_list},
528
+ {"count", field_list.size()}
529
+ };
530
+
531
+ return string_to_jstring(env, result.dump());
532
+ }
533
+
534
+ // ==================== 字符串操作 ====================
535
+
536
+ JNIEXPORT jstring JNICALL
537
+ Java_com_aetherlink_dexeditor_CppDex_listStrings(JNIEnv* env, jclass, jbyteArray dexBytes,
538
+ jstring filter, jint limit) {
539
+ auto data = jbyteArray_to_vector(env, dexBytes);
540
+ std::string filter_str = jstring_to_string(env, filter);
541
+
542
+ dex::DexParser parser;
543
+ if (!parser.parse(data)) {
544
+ json error = {{"error", "Failed to parse DEX"}};
545
+ return string_to_jstring(env, error.dump());
546
+ }
547
+
548
+ json string_list = json::array();
549
+ const auto& strings = parser.strings();
550
+ int count = 0;
551
+ int matched = 0;
552
+
553
+ for (const auto& s : strings) {
554
+ if (!filter_str.empty() && s.find(filter_str) == std::string::npos) {
555
+ continue;
556
+ }
557
+ matched++;
558
+ if (count < limit) {
559
+ string_list.push_back(s);
560
+ count++;
561
+ }
562
+ }
563
+
564
+ json result = {
565
+ {"strings", string_list},
566
+ {"shown", string_list.size()},
567
+ {"matched", matched},
568
+ {"total", strings.size()}
569
+ };
570
+
571
+ return string_to_jstring(env, result.dump());
572
+ }
573
+
574
+ // ==================== 交叉引用分析 ====================
575
+
576
+ JNIEXPORT jstring JNICALL
577
+ Java_com_aetherlink_dexeditor_CppDex_findMethodXrefs(JNIEnv* env, jclass, jbyteArray dexBytes,
578
+ jstring className, jstring methodName) {
579
+ auto data = jbyteArray_to_vector(env, dexBytes);
580
+ std::string class_name = jstring_to_string(env, className);
581
+ std::string method_name = jstring_to_string(env, methodName);
582
+
583
+ dex::DexParser parser;
584
+ if (!parser.parse(data)) {
585
+ json error = {{"error", "Failed to parse DEX"}};
586
+ return string_to_jstring(env, error.dump());
587
+ }
588
+
589
+ auto xrefs = parser.find_method_xrefs(class_name, method_name);
590
+
591
+ json xref_list = json::array();
592
+ for (const auto& xref : xrefs) {
593
+ xref_list.push_back({
594
+ {"callerClass", xref.caller_class},
595
+ {"callerMethod", xref.caller_method},
596
+ {"offset", xref.offset}
597
+ });
598
+ }
599
+
600
+ json result = {
601
+ {"className", class_name},
602
+ {"methodName", method_name},
603
+ {"xrefs", xref_list},
604
+ {"count", xref_list.size()}
605
+ };
606
+
607
+ return string_to_jstring(env, result.dump());
608
+ }
609
+
610
+ JNIEXPORT jstring JNICALL
611
+ Java_com_aetherlink_dexeditor_CppDex_findFieldXrefs(JNIEnv* env, jclass, jbyteArray dexBytes,
612
+ jstring className, jstring fieldName) {
613
+ auto data = jbyteArray_to_vector(env, dexBytes);
614
+ std::string class_name = jstring_to_string(env, className);
615
+ std::string field_name = jstring_to_string(env, fieldName);
616
+
617
+ dex::DexParser parser;
618
+ if (!parser.parse(data)) {
619
+ json error = {{"error", "Failed to parse DEX"}};
620
+ return string_to_jstring(env, error.dump());
621
+ }
622
+
623
+ auto xrefs = parser.find_field_xrefs(class_name, field_name);
624
+
625
+ json xref_list = json::array();
626
+ for (const auto& xref : xrefs) {
627
+ xref_list.push_back({
628
+ {"callerClass", xref.caller_class},
629
+ {"callerMethod", xref.caller_method},
630
+ {"offset", xref.offset}
631
+ });
632
+ }
633
+
634
+ json result = {
635
+ {"className", class_name},
636
+ {"fieldName", field_name},
637
+ {"xrefs", xref_list},
638
+ {"count", xref_list.size()}
639
+ };
640
+
641
+ return string_to_jstring(env, result.dump());
642
+ }
643
+
644
+ // ==================== Smali 编译 ====================
645
+
646
+ JNIEXPORT jbyteArray JNICALL
647
+ Java_com_aetherlink_dexeditor_CppDex_smaliToDex(JNIEnv* env, jclass, jstring smaliCode) {
648
+ std::string smali = jstring_to_string(env, smaliCode);
649
+
650
+ // 使用 DexBuilder 创建 DEX
651
+ dex::DexBuilder builder;
652
+
653
+ // TODO: 解析 smali 代码并构建 DEX
654
+ // 这需要完整的 Smali 解析器实现
655
+
656
+ auto result = builder.build();
657
+ if (result.empty()) {
658
+ LOGE("Failed to build DEX from Smali");
659
+ return nullptr;
660
+ }
661
+
662
+ return vector_to_jbyteArray(env, result);
663
+ }
664
+
665
+ // ==================== AXML 解析 ====================
666
+
667
+ JNIEXPORT jstring JNICALL
668
+ Java_com_aetherlink_dexeditor_CppDex_parseAxml(JNIEnv* env, jclass, jbyteArray axmlBytes) {
669
+ auto data = jbyteArray_to_vector(env, axmlBytes);
670
+
671
+ axml::AxmlParser parser;
672
+ if (!parser.parse(data)) {
673
+ json error = {{"error", "Failed to parse AXML"}};
674
+ return string_to_jstring(env, error.dump());
675
+ }
676
+
677
+ json result = {
678
+ {"packageName", parser.get_package_name()},
679
+ {"versionName", parser.get_version_name()},
680
+ {"versionCode", parser.get_version_code()},
681
+ {"minSdk", parser.get_min_sdk()},
682
+ {"targetSdk", parser.get_target_sdk()},
683
+ {"permissions", parser.get_permissions()},
684
+ {"activities", parser.get_activities()},
685
+ {"services", parser.get_services()},
686
+ {"xml", parser.to_xml()}
687
+ };
688
+
689
+ return string_to_jstring(env, result.dump());
690
+ }
691
+
692
+ JNIEXPORT jbyteArray JNICALL
693
+ Java_com_aetherlink_dexeditor_CppDex_editManifest(JNIEnv* env, jclass, jbyteArray axmlBytes,
694
+ jstring action, jstring value) {
695
+ auto data = jbyteArray_to_vector(env, axmlBytes);
696
+ std::string action_str = jstring_to_string(env, action);
697
+ std::string value_str = jstring_to_string(env, value);
698
+
699
+ axml::AxmlEditor editor;
700
+ if (!editor.load(data)) {
701
+ LOGE("Failed to load AXML for editing");
702
+ return nullptr;
703
+ }
704
+
705
+ bool success = false;
706
+ if (action_str == "set_package") {
707
+ success = editor.set_package_name(value_str);
708
+ } else if (action_str == "set_version_name") {
709
+ success = editor.set_version_name(value_str);
710
+ } else if (action_str == "set_version_code") {
711
+ success = editor.set_version_code(std::stoi(value_str));
712
+ } else if (action_str == "set_min_sdk") {
713
+ success = editor.set_min_sdk(std::stoi(value_str));
714
+ } else if (action_str == "set_target_sdk") {
715
+ success = editor.set_target_sdk(std::stoi(value_str));
716
+ } else {
717
+ LOGE("Unknown action: %s", action_str.c_str());
718
+ return nullptr;
719
+ }
720
+
721
+ if (!success) {
722
+ LOGE("Failed to execute action: %s", action_str.c_str());
723
+ return nullptr;
724
+ }
725
+
726
+ auto result = editor.save();
727
+ if (result.empty()) {
728
+ LOGE("Failed to save modified AXML");
729
+ return nullptr;
730
+ }
731
+
732
+ return vector_to_jbyteArray(env, result);
733
+ }
734
+
735
+ JNIEXPORT jstring JNICALL
736
+ Java_com_aetherlink_dexeditor_CppDex_searchXml(JNIEnv* env, jclass, jbyteArray axmlBytes,
737
+ jstring attrName, jstring value, jint limit) {
738
+ auto data = jbyteArray_to_vector(env, axmlBytes);
739
+ std::string attr_name = jstring_to_string(env, attrName);
740
+ std::string value_str = jstring_to_string(env, value);
741
+
742
+ axml::AxmlEditor editor;
743
+ if (!editor.load(data)) {
744
+ json error = {{"error", "Failed to load AXML"}};
745
+ return string_to_jstring(env, error.dump());
746
+ }
747
+
748
+ std::vector<axml::SearchResult> results;
749
+ if (!attr_name.empty()) {
750
+ results = editor.search_by_attribute(attr_name, value_str);
751
+ } else if (!value_str.empty()) {
752
+ results = editor.search_by_value(value_str);
753
+ }
754
+
755
+ json result_list = json::array();
756
+ int count = 0;
757
+ for (const auto& r : results) {
758
+ if (count >= limit) break;
759
+ result_list.push_back({
760
+ {"elementPath", r.element_path},
761
+ {"elementName", r.element_name},
762
+ {"attributeName", r.attribute_name},
763
+ {"attributeValue", r.attribute_value},
764
+ {"elementIndex", r.element_index}
765
+ });
766
+ count++;
767
+ }
768
+
769
+ json result = {
770
+ {"results", result_list},
771
+ {"count", result_list.size()}
772
+ };
773
+
774
+ return string_to_jstring(env, result.dump());
775
+ }
776
+
777
+ // ==================== ARSC 解析 ====================
778
+
779
+ JNIEXPORT jstring JNICALL
780
+ Java_com_aetherlink_dexeditor_CppDex_parseArsc(JNIEnv* env, jclass, jbyteArray arscBytes) {
781
+ auto data = jbyteArray_to_vector(env, arscBytes);
782
+
783
+ arsc::ArscParser parser;
784
+ if (!parser.parse(data)) {
785
+ json error = {{"error", "Failed to parse ARSC"}};
786
+ return string_to_jstring(env, error.dump());
787
+ }
788
+
789
+ json result = {
790
+ {"packageName", parser.package_name()},
791
+ {"stringCount", parser.strings().size()},
792
+ {"resourceCount", parser.resources().size()},
793
+ {"info", parser.get_info()}
794
+ };
795
+
796
+ return string_to_jstring(env, result.dump());
797
+ }
798
+
799
+ JNIEXPORT jstring JNICALL
800
+ Java_com_aetherlink_dexeditor_CppDex_searchArscStrings(JNIEnv* env, jclass, jbyteArray arscBytes,
801
+ jstring pattern, jint limit) {
802
+ auto data = jbyteArray_to_vector(env, arscBytes);
803
+ std::string pattern_str = jstring_to_string(env, pattern);
804
+
805
+ arsc::ArscParser parser;
806
+ if (!parser.parse(data)) {
807
+ json error = {{"error", "Failed to parse ARSC"}};
808
+ return string_to_jstring(env, error.dump());
809
+ }
810
+
811
+ auto results = parser.search_strings(pattern_str);
812
+
813
+ json result_list = json::array();
814
+ int count = 0;
815
+ for (const auto& r : results) {
816
+ if (count >= limit) break;
817
+ result_list.push_back({
818
+ {"index", r.index},
819
+ {"value", r.value}
820
+ });
821
+ count++;
822
+ }
823
+
824
+ json result = {
825
+ {"pattern", pattern_str},
826
+ {"results", result_list},
827
+ {"count", result_list.size()}
828
+ };
829
+
830
+ return string_to_jstring(env, result.dump());
831
+ }
832
+
833
+ JNIEXPORT jstring JNICALL
834
+ Java_com_aetherlink_dexeditor_CppDex_searchArscResources(JNIEnv* env, jclass, jbyteArray arscBytes,
835
+ jstring pattern, jstring type, jint limit) {
836
+ auto data = jbyteArray_to_vector(env, arscBytes);
837
+ std::string pattern_str = jstring_to_string(env, pattern);
838
+ std::string type_str = jstring_to_string(env, type);
839
+
840
+ arsc::ArscParser parser;
841
+ if (!parser.parse(data)) {
842
+ json error = {{"error", "Failed to parse ARSC"}};
843
+ return string_to_jstring(env, error.dump());
844
+ }
845
+
846
+ auto results = parser.search_resources(pattern_str, type_str);
847
+
848
+ json result_list = json::array();
849
+ int count = 0;
850
+ for (const auto& r : results) {
851
+ if (count >= limit) break;
852
+ result_list.push_back({
853
+ {"id", r.id},
854
+ {"name", r.name},
855
+ {"type", r.type},
856
+ {"value", r.value},
857
+ {"package", r.package}
858
+ });
859
+ count++;
860
+ }
861
+
862
+ json result = {
863
+ {"pattern", pattern_str},
864
+ {"type", type_str},
865
+ {"results", result_list},
866
+ {"count", result_list.size()}
867
+ };
868
+
869
+ return string_to_jstring(env, result.dump());
870
+ }
871
+
872
+ } // extern "C"