capacitor-dex-editor 0.0.69 → 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 -203
  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,390 @@
1
+ #include "arsc/arsc_parser.h"
2
+ #include <fstream>
3
+ #include <algorithm>
4
+ #include <cstring>
5
+ #include <sstream>
6
+
7
+ namespace arsc {
8
+
9
+ // Chunk types
10
+ static const uint16_t RES_NULL_TYPE = 0x0000;
11
+ static const uint16_t RES_STRING_POOL_TYPE = 0x0001;
12
+ static const uint16_t RES_TABLE_TYPE = 0x0002;
13
+ static const uint16_t RES_TABLE_PACKAGE_TYPE = 0x0200;
14
+ static const uint16_t RES_TABLE_TYPE_TYPE = 0x0201;
15
+ static const uint16_t RES_TABLE_TYPE_SPEC_TYPE = 0x0202;
16
+
17
+ // String pool flags
18
+ static const uint32_t SORTED_FLAG = 1 << 0;
19
+ static const uint32_t UTF8_FLAG = 1 << 8;
20
+
21
+ bool ArscParser::parse(const std::string& path) {
22
+ std::ifstream file(path, std::ios::binary | std::ios::ate);
23
+ if (!file) return false;
24
+
25
+ auto size = file.tellg();
26
+ if (size <= 0) return false;
27
+
28
+ std::vector<uint8_t> data(static_cast<size_t>(size));
29
+ file.seekg(0);
30
+ file.read(reinterpret_cast<char*>(data.data()), size);
31
+
32
+ return parse(data);
33
+ }
34
+
35
+ bool ArscParser::parse(const std::vector<uint8_t>& data) {
36
+ if (data.size() < 12) return false;
37
+
38
+ data_ = data;
39
+ strings_.clear();
40
+ resources_.clear();
41
+ id_to_index_.clear();
42
+
43
+ // Read table header
44
+ uint16_t type = read_le<uint16_t>(0);
45
+ uint16_t header_size = read_le<uint16_t>(2);
46
+ uint32_t size = read_le<uint32_t>(4);
47
+
48
+ if (type != RES_TABLE_TYPE) return false;
49
+ if (size > data_.size()) return false;
50
+
51
+ uint32_t package_count = read_le<uint32_t>(8);
52
+
53
+ size_t offset = header_size;
54
+
55
+ while (offset + 8 <= data_.size()) {
56
+ uint16_t chunk_type = read_le<uint16_t>(offset);
57
+ uint16_t chunk_header_size = read_le<uint16_t>(offset + 2);
58
+ uint32_t chunk_size = read_le<uint32_t>(offset + 4);
59
+
60
+ if (chunk_size < 8 || offset + chunk_size > data_.size()) break;
61
+
62
+ switch (chunk_type) {
63
+ case RES_STRING_POOL_TYPE:
64
+ parse_string_pool(offset, chunk_size);
65
+ break;
66
+ case RES_TABLE_PACKAGE_TYPE:
67
+ parse_package(offset, chunk_size);
68
+ break;
69
+ }
70
+
71
+ offset += chunk_size;
72
+ }
73
+
74
+ return true;
75
+ }
76
+
77
+ bool ArscParser::parse_string_pool(size_t offset, size_t size) {
78
+ if (offset + 28 > data_.size()) return false;
79
+
80
+ uint16_t header_size = read_le<uint16_t>(offset + 2);
81
+ uint32_t string_count = read_le<uint32_t>(offset + 8);
82
+ uint32_t style_count = read_le<uint32_t>(offset + 12);
83
+ uint32_t flags = read_le<uint32_t>(offset + 16);
84
+ uint32_t strings_start = read_le<uint32_t>(offset + 20);
85
+
86
+ bool is_utf8 = (flags & UTF8_FLAG) != 0;
87
+
88
+ size_t string_offsets_start = offset + header_size;
89
+ size_t strings_data_start = offset + strings_start;
90
+
91
+ for (uint32_t i = 0; i < string_count; i++) {
92
+ if (string_offsets_start + i * 4 + 4 > data_.size()) break;
93
+
94
+ uint32_t str_offset = read_le<uint32_t>(string_offsets_start + i * 4);
95
+ size_t abs_offset = strings_data_start + str_offset;
96
+
97
+ if (abs_offset >= data_.size()) {
98
+ strings_.push_back("");
99
+ continue;
100
+ }
101
+
102
+ std::string str = read_string_at(abs_offset, is_utf8);
103
+ strings_.push_back(str);
104
+ }
105
+
106
+ return true;
107
+ }
108
+
109
+ std::string ArscParser::read_string_at(size_t offset, bool utf8) const {
110
+ if (offset >= data_.size()) return "";
111
+
112
+ if (utf8) {
113
+ // UTF-8 format: charLen (1-2 bytes), byteLen (1-2 bytes), data
114
+ uint8_t char_len = data_[offset];
115
+ offset++;
116
+ if (char_len & 0x80) {
117
+ offset++; // Skip high byte
118
+ }
119
+
120
+ if (offset >= data_.size()) return "";
121
+
122
+ uint8_t byte_len = data_[offset];
123
+ offset++;
124
+ if (byte_len & 0x80) {
125
+ byte_len = ((byte_len & 0x7F) << 8) | data_[offset];
126
+ offset++;
127
+ }
128
+
129
+ if (offset + byte_len > data_.size()) return "";
130
+
131
+ return std::string(reinterpret_cast<const char*>(&data_[offset]), byte_len);
132
+ } else {
133
+ // UTF-16 format: len (2 bytes), data
134
+ if (offset + 2 > data_.size()) return "";
135
+
136
+ uint16_t len = read_le<uint16_t>(offset);
137
+ offset += 2;
138
+
139
+ if (len & 0x8000) {
140
+ len = ((len & 0x7FFF) << 16) | read_le<uint16_t>(offset);
141
+ offset += 2;
142
+ }
143
+
144
+ std::string result;
145
+ for (uint16_t i = 0; i < len && offset + 2 <= data_.size(); i++) {
146
+ uint16_t ch = read_le<uint16_t>(offset);
147
+ offset += 2;
148
+ if (ch == 0) break;
149
+ if (ch < 0x80) {
150
+ result += static_cast<char>(ch);
151
+ } else if (ch < 0x800) {
152
+ result += static_cast<char>(0xC0 | (ch >> 6));
153
+ result += static_cast<char>(0x80 | (ch & 0x3F));
154
+ } else {
155
+ result += static_cast<char>(0xE0 | (ch >> 12));
156
+ result += static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
157
+ result += static_cast<char>(0x80 | (ch & 0x3F));
158
+ }
159
+ }
160
+ return result;
161
+ }
162
+ }
163
+
164
+ bool ArscParser::parse_package(size_t offset, size_t size) {
165
+ if (offset + 288 > data_.size()) return false;
166
+
167
+ uint16_t header_size = read_le<uint16_t>(offset + 2);
168
+ package_id_ = read_le<uint32_t>(offset + 8);
169
+
170
+ // Read package name (128 chars, UTF-16)
171
+ std::string pkg_name;
172
+ for (int i = 0; i < 128; i++) {
173
+ uint16_t ch = read_le<uint16_t>(offset + 12 + i * 2);
174
+ if (ch == 0) break;
175
+ if (ch < 128) pkg_name += static_cast<char>(ch);
176
+ }
177
+ package_name_ = pkg_name;
178
+
179
+ uint32_t type_strings_offset = read_le<uint32_t>(offset + 268);
180
+ uint32_t key_strings_offset = read_le<uint32_t>(offset + 276);
181
+
182
+ // Parse type and key string pools
183
+ std::vector<std::string> type_strings;
184
+ std::vector<std::string> key_strings;
185
+
186
+ size_t pkg_start = offset;
187
+
188
+ // Parse chunks within package
189
+ size_t chunk_offset = offset + header_size;
190
+ std::string current_type;
191
+
192
+ while (chunk_offset + 8 <= offset + size) {
193
+ uint16_t chunk_type = read_le<uint16_t>(chunk_offset);
194
+ uint16_t chunk_header_size = read_le<uint16_t>(chunk_offset + 2);
195
+ uint32_t chunk_size = read_le<uint32_t>(chunk_offset + 4);
196
+
197
+ if (chunk_size < 8 || chunk_offset + chunk_size > offset + size) break;
198
+
199
+ switch (chunk_type) {
200
+ case RES_STRING_POOL_TYPE: {
201
+ // Parse as type or key strings based on position
202
+ size_t rel_offset = chunk_offset - pkg_start;
203
+ std::vector<std::string> pool_strings;
204
+
205
+ uint32_t str_count = read_le<uint32_t>(chunk_offset + 8);
206
+ uint32_t flags = read_le<uint32_t>(chunk_offset + 16);
207
+ uint32_t str_start = read_le<uint32_t>(chunk_offset + 20);
208
+ bool is_utf8 = (flags & UTF8_FLAG) != 0;
209
+
210
+ size_t offsets_start = chunk_offset + chunk_header_size;
211
+ size_t data_start = chunk_offset + str_start;
212
+
213
+ for (uint32_t i = 0; i < str_count; i++) {
214
+ if (offsets_start + i * 4 + 4 > data_.size()) break;
215
+ uint32_t str_off = read_le<uint32_t>(offsets_start + i * 4);
216
+ std::string s = read_string_at(data_start + str_off, is_utf8);
217
+ pool_strings.push_back(s);
218
+ }
219
+
220
+ if (rel_offset == type_strings_offset) {
221
+ type_strings = pool_strings;
222
+ } else if (rel_offset == key_strings_offset) {
223
+ key_strings = pool_strings;
224
+ }
225
+ break;
226
+ }
227
+ case RES_TABLE_TYPE_SPEC_TYPE: {
228
+ uint8_t type_id = data_[chunk_offset + 8];
229
+ if (type_id > 0 && type_id <= type_strings.size()) {
230
+ current_type = type_strings[type_id - 1];
231
+ }
232
+ break;
233
+ }
234
+ case RES_TABLE_TYPE_TYPE: {
235
+ uint8_t type_id = data_[chunk_offset + 8];
236
+ uint32_t entry_count = read_le<uint32_t>(chunk_offset + 12);
237
+ uint32_t entries_start = read_le<uint32_t>(chunk_offset + 16);
238
+
239
+ std::string type_name;
240
+ if (type_id > 0 && type_id <= type_strings.size()) {
241
+ type_name = type_strings[type_id - 1];
242
+ }
243
+
244
+ size_t offsets_start = chunk_offset + chunk_header_size;
245
+ size_t entries_data = chunk_offset + entries_start;
246
+
247
+ for (uint32_t i = 0; i < entry_count; i++) {
248
+ if (offsets_start + i * 4 + 4 > data_.size()) break;
249
+
250
+ uint32_t entry_offset = read_le<uint32_t>(offsets_start + i * 4);
251
+ if (entry_offset == 0xFFFFFFFF) continue;
252
+
253
+ size_t entry_pos = entries_data + entry_offset;
254
+ if (entry_pos + 8 > data_.size()) continue;
255
+
256
+ uint16_t entry_size = read_le<uint16_t>(entry_pos);
257
+ uint16_t entry_flags = read_le<uint16_t>(entry_pos + 2);
258
+ uint32_t key_index = read_le<uint32_t>(entry_pos + 4);
259
+
260
+ ResourceEntry res;
261
+ res.id = (package_id_ << 24) | (type_id << 16) | i;
262
+ res.type = type_name;
263
+ res.package = package_name_;
264
+
265
+ if (key_index < key_strings.size()) {
266
+ res.name = key_strings[key_index];
267
+ }
268
+
269
+ // Read value if simple entry
270
+ if (!(entry_flags & 0x0001) && entry_pos + entry_size + 8 <= data_.size()) {
271
+ size_t value_pos = entry_pos + 8;
272
+ uint8_t value_type = data_[value_pos + 3];
273
+ uint32_t value_data = read_le<uint32_t>(value_pos + 4);
274
+
275
+ switch (value_type) {
276
+ case 0x03: // String
277
+ if (value_data < strings_.size()) {
278
+ res.value = strings_[value_data];
279
+ }
280
+ break;
281
+ case 0x10: // Int dec
282
+ res.value = std::to_string(static_cast<int32_t>(value_data));
283
+ break;
284
+ case 0x11: // Int hex
285
+ res.value = "0x" + ([](uint32_t v) {
286
+ char buf[16];
287
+ snprintf(buf, sizeof(buf), "%08X", v);
288
+ return std::string(buf);
289
+ })(value_data);
290
+ break;
291
+ case 0x12: // Boolean
292
+ res.value = value_data ? "true" : "false";
293
+ break;
294
+ case 0x1C: // Color
295
+ case 0x1D:
296
+ case 0x1E:
297
+ case 0x1F:
298
+ res.value = "#" + ([](uint32_t v) {
299
+ char buf[16];
300
+ snprintf(buf, sizeof(buf), "%08X", v);
301
+ return std::string(buf);
302
+ })(value_data);
303
+ break;
304
+ }
305
+ }
306
+
307
+ id_to_index_[res.id] = resources_.size();
308
+ resources_.push_back(res);
309
+ }
310
+ break;
311
+ }
312
+ }
313
+
314
+ chunk_offset += chunk_size;
315
+ }
316
+
317
+ return true;
318
+ }
319
+
320
+ std::vector<StringResource> ArscParser::search_strings(const std::string& pattern) const {
321
+ std::vector<StringResource> results;
322
+ std::string lower_pattern = pattern;
323
+ std::transform(lower_pattern.begin(), lower_pattern.end(), lower_pattern.begin(), ::tolower);
324
+
325
+ for (size_t i = 0; i < strings_.size(); i++) {
326
+ std::string lower_str = strings_[i];
327
+ std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), ::tolower);
328
+
329
+ if (lower_str.find(lower_pattern) != std::string::npos) {
330
+ results.push_back({static_cast<uint32_t>(i), strings_[i]});
331
+ }
332
+ }
333
+
334
+ return results;
335
+ }
336
+
337
+ std::vector<ResourceEntry> ArscParser::search_resources(const std::string& pattern,
338
+ const std::string& type) const {
339
+ std::vector<ResourceEntry> results;
340
+ std::string lower_pattern = pattern;
341
+ std::transform(lower_pattern.begin(), lower_pattern.end(), lower_pattern.begin(), ::tolower);
342
+
343
+ for (const auto& res : resources_) {
344
+ if (!type.empty() && res.type != type) continue;
345
+
346
+ std::string lower_name = res.name;
347
+ std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
348
+
349
+ std::string lower_value = res.value;
350
+ std::transform(lower_value.begin(), lower_value.end(), lower_value.begin(), ::tolower);
351
+
352
+ if (lower_name.find(lower_pattern) != std::string::npos ||
353
+ lower_value.find(lower_pattern) != std::string::npos) {
354
+ results.push_back(res);
355
+ }
356
+ }
357
+
358
+ return results;
359
+ }
360
+
361
+ const ResourceEntry* ArscParser::get_resource(uint32_t id) const {
362
+ auto it = id_to_index_.find(id);
363
+ if (it != id_to_index_.end() && it->second < resources_.size()) {
364
+ return &resources_[it->second];
365
+ }
366
+ return nullptr;
367
+ }
368
+
369
+ std::string ArscParser::get_info() const {
370
+ std::ostringstream oss;
371
+ oss << "Package: " << package_name_ << "\n";
372
+ oss << "Package ID: 0x" << std::hex << package_id_ << std::dec << "\n";
373
+ oss << "String pool size: " << strings_.size() << "\n";
374
+ oss << "Resource count: " << resources_.size() << "\n";
375
+
376
+ // Count by type
377
+ std::unordered_map<std::string, int> type_counts;
378
+ for (const auto& res : resources_) {
379
+ type_counts[res.type]++;
380
+ }
381
+
382
+ oss << "\nResources by type:\n";
383
+ for (const auto& [type, count] : type_counts) {
384
+ oss << " " << type << ": " << count << "\n";
385
+ }
386
+
387
+ return oss.str();
388
+ }
389
+
390
+ } // namespace arsc