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.
- package/android/build.gradle +22 -0
- package/android/src/main/cpp/CMakeLists.txt +57 -0
- package/android/src/main/cpp/apk/apk_handler.cpp +121 -0
- package/android/src/main/cpp/apk/zip_utils.cpp +425 -0
- package/android/src/main/cpp/arsc/arsc_parser.cpp +390 -0
- package/android/src/main/cpp/dex/dex_builder.cpp +752 -0
- package/android/src/main/cpp/dex/dex_parser.cpp +620 -0
- package/android/src/main/cpp/dex/smali_disasm.cpp +1223 -0
- package/android/src/main/cpp/dex/smali_to_java.cpp +576 -0
- package/android/src/main/cpp/include/apk/apk_handler.h +41 -0
- package/android/src/main/cpp/include/apk/zip_utils.h +57 -0
- package/android/src/main/cpp/include/arsc/arsc_parser.h +98 -0
- package/android/src/main/cpp/include/dex/dex_builder.h +189 -0
- package/android/src/main/cpp/include/dex/dex_parser.h +137 -0
- package/android/src/main/cpp/include/dex/smali_disasm.h +127 -0
- package/android/src/main/cpp/include/dex/smali_to_java.h +50 -0
- package/android/src/main/cpp/include/xml/android_resources.h +495 -0
- package/android/src/main/cpp/include/xml/axml_parser.h +147 -0
- package/android/src/main/cpp/jni_bridge.cpp +872 -0
- package/android/src/main/cpp/third_party/miniz.c +646 -0
- package/android/src/main/cpp/third_party/miniz.h +605 -0
- package/android/src/main/cpp/third_party/miniz_common.h +97 -0
- package/android/src/main/cpp/third_party/miniz_export.h +6 -0
- package/android/src/main/cpp/third_party/miniz_tdef.c +1597 -0
- package/android/src/main/cpp/third_party/miniz_tdef.h +199 -0
- package/android/src/main/cpp/third_party/miniz_tinfl.c +770 -0
- package/android/src/main/cpp/third_party/miniz_tinfl.h +150 -0
- package/android/src/main/cpp/third_party/miniz_zip.c +4895 -0
- package/android/src/main/cpp/third_party/miniz_zip.h +454 -0
- package/android/src/main/cpp/third_party/nlohmann_json/CMakeLists.txt +0 -0
- package/android/src/main/cpp/third_party/nlohmann_json/single_include/nlohmann/json.hpp +24765 -0
- package/android/src/main/cpp/xml/axml_parser.cpp +1701 -0
- package/android/src/main/java/com/aetherlink/dexeditor/CppDex.java +295 -0
- package/android/src/main/java/com/aetherlink/dexeditor/DexManager.java +20 -20
- package/package.json +1 -1
- package/android/src/main/java/com/aetherlink/dexeditor/RustDex.java +0 -203
- package/android/src/main/jniLibs/arm64-v8a/libdex_rust.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libdex_rust.so +0 -0
- package/android/src/main/jniLibs/x86/libdex_rust.so +0 -0
- package/android/src/main/jniLibs/x86_64/libdex_rust.so +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <unordered_map>
|
|
7
|
+
|
|
8
|
+
namespace arsc {
|
|
9
|
+
|
|
10
|
+
// Resource types
|
|
11
|
+
enum class ResourceType : uint16_t {
|
|
12
|
+
NULL_TYPE = 0x00,
|
|
13
|
+
STRING_POOL = 0x01,
|
|
14
|
+
TABLE = 0x02,
|
|
15
|
+
XML = 0x03,
|
|
16
|
+
TABLE_PACKAGE = 0x0200,
|
|
17
|
+
TABLE_TYPE = 0x0201,
|
|
18
|
+
TABLE_TYPE_SPEC = 0x0202,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
struct StringPoolHeader {
|
|
22
|
+
uint32_t string_count;
|
|
23
|
+
uint32_t style_count;
|
|
24
|
+
uint32_t flags;
|
|
25
|
+
uint32_t strings_start;
|
|
26
|
+
uint32_t styles_start;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
struct ResourceEntry {
|
|
30
|
+
uint32_t id; // Full resource ID (0xPPTTEEEE)
|
|
31
|
+
std::string name; // Resource name
|
|
32
|
+
std::string type; // Type name (string, drawable, etc.)
|
|
33
|
+
std::string value; // Value (for simple types)
|
|
34
|
+
std::string package; // Package name
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
struct StringResource {
|
|
38
|
+
uint32_t index;
|
|
39
|
+
std::string value;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
class ArscParser {
|
|
43
|
+
public:
|
|
44
|
+
ArscParser() = default;
|
|
45
|
+
~ArscParser() = default;
|
|
46
|
+
|
|
47
|
+
bool parse(const std::vector<uint8_t>& data);
|
|
48
|
+
bool parse(const std::string& path);
|
|
49
|
+
|
|
50
|
+
// Get all strings from string pool
|
|
51
|
+
const std::vector<std::string>& strings() const { return strings_; }
|
|
52
|
+
|
|
53
|
+
// Get all resources
|
|
54
|
+
const std::vector<ResourceEntry>& resources() const { return resources_; }
|
|
55
|
+
|
|
56
|
+
// Get package name
|
|
57
|
+
const std::string& package_name() const { return package_name_; }
|
|
58
|
+
|
|
59
|
+
// Search strings
|
|
60
|
+
std::vector<StringResource> search_strings(const std::string& pattern) const;
|
|
61
|
+
|
|
62
|
+
// Search resources by name or type
|
|
63
|
+
std::vector<ResourceEntry> search_resources(const std::string& pattern,
|
|
64
|
+
const std::string& type = "") const;
|
|
65
|
+
|
|
66
|
+
// Get resource by ID
|
|
67
|
+
const ResourceEntry* get_resource(uint32_t id) const;
|
|
68
|
+
|
|
69
|
+
// Get summary info
|
|
70
|
+
std::string get_info() const;
|
|
71
|
+
|
|
72
|
+
private:
|
|
73
|
+
std::vector<uint8_t> data_;
|
|
74
|
+
std::vector<std::string> strings_;
|
|
75
|
+
std::vector<ResourceEntry> resources_;
|
|
76
|
+
std::string package_name_;
|
|
77
|
+
uint32_t package_id_ = 0;
|
|
78
|
+
|
|
79
|
+
std::unordered_map<uint32_t, size_t> id_to_index_;
|
|
80
|
+
|
|
81
|
+
bool parse_string_pool(size_t offset, size_t size);
|
|
82
|
+
bool parse_package(size_t offset, size_t size);
|
|
83
|
+
bool parse_type_spec(size_t offset, size_t size, const std::string& type_name);
|
|
84
|
+
bool parse_type(size_t offset, size_t size, const std::string& type_name);
|
|
85
|
+
|
|
86
|
+
std::string read_string_at(size_t offset, bool utf8) const;
|
|
87
|
+
|
|
88
|
+
template<typename T>
|
|
89
|
+
T read_le(size_t offset) const {
|
|
90
|
+
T val = 0;
|
|
91
|
+
for (size_t i = 0; i < sizeof(T); i++) {
|
|
92
|
+
val |= static_cast<T>(data_[offset + i]) << (i * 8);
|
|
93
|
+
}
|
|
94
|
+
return val;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
} // namespace arsc
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <unordered_map>
|
|
7
|
+
#include <memory>
|
|
8
|
+
#include "dex_parser.h"
|
|
9
|
+
|
|
10
|
+
namespace dex {
|
|
11
|
+
|
|
12
|
+
// Access flags
|
|
13
|
+
enum AccessFlags : uint32_t {
|
|
14
|
+
ACC_PUBLIC = 0x0001,
|
|
15
|
+
ACC_PRIVATE = 0x0002,
|
|
16
|
+
ACC_PROTECTED = 0x0004,
|
|
17
|
+
ACC_STATIC = 0x0008,
|
|
18
|
+
ACC_FINAL = 0x0010,
|
|
19
|
+
ACC_SYNCHRONIZED = 0x0020,
|
|
20
|
+
ACC_VOLATILE = 0x0040,
|
|
21
|
+
ACC_BRIDGE = 0x0040,
|
|
22
|
+
ACC_TRANSIENT = 0x0080,
|
|
23
|
+
ACC_VARARGS = 0x0080,
|
|
24
|
+
ACC_NATIVE = 0x0100,
|
|
25
|
+
ACC_INTERFACE = 0x0200,
|
|
26
|
+
ACC_ABSTRACT = 0x0400,
|
|
27
|
+
ACC_STRICT = 0x0800,
|
|
28
|
+
ACC_SYNTHETIC = 0x1000,
|
|
29
|
+
ACC_ANNOTATION = 0x2000,
|
|
30
|
+
ACC_ENUM = 0x4000,
|
|
31
|
+
ACC_CONSTRUCTOR = 0x10000,
|
|
32
|
+
ACC_DECLARED_SYNCHRONIZED = 0x20000,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Method prototype
|
|
36
|
+
struct Prototype {
|
|
37
|
+
std::string return_type;
|
|
38
|
+
std::vector<std::string> param_types;
|
|
39
|
+
|
|
40
|
+
Prototype() : return_type("V") {}
|
|
41
|
+
Prototype(const std::string& ret) : return_type(ret) {}
|
|
42
|
+
Prototype(const std::string& ret, std::initializer_list<std::string> params)
|
|
43
|
+
: return_type(ret), param_types(params) {}
|
|
44
|
+
|
|
45
|
+
std::string to_string() const;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Method definition for building
|
|
49
|
+
struct MethodDef {
|
|
50
|
+
std::string name;
|
|
51
|
+
Prototype prototype;
|
|
52
|
+
uint32_t access_flags;
|
|
53
|
+
uint16_t registers_size;
|
|
54
|
+
uint16_t ins_size;
|
|
55
|
+
uint16_t outs_size;
|
|
56
|
+
std::vector<uint8_t> code; // bytecode
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Field definition for building
|
|
60
|
+
struct FieldDef {
|
|
61
|
+
std::string name;
|
|
62
|
+
std::string type;
|
|
63
|
+
uint32_t access_flags;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Class definition for building
|
|
67
|
+
struct ClassBuilder {
|
|
68
|
+
std::string class_name;
|
|
69
|
+
std::string super_class;
|
|
70
|
+
uint32_t access_flags;
|
|
71
|
+
std::vector<std::string> interfaces;
|
|
72
|
+
std::vector<FieldDef> static_fields;
|
|
73
|
+
std::vector<FieldDef> instance_fields;
|
|
74
|
+
std::vector<MethodDef> direct_methods; // static, private, constructor
|
|
75
|
+
std::vector<MethodDef> virtual_methods; // other methods
|
|
76
|
+
|
|
77
|
+
ClassBuilder(const std::string& name)
|
|
78
|
+
: class_name(name), super_class("Ljava/lang/Object;"), access_flags(ACC_PUBLIC) {}
|
|
79
|
+
|
|
80
|
+
ClassBuilder& set_super(const std::string& s) { super_class = s; return *this; }
|
|
81
|
+
ClassBuilder& set_access(uint32_t f) { access_flags = f; return *this; }
|
|
82
|
+
ClassBuilder& add_interface(const std::string& i) { interfaces.push_back(i); return *this; }
|
|
83
|
+
|
|
84
|
+
// Add field
|
|
85
|
+
ClassBuilder& add_field(const std::string& name, const std::string& type, uint32_t flags = ACC_PRIVATE);
|
|
86
|
+
ClassBuilder& add_static_field(const std::string& name, const std::string& type, uint32_t flags = ACC_PRIVATE | ACC_STATIC);
|
|
87
|
+
|
|
88
|
+
// Add method
|
|
89
|
+
ClassBuilder& add_method(const MethodDef& method);
|
|
90
|
+
MethodDef& create_method(const std::string& name, const Prototype& proto, uint32_t flags = ACC_PUBLIC);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// DEX Builder - can build DEX from scratch or modify existing
|
|
94
|
+
class DexBuilder {
|
|
95
|
+
public:
|
|
96
|
+
DexBuilder();
|
|
97
|
+
~DexBuilder() = default;
|
|
98
|
+
|
|
99
|
+
// Load existing DEX as base (for modification)
|
|
100
|
+
bool load(const std::vector<uint8_t>& data);
|
|
101
|
+
bool load(const std::string& path);
|
|
102
|
+
|
|
103
|
+
// Create new class
|
|
104
|
+
ClassBuilder& make_class(const std::string& class_name);
|
|
105
|
+
|
|
106
|
+
// Modify existing class
|
|
107
|
+
ClassBuilder* get_class(const std::string& class_name);
|
|
108
|
+
|
|
109
|
+
// Add/modify method in existing class
|
|
110
|
+
bool add_method(const std::string& class_name, const MethodDef& method);
|
|
111
|
+
bool modify_method(const std::string& class_name, const std::string& method_name,
|
|
112
|
+
const std::string& new_prototype, const std::vector<uint8_t>& new_code);
|
|
113
|
+
|
|
114
|
+
// String/Type pool management
|
|
115
|
+
uint32_t get_or_add_string(const std::string& str);
|
|
116
|
+
uint32_t get_or_add_type(const std::string& type);
|
|
117
|
+
uint32_t get_or_add_proto(const Prototype& proto);
|
|
118
|
+
uint32_t get_or_add_field(const std::string& class_name, const std::string& field_name, const std::string& type);
|
|
119
|
+
uint32_t get_or_add_method(const std::string& class_name, const std::string& method_name, const Prototype& proto);
|
|
120
|
+
|
|
121
|
+
// Build final DEX
|
|
122
|
+
std::vector<uint8_t> build();
|
|
123
|
+
bool save(const std::string& path);
|
|
124
|
+
|
|
125
|
+
// Get info
|
|
126
|
+
const std::vector<std::string>& strings() const { return strings_; }
|
|
127
|
+
const std::vector<std::string>& types() const { return types_; }
|
|
128
|
+
|
|
129
|
+
private:
|
|
130
|
+
// String pool
|
|
131
|
+
std::vector<std::string> strings_;
|
|
132
|
+
std::unordered_map<std::string, uint32_t> string_map_;
|
|
133
|
+
|
|
134
|
+
// Type pool
|
|
135
|
+
std::vector<std::string> types_;
|
|
136
|
+
std::unordered_map<std::string, uint32_t> type_map_;
|
|
137
|
+
|
|
138
|
+
// Proto pool
|
|
139
|
+
struct ProtoId {
|
|
140
|
+
uint32_t shorty_idx;
|
|
141
|
+
uint32_t return_type_idx;
|
|
142
|
+
std::vector<uint32_t> param_type_idxs;
|
|
143
|
+
};
|
|
144
|
+
std::vector<ProtoId> protos_;
|
|
145
|
+
std::unordered_map<std::string, uint32_t> proto_map_;
|
|
146
|
+
|
|
147
|
+
// Field pool
|
|
148
|
+
struct FieldId {
|
|
149
|
+
uint16_t class_idx;
|
|
150
|
+
uint16_t type_idx;
|
|
151
|
+
uint32_t name_idx;
|
|
152
|
+
};
|
|
153
|
+
std::vector<FieldId> fields_;
|
|
154
|
+
std::unordered_map<std::string, uint32_t> field_map_;
|
|
155
|
+
|
|
156
|
+
// Method pool
|
|
157
|
+
struct MethodId {
|
|
158
|
+
uint16_t class_idx;
|
|
159
|
+
uint16_t proto_idx;
|
|
160
|
+
uint32_t name_idx;
|
|
161
|
+
};
|
|
162
|
+
std::vector<MethodId> methods_;
|
|
163
|
+
std::unordered_map<std::string, uint32_t> method_map_;
|
|
164
|
+
|
|
165
|
+
// Classes
|
|
166
|
+
std::vector<ClassBuilder> classes_;
|
|
167
|
+
std::unordered_map<std::string, size_t> class_map_;
|
|
168
|
+
|
|
169
|
+
// Original data (if loaded from existing DEX)
|
|
170
|
+
std::vector<uint8_t> original_data_;
|
|
171
|
+
bool has_original_ = false;
|
|
172
|
+
|
|
173
|
+
// Helper functions
|
|
174
|
+
void write_uleb128(std::vector<uint8_t>& out, uint32_t value);
|
|
175
|
+
void write_sleb128(std::vector<uint8_t>& out, int32_t value);
|
|
176
|
+
std::string get_shorty(const Prototype& proto) const;
|
|
177
|
+
|
|
178
|
+
// Build sections
|
|
179
|
+
std::vector<uint8_t> build_string_data();
|
|
180
|
+
std::vector<uint8_t> build_type_list(const std::vector<uint32_t>& type_idxs);
|
|
181
|
+
std::vector<uint8_t> build_class_data(const ClassBuilder& cls);
|
|
182
|
+
std::vector<uint8_t> build_code_item(const MethodDef& method);
|
|
183
|
+
|
|
184
|
+
// Checksum and signature
|
|
185
|
+
uint32_t compute_checksum(const std::vector<uint8_t>& data);
|
|
186
|
+
void compute_signature(std::vector<uint8_t>& data);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
} // namespace dex
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <unordered_map>
|
|
7
|
+
#include <map>
|
|
8
|
+
|
|
9
|
+
namespace dex {
|
|
10
|
+
|
|
11
|
+
struct DexHeader {
|
|
12
|
+
uint8_t magic[8];
|
|
13
|
+
uint32_t checksum;
|
|
14
|
+
uint8_t signature[20];
|
|
15
|
+
uint32_t file_size;
|
|
16
|
+
uint32_t header_size;
|
|
17
|
+
uint32_t endian_tag;
|
|
18
|
+
uint32_t link_size;
|
|
19
|
+
uint32_t link_off;
|
|
20
|
+
uint32_t map_off;
|
|
21
|
+
uint32_t string_ids_size;
|
|
22
|
+
uint32_t string_ids_off;
|
|
23
|
+
uint32_t type_ids_size;
|
|
24
|
+
uint32_t type_ids_off;
|
|
25
|
+
uint32_t proto_ids_size;
|
|
26
|
+
uint32_t proto_ids_off;
|
|
27
|
+
uint32_t field_ids_size;
|
|
28
|
+
uint32_t field_ids_off;
|
|
29
|
+
uint32_t method_ids_size;
|
|
30
|
+
uint32_t method_ids_off;
|
|
31
|
+
uint32_t class_defs_size;
|
|
32
|
+
uint32_t class_defs_off;
|
|
33
|
+
uint32_t data_size;
|
|
34
|
+
uint32_t data_off;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
struct ClassDef {
|
|
38
|
+
uint32_t class_idx;
|
|
39
|
+
uint32_t access_flags;
|
|
40
|
+
uint32_t superclass_idx;
|
|
41
|
+
uint32_t interfaces_off;
|
|
42
|
+
uint32_t source_file_idx;
|
|
43
|
+
uint32_t annotations_off;
|
|
44
|
+
uint32_t class_data_off;
|
|
45
|
+
uint32_t static_values_off;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
struct CodeItem {
|
|
49
|
+
uint16_t registers_size;
|
|
50
|
+
uint16_t ins_size;
|
|
51
|
+
uint16_t outs_size;
|
|
52
|
+
uint16_t tries_size;
|
|
53
|
+
uint32_t debug_info_off;
|
|
54
|
+
uint32_t insns_size; // in 16-bit code units
|
|
55
|
+
std::vector<uint8_t> insns;
|
|
56
|
+
uint32_t code_off; // offset of code_item in DEX file
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
struct MethodInfo {
|
|
60
|
+
std::string class_name;
|
|
61
|
+
std::string method_name;
|
|
62
|
+
std::string prototype;
|
|
63
|
+
uint32_t access_flags;
|
|
64
|
+
uint32_t code_off;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
struct FieldInfo {
|
|
68
|
+
std::string class_name;
|
|
69
|
+
std::string field_name;
|
|
70
|
+
std::string type_name;
|
|
71
|
+
uint32_t access_flags;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
class DexParser {
|
|
75
|
+
public:
|
|
76
|
+
DexParser() = default;
|
|
77
|
+
~DexParser() = default;
|
|
78
|
+
|
|
79
|
+
bool parse(const std::vector<uint8_t>& data);
|
|
80
|
+
bool parse(const std::string& path);
|
|
81
|
+
|
|
82
|
+
const DexHeader& header() const { return header_; }
|
|
83
|
+
const std::vector<std::string>& strings() const { return strings_; }
|
|
84
|
+
const std::vector<std::string>& types() const { return types_; }
|
|
85
|
+
const std::vector<ClassDef>& classes() const { return classes_; }
|
|
86
|
+
std::vector<MethodInfo> get_methods() const;
|
|
87
|
+
std::vector<FieldInfo> get_fields() const;
|
|
88
|
+
|
|
89
|
+
std::string get_class_name(uint32_t idx) const;
|
|
90
|
+
std::vector<std::string> get_class_methods(const std::string& class_name) const;
|
|
91
|
+
|
|
92
|
+
// Get method code for disassembly
|
|
93
|
+
bool get_method_code(const std::string& class_name, const std::string& method_name, CodeItem& code) const;
|
|
94
|
+
|
|
95
|
+
// Get all method codes at once (optimized batch operation)
|
|
96
|
+
std::unordered_map<std::string, CodeItem> get_all_method_codes() const;
|
|
97
|
+
|
|
98
|
+
// Get all method signatures for reference resolution
|
|
99
|
+
std::vector<std::string> get_method_signatures() const;
|
|
100
|
+
std::vector<std::string> get_field_signatures() const;
|
|
101
|
+
|
|
102
|
+
// Get full method signature with parameters and return type
|
|
103
|
+
std::string get_full_method_signature(uint32_t method_idx) const;
|
|
104
|
+
std::string get_proto_string(uint32_t proto_idx) const;
|
|
105
|
+
|
|
106
|
+
// Cross-reference analysis
|
|
107
|
+
struct XRef {
|
|
108
|
+
std::string caller_class;
|
|
109
|
+
std::string caller_method;
|
|
110
|
+
uint32_t offset;
|
|
111
|
+
};
|
|
112
|
+
std::vector<XRef> find_method_xrefs(const std::string& class_name, const std::string& method_name) const;
|
|
113
|
+
std::vector<XRef> find_field_xrefs(const std::string& class_name, const std::string& field_name) const;
|
|
114
|
+
|
|
115
|
+
std::string get_info() const;
|
|
116
|
+
|
|
117
|
+
const std::vector<uint8_t>& data() const { return data_; }
|
|
118
|
+
|
|
119
|
+
private:
|
|
120
|
+
DexHeader header_;
|
|
121
|
+
std::vector<uint8_t> data_;
|
|
122
|
+
std::vector<std::string> strings_;
|
|
123
|
+
std::vector<std::string> types_;
|
|
124
|
+
std::vector<ClassDef> classes_;
|
|
125
|
+
std::vector<uint32_t> string_ids_;
|
|
126
|
+
std::vector<uint32_t> type_ids_;
|
|
127
|
+
|
|
128
|
+
bool parse_header();
|
|
129
|
+
bool parse_strings();
|
|
130
|
+
bool parse_types();
|
|
131
|
+
bool parse_classes();
|
|
132
|
+
|
|
133
|
+
std::string read_string_at(uint32_t offset) const;
|
|
134
|
+
uint32_t read_uleb128(size_t& offset) const;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
} // namespace dex
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <map>
|
|
7
|
+
|
|
8
|
+
namespace dex {
|
|
9
|
+
|
|
10
|
+
// Dalvik opcode formats
|
|
11
|
+
enum class OpcodeFormat {
|
|
12
|
+
k10x, // op
|
|
13
|
+
k12x, // op vA, vB
|
|
14
|
+
k11n, // op vA, #+B
|
|
15
|
+
k11x, // op vAA
|
|
16
|
+
k10t, // op +AA
|
|
17
|
+
k20t, // op +AAAA
|
|
18
|
+
k22x, // op vAA, vBBBB
|
|
19
|
+
k21t, // op vAA, +BBBB
|
|
20
|
+
k21s, // op vAA, #+BBBB
|
|
21
|
+
k21h, // op vAA, #+BBBB0000(00000000)
|
|
22
|
+
k21c, // op vAA, type@BBBB / field@BBBB / string@BBBB
|
|
23
|
+
k23x, // op vAA, vBB, vCC
|
|
24
|
+
k22b, // op vAA, vBB, #+CC
|
|
25
|
+
k22t, // op vA, vB, +CCCC
|
|
26
|
+
k22s, // op vA, vB, #+CCCC
|
|
27
|
+
k22c, // op vA, vB, type@CCCC / field@CCCC
|
|
28
|
+
k32x, // op vAAAA, vBBBB
|
|
29
|
+
k30t, // op +AAAAAAAA
|
|
30
|
+
k31t, // op vAA, +BBBBBBBB
|
|
31
|
+
k31i, // op vAA, #+BBBBBBBB
|
|
32
|
+
k31c, // op vAA, string@BBBBBBBB
|
|
33
|
+
k35c, // op {vC, vD, vE, vF, vG}, meth@BBBB / type@BBBB
|
|
34
|
+
k3rc, // op {vCCCC .. vNNNN}, meth@BBBB / type@BBBB
|
|
35
|
+
k51l, // op vAA, #+BBBBBBBBBBBBBBBB
|
|
36
|
+
kPackedSwitch,
|
|
37
|
+
kSparseSwitch,
|
|
38
|
+
kFillArrayData,
|
|
39
|
+
kUnknown
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
struct OpcodeInfo {
|
|
43
|
+
const char* name;
|
|
44
|
+
OpcodeFormat format;
|
|
45
|
+
uint8_t size; // in 16-bit code units
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
struct DisassembledInsn {
|
|
49
|
+
uint32_t offset;
|
|
50
|
+
std::string opcode;
|
|
51
|
+
std::string operands;
|
|
52
|
+
std::string comment;
|
|
53
|
+
std::vector<uint16_t> raw_bytes;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
class SmaliDisassembler {
|
|
57
|
+
public:
|
|
58
|
+
SmaliDisassembler() = default;
|
|
59
|
+
~SmaliDisassembler() = default;
|
|
60
|
+
|
|
61
|
+
// Set context for resolving references
|
|
62
|
+
void set_strings(const std::vector<std::string>& strings) { strings_ = strings; }
|
|
63
|
+
void set_types(const std::vector<std::string>& types) { types_ = types; }
|
|
64
|
+
void set_methods(const std::vector<std::string>& methods) { methods_ = methods; }
|
|
65
|
+
void set_fields(const std::vector<std::string>& fields) { fields_ = fields; }
|
|
66
|
+
|
|
67
|
+
// Disassemble a single instruction
|
|
68
|
+
DisassembledInsn disassemble_insn(const uint8_t* code, size_t code_size, uint32_t offset);
|
|
69
|
+
|
|
70
|
+
// Disassemble entire method code
|
|
71
|
+
std::vector<DisassembledInsn> disassemble_method(const uint8_t* code, size_t code_size);
|
|
72
|
+
|
|
73
|
+
// Convert disassembled instructions to Smali text
|
|
74
|
+
std::string to_smali(const std::vector<DisassembledInsn>& insns);
|
|
75
|
+
|
|
76
|
+
// Get opcode info
|
|
77
|
+
static const OpcodeInfo& get_opcode_info(uint8_t opcode);
|
|
78
|
+
static int get_opcode_by_name(const std::string& name);
|
|
79
|
+
|
|
80
|
+
private:
|
|
81
|
+
std::vector<std::string> strings_;
|
|
82
|
+
std::vector<std::string> types_;
|
|
83
|
+
std::vector<std::string> methods_;
|
|
84
|
+
std::vector<std::string> fields_;
|
|
85
|
+
|
|
86
|
+
std::string resolve_string(uint32_t idx) const;
|
|
87
|
+
std::string resolve_type(uint32_t idx) const;
|
|
88
|
+
std::string resolve_method(uint32_t idx) const;
|
|
89
|
+
std::string resolve_field(uint32_t idx) const;
|
|
90
|
+
|
|
91
|
+
static const OpcodeInfo opcodes_[256];
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Smali Assembler - converts Smali text to bytecode
|
|
95
|
+
class SmaliAssembler {
|
|
96
|
+
public:
|
|
97
|
+
SmaliAssembler() = default;
|
|
98
|
+
~SmaliAssembler() = default;
|
|
99
|
+
|
|
100
|
+
// Set context for reference lookup
|
|
101
|
+
void set_strings(const std::vector<std::string>& strings) { strings_ = strings; }
|
|
102
|
+
void set_types(const std::vector<std::string>& types) { types_ = types; }
|
|
103
|
+
void set_methods(const std::vector<std::string>& methods) { methods_ = methods; }
|
|
104
|
+
void set_fields(const std::vector<std::string>& fields) { fields_ = fields; }
|
|
105
|
+
|
|
106
|
+
// Assemble Smali text to bytecode
|
|
107
|
+
bool assemble(const std::string& smali_code, std::vector<uint8_t>& bytecode, std::string& error);
|
|
108
|
+
|
|
109
|
+
// Assemble a single instruction
|
|
110
|
+
bool assemble_insn(const std::string& line, std::vector<uint8_t>& bytecode, std::string& error);
|
|
111
|
+
|
|
112
|
+
private:
|
|
113
|
+
std::vector<std::string> strings_;
|
|
114
|
+
std::vector<std::string> types_;
|
|
115
|
+
std::vector<std::string> methods_;
|
|
116
|
+
std::vector<std::string> fields_;
|
|
117
|
+
|
|
118
|
+
int find_string(const std::string& str) const;
|
|
119
|
+
int find_type(const std::string& type) const;
|
|
120
|
+
int find_method(const std::string& method) const;
|
|
121
|
+
int find_field(const std::string& field) const;
|
|
122
|
+
|
|
123
|
+
bool parse_register(const std::string& reg, int& num);
|
|
124
|
+
bool parse_int(const std::string& str, int64_t& val);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
} // namespace dex
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <unordered_map>
|
|
6
|
+
#include <sstream>
|
|
7
|
+
|
|
8
|
+
namespace dex {
|
|
9
|
+
|
|
10
|
+
class SmaliToJava {
|
|
11
|
+
public:
|
|
12
|
+
SmaliToJava() = default;
|
|
13
|
+
|
|
14
|
+
// Convert Smali code to Java-like pseudocode
|
|
15
|
+
std::string convert(const std::string& smali_code);
|
|
16
|
+
|
|
17
|
+
// Convert a single method
|
|
18
|
+
std::string convert_method(const std::string& method_smali);
|
|
19
|
+
|
|
20
|
+
private:
|
|
21
|
+
struct Register {
|
|
22
|
+
std::string type;
|
|
23
|
+
std::string value;
|
|
24
|
+
bool is_param = false;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
std::unordered_map<std::string, Register> registers_;
|
|
28
|
+
std::unordered_map<std::string, int> labels_; // label -> line number
|
|
29
|
+
int indent_ = 0;
|
|
30
|
+
|
|
31
|
+
std::string convert_instruction(const std::string& line);
|
|
32
|
+
std::string convert_invoke(const std::string& line);
|
|
33
|
+
std::string convert_field_access(const std::string& line);
|
|
34
|
+
std::string convert_const(const std::string& line);
|
|
35
|
+
std::string convert_move(const std::string& line);
|
|
36
|
+
std::string convert_return(const std::string& line);
|
|
37
|
+
std::string convert_if(const std::string& line);
|
|
38
|
+
std::string convert_new(const std::string& line);
|
|
39
|
+
std::string convert_array(const std::string& line);
|
|
40
|
+
std::string convert_cast(const std::string& line);
|
|
41
|
+
std::string convert_arithmetic(const std::string& line);
|
|
42
|
+
|
|
43
|
+
std::string type_to_java(const std::string& smali_type);
|
|
44
|
+
std::string method_to_java(const std::string& method_ref);
|
|
45
|
+
std::string get_indent();
|
|
46
|
+
std::vector<std::string> split(const std::string& s, char delim);
|
|
47
|
+
std::string trim(const std::string& s);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
} // namespace dex
|