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,1223 @@
1
+ #include "dex/smali_disasm.h"
2
+ #include <sstream>
3
+ #include <iomanip>
4
+ #include <cstring>
5
+ #include <algorithm>
6
+
7
+ namespace dex {
8
+
9
+ // Dalvik opcode table (256 opcodes)
10
+ const OpcodeInfo SmaliDisassembler::opcodes_[256] = {
11
+ {"nop", OpcodeFormat::k10x, 1}, // 0x00
12
+ {"move", OpcodeFormat::k12x, 1}, // 0x01
13
+ {"move/from16", OpcodeFormat::k22x, 2}, // 0x02
14
+ {"move/16", OpcodeFormat::k32x, 3}, // 0x03
15
+ {"move-wide", OpcodeFormat::k12x, 1}, // 0x04
16
+ {"move-wide/from16", OpcodeFormat::k22x, 2}, // 0x05
17
+ {"move-wide/16", OpcodeFormat::k32x, 3}, // 0x06
18
+ {"move-object", OpcodeFormat::k12x, 1}, // 0x07
19
+ {"move-object/from16", OpcodeFormat::k22x, 2}, // 0x08
20
+ {"move-object/16", OpcodeFormat::k32x, 3}, // 0x09
21
+ {"move-result", OpcodeFormat::k11x, 1}, // 0x0a
22
+ {"move-result-wide", OpcodeFormat::k11x, 1}, // 0x0b
23
+ {"move-result-object", OpcodeFormat::k11x, 1}, // 0x0c
24
+ {"move-exception", OpcodeFormat::k11x, 1}, // 0x0d
25
+ {"return-void", OpcodeFormat::k10x, 1}, // 0x0e
26
+ {"return", OpcodeFormat::k11x, 1}, // 0x0f
27
+ {"return-wide", OpcodeFormat::k11x, 1}, // 0x10
28
+ {"return-object", OpcodeFormat::k11x, 1}, // 0x11
29
+ {"const/4", OpcodeFormat::k11n, 1}, // 0x12
30
+ {"const/16", OpcodeFormat::k21s, 2}, // 0x13
31
+ {"const", OpcodeFormat::k31i, 3}, // 0x14
32
+ {"const/high16", OpcodeFormat::k21h, 2}, // 0x15
33
+ {"const-wide/16", OpcodeFormat::k21s, 2}, // 0x16
34
+ {"const-wide/32", OpcodeFormat::k31i, 3}, // 0x17
35
+ {"const-wide", OpcodeFormat::k51l, 5}, // 0x18
36
+ {"const-wide/high16", OpcodeFormat::k21h, 2}, // 0x19
37
+ {"const-string", OpcodeFormat::k21c, 2}, // 0x1a
38
+ {"const-string/jumbo", OpcodeFormat::k31c, 3}, // 0x1b
39
+ {"const-class", OpcodeFormat::k21c, 2}, // 0x1c
40
+ {"monitor-enter", OpcodeFormat::k11x, 1}, // 0x1d
41
+ {"monitor-exit", OpcodeFormat::k11x, 1}, // 0x1e
42
+ {"check-cast", OpcodeFormat::k21c, 2}, // 0x1f
43
+ {"instance-of", OpcodeFormat::k22c, 2}, // 0x20
44
+ {"array-length", OpcodeFormat::k12x, 1}, // 0x21
45
+ {"new-instance", OpcodeFormat::k21c, 2}, // 0x22
46
+ {"new-array", OpcodeFormat::k22c, 2}, // 0x23
47
+ {"filled-new-array", OpcodeFormat::k35c, 3}, // 0x24
48
+ {"filled-new-array/range", OpcodeFormat::k3rc, 3}, // 0x25
49
+ {"fill-array-data", OpcodeFormat::k31t, 3}, // 0x26
50
+ {"throw", OpcodeFormat::k11x, 1}, // 0x27
51
+ {"goto", OpcodeFormat::k10t, 1}, // 0x28
52
+ {"goto/16", OpcodeFormat::k20t, 2}, // 0x29
53
+ {"goto/32", OpcodeFormat::k30t, 3}, // 0x2a
54
+ {"packed-switch", OpcodeFormat::k31t, 3}, // 0x2b
55
+ {"sparse-switch", OpcodeFormat::k31t, 3}, // 0x2c
56
+ {"cmpl-float", OpcodeFormat::k23x, 2}, // 0x2d
57
+ {"cmpg-float", OpcodeFormat::k23x, 2}, // 0x2e
58
+ {"cmpl-double", OpcodeFormat::k23x, 2}, // 0x2f
59
+ {"cmpg-double", OpcodeFormat::k23x, 2}, // 0x30
60
+ {"cmp-long", OpcodeFormat::k23x, 2}, // 0x31
61
+ {"if-eq", OpcodeFormat::k22t, 2}, // 0x32
62
+ {"if-ne", OpcodeFormat::k22t, 2}, // 0x33
63
+ {"if-lt", OpcodeFormat::k22t, 2}, // 0x34
64
+ {"if-ge", OpcodeFormat::k22t, 2}, // 0x35
65
+ {"if-gt", OpcodeFormat::k22t, 2}, // 0x36
66
+ {"if-le", OpcodeFormat::k22t, 2}, // 0x37
67
+ {"if-eqz", OpcodeFormat::k21t, 2}, // 0x38
68
+ {"if-nez", OpcodeFormat::k21t, 2}, // 0x39
69
+ {"if-ltz", OpcodeFormat::k21t, 2}, // 0x3a
70
+ {"if-gez", OpcodeFormat::k21t, 2}, // 0x3b
71
+ {"if-gtz", OpcodeFormat::k21t, 2}, // 0x3c
72
+ {"if-lez", OpcodeFormat::k21t, 2}, // 0x3d
73
+ {"unused-3e", OpcodeFormat::k10x, 1}, // 0x3e
74
+ {"unused-3f", OpcodeFormat::k10x, 1}, // 0x3f
75
+ {"unused-40", OpcodeFormat::k10x, 1}, // 0x40
76
+ {"unused-41", OpcodeFormat::k10x, 1}, // 0x41
77
+ {"unused-42", OpcodeFormat::k10x, 1}, // 0x42
78
+ {"unused-43", OpcodeFormat::k10x, 1}, // 0x43
79
+ {"aget", OpcodeFormat::k23x, 2}, // 0x44
80
+ {"aget-wide", OpcodeFormat::k23x, 2}, // 0x45
81
+ {"aget-object", OpcodeFormat::k23x, 2}, // 0x46
82
+ {"aget-boolean", OpcodeFormat::k23x, 2}, // 0x47
83
+ {"aget-byte", OpcodeFormat::k23x, 2}, // 0x48
84
+ {"aget-char", OpcodeFormat::k23x, 2}, // 0x49
85
+ {"aget-short", OpcodeFormat::k23x, 2}, // 0x4a
86
+ {"aput", OpcodeFormat::k23x, 2}, // 0x4b
87
+ {"aput-wide", OpcodeFormat::k23x, 2}, // 0x4c
88
+ {"aput-object", OpcodeFormat::k23x, 2}, // 0x4d
89
+ {"aput-boolean", OpcodeFormat::k23x, 2}, // 0x4e
90
+ {"aput-byte", OpcodeFormat::k23x, 2}, // 0x4f
91
+ {"aput-char", OpcodeFormat::k23x, 2}, // 0x50
92
+ {"aput-short", OpcodeFormat::k23x, 2}, // 0x51
93
+ {"iget", OpcodeFormat::k22c, 2}, // 0x52
94
+ {"iget-wide", OpcodeFormat::k22c, 2}, // 0x53
95
+ {"iget-object", OpcodeFormat::k22c, 2}, // 0x54
96
+ {"iget-boolean", OpcodeFormat::k22c, 2}, // 0x55
97
+ {"iget-byte", OpcodeFormat::k22c, 2}, // 0x56
98
+ {"iget-char", OpcodeFormat::k22c, 2}, // 0x57
99
+ {"iget-short", OpcodeFormat::k22c, 2}, // 0x58
100
+ {"iput", OpcodeFormat::k22c, 2}, // 0x59
101
+ {"iput-wide", OpcodeFormat::k22c, 2}, // 0x5a
102
+ {"iput-object", OpcodeFormat::k22c, 2}, // 0x5b
103
+ {"iput-boolean", OpcodeFormat::k22c, 2}, // 0x5c
104
+ {"iput-byte", OpcodeFormat::k22c, 2}, // 0x5d
105
+ {"iput-char", OpcodeFormat::k22c, 2}, // 0x5e
106
+ {"iput-short", OpcodeFormat::k22c, 2}, // 0x5f
107
+ {"sget", OpcodeFormat::k21c, 2}, // 0x60
108
+ {"sget-wide", OpcodeFormat::k21c, 2}, // 0x61
109
+ {"sget-object", OpcodeFormat::k21c, 2}, // 0x62
110
+ {"sget-boolean", OpcodeFormat::k21c, 2}, // 0x63
111
+ {"sget-byte", OpcodeFormat::k21c, 2}, // 0x64
112
+ {"sget-char", OpcodeFormat::k21c, 2}, // 0x65
113
+ {"sget-short", OpcodeFormat::k21c, 2}, // 0x66
114
+ {"sput", OpcodeFormat::k21c, 2}, // 0x67
115
+ {"sput-wide", OpcodeFormat::k21c, 2}, // 0x68
116
+ {"sput-object", OpcodeFormat::k21c, 2}, // 0x69
117
+ {"sput-boolean", OpcodeFormat::k21c, 2}, // 0x6a
118
+ {"sput-byte", OpcodeFormat::k21c, 2}, // 0x6b
119
+ {"sput-char", OpcodeFormat::k21c, 2}, // 0x6c
120
+ {"sput-short", OpcodeFormat::k21c, 2}, // 0x6d
121
+ {"invoke-virtual", OpcodeFormat::k35c, 3}, // 0x6e
122
+ {"invoke-super", OpcodeFormat::k35c, 3}, // 0x6f
123
+ {"invoke-direct", OpcodeFormat::k35c, 3}, // 0x70
124
+ {"invoke-static", OpcodeFormat::k35c, 3}, // 0x71
125
+ {"invoke-interface", OpcodeFormat::k35c, 3}, // 0x72
126
+ {"unused-73", OpcodeFormat::k10x, 1}, // 0x73
127
+ {"invoke-virtual/range", OpcodeFormat::k3rc, 3}, // 0x74
128
+ {"invoke-super/range", OpcodeFormat::k3rc, 3}, // 0x75
129
+ {"invoke-direct/range", OpcodeFormat::k3rc, 3}, // 0x76
130
+ {"invoke-static/range", OpcodeFormat::k3rc, 3}, // 0x77
131
+ {"invoke-interface/range", OpcodeFormat::k3rc, 3}, // 0x78
132
+ {"unused-79", OpcodeFormat::k10x, 1}, // 0x79
133
+ {"unused-7a", OpcodeFormat::k10x, 1}, // 0x7a
134
+ {"neg-int", OpcodeFormat::k12x, 1}, // 0x7b
135
+ {"not-int", OpcodeFormat::k12x, 1}, // 0x7c
136
+ {"neg-long", OpcodeFormat::k12x, 1}, // 0x7d
137
+ {"not-long", OpcodeFormat::k12x, 1}, // 0x7e
138
+ {"neg-float", OpcodeFormat::k12x, 1}, // 0x7f
139
+ {"neg-double", OpcodeFormat::k12x, 1}, // 0x80
140
+ {"int-to-long", OpcodeFormat::k12x, 1}, // 0x81
141
+ {"int-to-float", OpcodeFormat::k12x, 1}, // 0x82
142
+ {"int-to-double", OpcodeFormat::k12x, 1}, // 0x83
143
+ {"long-to-int", OpcodeFormat::k12x, 1}, // 0x84
144
+ {"long-to-float", OpcodeFormat::k12x, 1}, // 0x85
145
+ {"long-to-double", OpcodeFormat::k12x, 1}, // 0x86
146
+ {"float-to-int", OpcodeFormat::k12x, 1}, // 0x87
147
+ {"float-to-long", OpcodeFormat::k12x, 1}, // 0x88
148
+ {"float-to-double", OpcodeFormat::k12x, 1}, // 0x89
149
+ {"double-to-int", OpcodeFormat::k12x, 1}, // 0x8a
150
+ {"double-to-long", OpcodeFormat::k12x, 1}, // 0x8b
151
+ {"double-to-float", OpcodeFormat::k12x, 1}, // 0x8c
152
+ {"int-to-byte", OpcodeFormat::k12x, 1}, // 0x8d
153
+ {"int-to-char", OpcodeFormat::k12x, 1}, // 0x8e
154
+ {"int-to-short", OpcodeFormat::k12x, 1}, // 0x8f
155
+ {"add-int", OpcodeFormat::k23x, 2}, // 0x90
156
+ {"sub-int", OpcodeFormat::k23x, 2}, // 0x91
157
+ {"mul-int", OpcodeFormat::k23x, 2}, // 0x92
158
+ {"div-int", OpcodeFormat::k23x, 2}, // 0x93
159
+ {"rem-int", OpcodeFormat::k23x, 2}, // 0x94
160
+ {"and-int", OpcodeFormat::k23x, 2}, // 0x95
161
+ {"or-int", OpcodeFormat::k23x, 2}, // 0x96
162
+ {"xor-int", OpcodeFormat::k23x, 2}, // 0x97
163
+ {"shl-int", OpcodeFormat::k23x, 2}, // 0x98
164
+ {"shr-int", OpcodeFormat::k23x, 2}, // 0x99
165
+ {"ushr-int", OpcodeFormat::k23x, 2}, // 0x9a
166
+ {"add-long", OpcodeFormat::k23x, 2}, // 0x9b
167
+ {"sub-long", OpcodeFormat::k23x, 2}, // 0x9c
168
+ {"mul-long", OpcodeFormat::k23x, 2}, // 0x9d
169
+ {"div-long", OpcodeFormat::k23x, 2}, // 0x9e
170
+ {"rem-long", OpcodeFormat::k23x, 2}, // 0x9f
171
+ {"and-long", OpcodeFormat::k23x, 2}, // 0xa0
172
+ {"or-long", OpcodeFormat::k23x, 2}, // 0xa1
173
+ {"xor-long", OpcodeFormat::k23x, 2}, // 0xa2
174
+ {"shl-long", OpcodeFormat::k23x, 2}, // 0xa3
175
+ {"shr-long", OpcodeFormat::k23x, 2}, // 0xa4
176
+ {"ushr-long", OpcodeFormat::k23x, 2}, // 0xa5
177
+ {"add-float", OpcodeFormat::k23x, 2}, // 0xa6
178
+ {"sub-float", OpcodeFormat::k23x, 2}, // 0xa7
179
+ {"mul-float", OpcodeFormat::k23x, 2}, // 0xa8
180
+ {"div-float", OpcodeFormat::k23x, 2}, // 0xa9
181
+ {"rem-float", OpcodeFormat::k23x, 2}, // 0xaa
182
+ {"add-double", OpcodeFormat::k23x, 2}, // 0xab
183
+ {"sub-double", OpcodeFormat::k23x, 2}, // 0xac
184
+ {"mul-double", OpcodeFormat::k23x, 2}, // 0xad
185
+ {"div-double", OpcodeFormat::k23x, 2}, // 0xae
186
+ {"rem-double", OpcodeFormat::k23x, 2}, // 0xaf
187
+ {"add-int/2addr", OpcodeFormat::k12x, 1}, // 0xb0
188
+ {"sub-int/2addr", OpcodeFormat::k12x, 1}, // 0xb1
189
+ {"mul-int/2addr", OpcodeFormat::k12x, 1}, // 0xb2
190
+ {"div-int/2addr", OpcodeFormat::k12x, 1}, // 0xb3
191
+ {"rem-int/2addr", OpcodeFormat::k12x, 1}, // 0xb4
192
+ {"and-int/2addr", OpcodeFormat::k12x, 1}, // 0xb5
193
+ {"or-int/2addr", OpcodeFormat::k12x, 1}, // 0xb6
194
+ {"xor-int/2addr", OpcodeFormat::k12x, 1}, // 0xb7
195
+ {"shl-int/2addr", OpcodeFormat::k12x, 1}, // 0xb8
196
+ {"shr-int/2addr", OpcodeFormat::k12x, 1}, // 0xb9
197
+ {"ushr-int/2addr", OpcodeFormat::k12x, 1}, // 0xba
198
+ {"add-long/2addr", OpcodeFormat::k12x, 1}, // 0xbb
199
+ {"sub-long/2addr", OpcodeFormat::k12x, 1}, // 0xbc
200
+ {"mul-long/2addr", OpcodeFormat::k12x, 1}, // 0xbd
201
+ {"div-long/2addr", OpcodeFormat::k12x, 1}, // 0xbe
202
+ {"rem-long/2addr", OpcodeFormat::k12x, 1}, // 0xbf
203
+ {"and-long/2addr", OpcodeFormat::k12x, 1}, // 0xc0
204
+ {"or-long/2addr", OpcodeFormat::k12x, 1}, // 0xc1
205
+ {"xor-long/2addr", OpcodeFormat::k12x, 1}, // 0xc2
206
+ {"shl-long/2addr", OpcodeFormat::k12x, 1}, // 0xc3
207
+ {"shr-long/2addr", OpcodeFormat::k12x, 1}, // 0xc4
208
+ {"ushr-long/2addr", OpcodeFormat::k12x, 1}, // 0xc5
209
+ {"add-float/2addr", OpcodeFormat::k12x, 1}, // 0xc6
210
+ {"sub-float/2addr", OpcodeFormat::k12x, 1}, // 0xc7
211
+ {"mul-float/2addr", OpcodeFormat::k12x, 1}, // 0xc8
212
+ {"div-float/2addr", OpcodeFormat::k12x, 1}, // 0xc9
213
+ {"rem-float/2addr", OpcodeFormat::k12x, 1}, // 0xca
214
+ {"add-double/2addr", OpcodeFormat::k12x, 1}, // 0xcb
215
+ {"sub-double/2addr", OpcodeFormat::k12x, 1}, // 0xcc
216
+ {"mul-double/2addr", OpcodeFormat::k12x, 1}, // 0xcd
217
+ {"div-double/2addr", OpcodeFormat::k12x, 1}, // 0xce
218
+ {"rem-double/2addr", OpcodeFormat::k12x, 1}, // 0xcf
219
+ {"add-int/lit16", OpcodeFormat::k22s, 2}, // 0xd0
220
+ {"rsub-int", OpcodeFormat::k22s, 2}, // 0xd1
221
+ {"mul-int/lit16", OpcodeFormat::k22s, 2}, // 0xd2
222
+ {"div-int/lit16", OpcodeFormat::k22s, 2}, // 0xd3
223
+ {"rem-int/lit16", OpcodeFormat::k22s, 2}, // 0xd4
224
+ {"and-int/lit16", OpcodeFormat::k22s, 2}, // 0xd5
225
+ {"or-int/lit16", OpcodeFormat::k22s, 2}, // 0xd6
226
+ {"xor-int/lit16", OpcodeFormat::k22s, 2}, // 0xd7
227
+ {"add-int/lit8", OpcodeFormat::k22b, 2}, // 0xd8
228
+ {"rsub-int/lit8", OpcodeFormat::k22b, 2}, // 0xd9
229
+ {"mul-int/lit8", OpcodeFormat::k22b, 2}, // 0xda
230
+ {"div-int/lit8", OpcodeFormat::k22b, 2}, // 0xdb
231
+ {"rem-int/lit8", OpcodeFormat::k22b, 2}, // 0xdc
232
+ {"and-int/lit8", OpcodeFormat::k22b, 2}, // 0xdd
233
+ {"or-int/lit8", OpcodeFormat::k22b, 2}, // 0xde
234
+ {"xor-int/lit8", OpcodeFormat::k22b, 2}, // 0xdf
235
+ {"shl-int/lit8", OpcodeFormat::k22b, 2}, // 0xe0
236
+ {"shr-int/lit8", OpcodeFormat::k22b, 2}, // 0xe1
237
+ {"ushr-int/lit8", OpcodeFormat::k22b, 2}, // 0xe2
238
+ {"unused-e3", OpcodeFormat::k10x, 1}, // 0xe3
239
+ {"unused-e4", OpcodeFormat::k10x, 1}, // 0xe4
240
+ {"unused-e5", OpcodeFormat::k10x, 1}, // 0xe5
241
+ {"unused-e6", OpcodeFormat::k10x, 1}, // 0xe6
242
+ {"unused-e7", OpcodeFormat::k10x, 1}, // 0xe7
243
+ {"unused-e8", OpcodeFormat::k10x, 1}, // 0xe8
244
+ {"unused-e9", OpcodeFormat::k10x, 1}, // 0xe9
245
+ {"unused-ea", OpcodeFormat::k10x, 1}, // 0xea
246
+ {"unused-eb", OpcodeFormat::k10x, 1}, // 0xeb
247
+ {"unused-ec", OpcodeFormat::k10x, 1}, // 0xec
248
+ {"unused-ed", OpcodeFormat::k10x, 1}, // 0xed
249
+ {"unused-ee", OpcodeFormat::k10x, 1}, // 0xee
250
+ {"unused-ef", OpcodeFormat::k10x, 1}, // 0xef
251
+ {"unused-f0", OpcodeFormat::k10x, 1}, // 0xf0
252
+ {"unused-f1", OpcodeFormat::k10x, 1}, // 0xf1
253
+ {"unused-f2", OpcodeFormat::k10x, 1}, // 0xf2
254
+ {"unused-f3", OpcodeFormat::k10x, 1}, // 0xf3
255
+ {"unused-f4", OpcodeFormat::k10x, 1}, // 0xf4
256
+ {"unused-f5", OpcodeFormat::k10x, 1}, // 0xf5
257
+ {"unused-f6", OpcodeFormat::k10x, 1}, // 0xf6
258
+ {"unused-f7", OpcodeFormat::k10x, 1}, // 0xf7
259
+ {"unused-f8", OpcodeFormat::k10x, 1}, // 0xf8
260
+ {"unused-f9", OpcodeFormat::k10x, 1}, // 0xf9
261
+ {"unused-fa", OpcodeFormat::k10x, 1}, // 0xfa
262
+ {"unused-fb", OpcodeFormat::k10x, 1}, // 0xfb
263
+ {"unused-fc", OpcodeFormat::k10x, 1}, // 0xfc
264
+ {"unused-fd", OpcodeFormat::k10x, 1}, // 0xfd
265
+ {"unused-fe", OpcodeFormat::k10x, 1}, // 0xfe
266
+ {"unused-ff", OpcodeFormat::k10x, 1}, // 0xff
267
+ };
268
+
269
+ template<typename T>
270
+ static T read_le(const uint8_t* p) {
271
+ T val = 0;
272
+ for (size_t i = 0; i < sizeof(T); i++) {
273
+ val |= static_cast<T>(p[i]) << (i * 8);
274
+ }
275
+ return val;
276
+ }
277
+
278
+ const OpcodeInfo& SmaliDisassembler::get_opcode_info(uint8_t opcode) {
279
+ return opcodes_[opcode];
280
+ }
281
+
282
+ std::string SmaliDisassembler::resolve_string(uint32_t idx) const {
283
+ if (idx < strings_.size()) {
284
+ return "\"" + strings_[idx] + "\"";
285
+ }
286
+ return "string@" + std::to_string(idx);
287
+ }
288
+
289
+ std::string SmaliDisassembler::resolve_type(uint32_t idx) const {
290
+ if (idx < types_.size()) {
291
+ return types_[idx];
292
+ }
293
+ return "type@" + std::to_string(idx);
294
+ }
295
+
296
+ std::string SmaliDisassembler::resolve_method(uint32_t idx) const {
297
+ if (idx < methods_.size()) {
298
+ return methods_[idx];
299
+ }
300
+ return "method@" + std::to_string(idx);
301
+ }
302
+
303
+ std::string SmaliDisassembler::resolve_field(uint32_t idx) const {
304
+ if (idx < fields_.size()) {
305
+ return fields_[idx];
306
+ }
307
+ return "field@" + std::to_string(idx);
308
+ }
309
+
310
+ DisassembledInsn SmaliDisassembler::disassemble_insn(const uint8_t* code, size_t code_size, uint32_t offset) {
311
+ DisassembledInsn insn;
312
+ insn.offset = offset;
313
+
314
+ if (code_size < 2) {
315
+ insn.opcode = "invalid";
316
+ return insn;
317
+ }
318
+
319
+ uint8_t op = code[0];
320
+ const OpcodeInfo& info = opcodes_[op];
321
+ insn.opcode = info.name;
322
+
323
+ // Store raw bytes
324
+ size_t byte_size = info.size * 2;
325
+ for (size_t i = 0; i < byte_size && i < code_size; i += 2) {
326
+ insn.raw_bytes.push_back(read_le<uint16_t>(&code[i]));
327
+ }
328
+
329
+ std::ostringstream oss;
330
+
331
+ switch (info.format) {
332
+ case OpcodeFormat::k10x:
333
+ // No operands
334
+ break;
335
+
336
+ case OpcodeFormat::k12x: {
337
+ // k12x format: B|A|op, A is low 4 bits, B is high 4 bits
338
+ uint8_t vA = code[1] & 0xF;
339
+ uint8_t vB = (code[1] >> 4) & 0xF;
340
+ oss << "v" << (int)vA << ", v" << (int)vB;
341
+ break;
342
+ }
343
+
344
+ case OpcodeFormat::k11n: {
345
+ uint8_t vA = code[1] & 0xF;
346
+ int8_t B = (code[1] >> 4);
347
+ if (B & 0x8) B |= 0xF0; // Sign extend
348
+ oss << "v" << (int)vA << ", #int " << (int)B;
349
+ break;
350
+ }
351
+
352
+ case OpcodeFormat::k11x: {
353
+ uint8_t vAA = code[1];
354
+ oss << "v" << (int)vAA;
355
+ break;
356
+ }
357
+
358
+ case OpcodeFormat::k10t: {
359
+ int8_t AA = static_cast<int8_t>(code[1]);
360
+ oss << std::showpos << (int)AA << std::noshowpos;
361
+ insn.comment = "goto " + std::to_string(offset / 2 + AA);
362
+ break;
363
+ }
364
+
365
+ case OpcodeFormat::k20t: {
366
+ int16_t AAAA = read_le<int16_t>(&code[2]);
367
+ oss << std::showpos << (int)AAAA << std::noshowpos;
368
+ insn.comment = "goto " + std::to_string(offset / 2 + AAAA);
369
+ break;
370
+ }
371
+
372
+ case OpcodeFormat::k22x: {
373
+ uint8_t vAA = code[1];
374
+ uint16_t vBBBB = read_le<uint16_t>(&code[2]);
375
+ oss << "v" << (int)vAA << ", v" << (int)vBBBB;
376
+ break;
377
+ }
378
+
379
+ case OpcodeFormat::k21t: {
380
+ uint8_t vAA = code[1];
381
+ int16_t BBBB = read_le<int16_t>(&code[2]);
382
+ oss << "v" << (int)vAA << ", " << std::showpos << (int)BBBB << std::noshowpos;
383
+ insn.comment = "target " + std::to_string(offset / 2 + BBBB);
384
+ break;
385
+ }
386
+
387
+ case OpcodeFormat::k21s: {
388
+ uint8_t vAA = code[1];
389
+ int16_t BBBB = read_le<int16_t>(&code[2]);
390
+ oss << "v" << (int)vAA << ", #int " << (int)BBBB;
391
+ break;
392
+ }
393
+
394
+ case OpcodeFormat::k21h: {
395
+ uint8_t vAA = code[1];
396
+ int16_t BBBB = read_le<int16_t>(&code[2]);
397
+ if (op == 0x15) { // const/high16
398
+ oss << "v" << (int)vAA << ", #int " << ((int)BBBB << 16);
399
+ } else { // const-wide/high16
400
+ oss << "v" << (int)vAA << ", #long " << ((int64_t)BBBB << 48);
401
+ }
402
+ break;
403
+ }
404
+
405
+ case OpcodeFormat::k21c: {
406
+ uint8_t vAA = code[1];
407
+ uint16_t BBBB = read_le<uint16_t>(&code[2]);
408
+ oss << "v" << (int)vAA << ", ";
409
+ if (op == 0x1a) { // const-string
410
+ oss << resolve_string(BBBB);
411
+ } else if (op == 0x1c || op == 0x1f || op == 0x22) { // const-class, check-cast, new-instance
412
+ oss << resolve_type(BBBB);
413
+ } else if (op >= 0x60 && op <= 0x6d) { // sget/sput
414
+ oss << resolve_field(BBBB);
415
+ } else {
416
+ oss << "ref@" << BBBB;
417
+ }
418
+ break;
419
+ }
420
+
421
+ case OpcodeFormat::k23x: {
422
+ uint8_t vAA = code[1];
423
+ uint8_t vBB = code[2];
424
+ uint8_t vCC = code[3];
425
+ oss << "v" << (int)vAA << ", v" << (int)vBB << ", v" << (int)vCC;
426
+ break;
427
+ }
428
+
429
+ case OpcodeFormat::k22b: {
430
+ uint8_t vAA = code[1];
431
+ uint8_t vBB = code[2];
432
+ int8_t CC = static_cast<int8_t>(code[3]);
433
+ oss << "v" << (int)vAA << ", v" << (int)vBB << ", #int " << (int)CC;
434
+ break;
435
+ }
436
+
437
+ case OpcodeFormat::k22t: {
438
+ uint8_t vA = code[1] & 0xF;
439
+ uint8_t vB = (code[1] >> 4) & 0xF;
440
+ int16_t CCCC = read_le<int16_t>(&code[2]);
441
+ oss << "v" << (int)vA << ", v" << (int)vB << ", " << std::showpos << (int)CCCC << std::noshowpos;
442
+ insn.comment = "target " + std::to_string(offset / 2 + CCCC);
443
+ break;
444
+ }
445
+
446
+ case OpcodeFormat::k22s: {
447
+ uint8_t vA = code[1] & 0xF;
448
+ uint8_t vB = (code[1] >> 4) & 0xF;
449
+ int16_t CCCC = read_le<int16_t>(&code[2]);
450
+ oss << "v" << (int)vA << ", v" << (int)vB << ", #int " << (int)CCCC;
451
+ break;
452
+ }
453
+
454
+ case OpcodeFormat::k22c: {
455
+ uint8_t vA = code[1] & 0xF;
456
+ uint8_t vB = (code[1] >> 4) & 0xF;
457
+ uint16_t CCCC = read_le<uint16_t>(&code[2]);
458
+ oss << "v" << (int)vA << ", v" << (int)vB << ", ";
459
+ if (op == 0x20 || op == 0x23) { // instance-of, new-array
460
+ oss << resolve_type(CCCC);
461
+ } else { // iget/iput
462
+ oss << resolve_field(CCCC);
463
+ }
464
+ break;
465
+ }
466
+
467
+ case OpcodeFormat::k32x: {
468
+ uint16_t vAAAA = read_le<uint16_t>(&code[2]);
469
+ uint16_t vBBBB = read_le<uint16_t>(&code[4]);
470
+ oss << "v" << (int)vAAAA << ", v" << (int)vBBBB;
471
+ break;
472
+ }
473
+
474
+ case OpcodeFormat::k30t: {
475
+ int32_t AAAAAAAA = read_le<int32_t>(&code[2]);
476
+ oss << std::showpos << AAAAAAAA << std::noshowpos;
477
+ insn.comment = "goto " + std::to_string(offset / 2 + AAAAAAAA);
478
+ break;
479
+ }
480
+
481
+ case OpcodeFormat::k31t: {
482
+ uint8_t vAA = code[1];
483
+ int32_t BBBBBBBB = read_le<int32_t>(&code[2]);
484
+ oss << "v" << (int)vAA << ", " << std::showpos << BBBBBBBB << std::noshowpos;
485
+ break;
486
+ }
487
+
488
+ case OpcodeFormat::k31i: {
489
+ uint8_t vAA = code[1];
490
+ int32_t BBBBBBBB = read_le<int32_t>(&code[2]);
491
+ oss << "v" << (int)vAA << ", #int " << BBBBBBBB;
492
+ break;
493
+ }
494
+
495
+ case OpcodeFormat::k31c: {
496
+ uint8_t vAA = code[1];
497
+ uint32_t BBBBBBBB = read_le<uint32_t>(&code[2]);
498
+ oss << "v" << (int)vAA << ", " << resolve_string(BBBBBBBB);
499
+ break;
500
+ }
501
+
502
+ case OpcodeFormat::k35c: {
503
+ // k35c format: A|G|op BBBB F|E|D|C
504
+ // A = register count (high 4 bits of code[1])
505
+ // G = 5th register if A=5 (low 4 bits of code[1])
506
+ // C = low 4 bits of code[4]
507
+ // D = high 4 bits of code[4]
508
+ // E = low 4 bits of code[5]
509
+ // F = high 4 bits of code[5]
510
+ uint8_t A = (code[1] >> 4) & 0xF;
511
+ uint8_t G = code[1] & 0xF;
512
+ uint16_t BBBB = read_le<uint16_t>(&code[2]);
513
+ uint8_t C = code[4] & 0xF;
514
+ uint8_t D = (code[4] >> 4) & 0xF;
515
+ uint8_t E = code[5] & 0xF;
516
+ uint8_t F = (code[5] >> 4) & 0xF;
517
+
518
+ oss << "{";
519
+ uint8_t regs[] = {C, D, E, F, G};
520
+ for (int i = 0; i < A && i < 5; i++) {
521
+ if (i > 0) oss << ", ";
522
+ oss << "v" << (int)regs[i];
523
+ }
524
+ oss << "}, ";
525
+
526
+ if (op >= 0x6e && op <= 0x72) { // invoke-*
527
+ oss << resolve_method(BBBB);
528
+ } else {
529
+ oss << resolve_type(BBBB);
530
+ }
531
+ break;
532
+ }
533
+
534
+ case OpcodeFormat::k3rc: {
535
+ uint8_t AA = code[1];
536
+ uint16_t BBBB = read_le<uint16_t>(&code[2]);
537
+ uint16_t CCCC = read_le<uint16_t>(&code[4]);
538
+
539
+ oss << "{v" << CCCC << " .. v" << (CCCC + AA - 1) << "}, ";
540
+ if (op >= 0x74 && op <= 0x78) { // invoke-*/range
541
+ oss << resolve_method(BBBB);
542
+ } else {
543
+ oss << resolve_type(BBBB);
544
+ }
545
+ break;
546
+ }
547
+
548
+ case OpcodeFormat::k51l: {
549
+ uint8_t vAA = code[1];
550
+ int64_t BBBBBBBBBBBBBBBB = read_le<int64_t>(&code[2]);
551
+ oss << "v" << (int)vAA << ", #long " << BBBBBBBBBBBBBBBB;
552
+ break;
553
+ }
554
+
555
+ default:
556
+ oss << "?";
557
+ break;
558
+ }
559
+
560
+ insn.operands = oss.str();
561
+ return insn;
562
+ }
563
+
564
+ std::vector<DisassembledInsn> SmaliDisassembler::disassemble_method(const uint8_t* code, size_t code_size) {
565
+ std::vector<DisassembledInsn> result;
566
+
567
+ size_t offset = 0;
568
+ while (offset < code_size) {
569
+ DisassembledInsn insn = disassemble_insn(code + offset, code_size - offset, offset);
570
+
571
+ uint8_t op = code[offset];
572
+ size_t insn_size = opcodes_[op].size * 2;
573
+
574
+ result.push_back(insn);
575
+ offset += insn_size;
576
+
577
+ if (insn_size == 0) break; // Safety
578
+ }
579
+
580
+ return result;
581
+ }
582
+
583
+ std::string SmaliDisassembler::to_smali(const std::vector<DisassembledInsn>& insns) {
584
+ std::ostringstream oss;
585
+
586
+ for (const auto& insn : insns) {
587
+ oss << " " << insn.opcode;
588
+ if (!insn.operands.empty()) {
589
+ oss << " " << insn.operands;
590
+ }
591
+ if (!insn.comment.empty()) {
592
+ oss << " # " << insn.comment;
593
+ }
594
+ oss << "\n";
595
+ }
596
+
597
+ return oss.str();
598
+ }
599
+
600
+ int SmaliDisassembler::get_opcode_by_name(const std::string& name) {
601
+ for (int i = 0; i < 256; i++) {
602
+ if (opcodes_[i].name == name) {
603
+ return i;
604
+ }
605
+ }
606
+ return -1;
607
+ }
608
+
609
+ // SmaliAssembler implementation
610
+
611
+ template<typename T>
612
+ static void write_le(uint8_t* p, T val) {
613
+ for (size_t i = 0; i < sizeof(T); i++) {
614
+ p[i] = static_cast<uint8_t>(val >> (i * 8));
615
+ }
616
+ }
617
+
618
+ int SmaliAssembler::find_string(const std::string& str) const {
619
+ for (size_t i = 0; i < strings_.size(); i++) {
620
+ if (strings_[i] == str) return static_cast<int>(i);
621
+ }
622
+ return -1;
623
+ }
624
+
625
+ int SmaliAssembler::find_type(const std::string& type) const {
626
+ for (size_t i = 0; i < types_.size(); i++) {
627
+ if (types_[i] == type) return static_cast<int>(i);
628
+ }
629
+ return -1;
630
+ }
631
+
632
+ int SmaliAssembler::find_method(const std::string& method) const {
633
+ // First try exact match
634
+ for (size_t i = 0; i < methods_.size(); i++) {
635
+ if (methods_[i] == method) return static_cast<int>(i);
636
+ }
637
+ // Then try substring match (for cases like partial method signatures)
638
+ for (size_t i = 0; i < methods_.size(); i++) {
639
+ if (methods_[i].find(method) != std::string::npos) return static_cast<int>(i);
640
+ }
641
+ return -1;
642
+ }
643
+
644
+ int SmaliAssembler::find_field(const std::string& field) const {
645
+ // First try exact match
646
+ for (size_t i = 0; i < fields_.size(); i++) {
647
+ if (fields_[i] == field) return static_cast<int>(i);
648
+ }
649
+ // Then try substring match (for cases like partial field references)
650
+ for (size_t i = 0; i < fields_.size(); i++) {
651
+ if (fields_[i].find(field) != std::string::npos) return static_cast<int>(i);
652
+ }
653
+ return -1;
654
+ }
655
+
656
+ bool SmaliAssembler::parse_register(const std::string& reg, int& num) {
657
+ if (reg.empty() || reg[0] != 'v') return false;
658
+ try {
659
+ num = std::stoi(reg.substr(1));
660
+ return true;
661
+ } catch (...) {
662
+ return false;
663
+ }
664
+ }
665
+
666
+ bool SmaliAssembler::parse_int(const std::string& str, int64_t& val) {
667
+ try {
668
+ if (str.find("0x") == 0 || str.find("0X") == 0) {
669
+ val = std::stoll(str, nullptr, 16);
670
+ } else {
671
+ val = std::stoll(str);
672
+ }
673
+ return true;
674
+ } catch (...) {
675
+ return false;
676
+ }
677
+ }
678
+
679
+ bool SmaliAssembler::assemble_insn(const std::string& line, std::vector<uint8_t>& bytecode, std::string& error) {
680
+ // Parse line: ".XXXX: opcode operands // comment"
681
+ std::string trimmed = line;
682
+
683
+ // Remove leading whitespace
684
+ size_t start = trimmed.find_first_not_of(" \t");
685
+ if (start == std::string::npos) return true; // Empty line
686
+ trimmed = trimmed.substr(start);
687
+
688
+ // Skip directives and offset labels
689
+ if (trimmed[0] == '.') {
690
+ size_t colon = trimmed.find(':');
691
+ if (colon != std::string::npos && colon < 8) {
692
+ // Offset label like .0000: - extract instruction after it
693
+ trimmed = trimmed.substr(colon + 1);
694
+ start = trimmed.find_first_not_of(" \t");
695
+ if (start == std::string::npos) return true;
696
+ trimmed = trimmed.substr(start);
697
+ } else {
698
+ // Skip other directives like .method, .registers, .end, .line, etc
699
+ return true;
700
+ }
701
+ }
702
+
703
+ // Remove comment (only outside quotes)
704
+ bool in_str = false;
705
+ size_t comment_pos = std::string::npos;
706
+ for (size_t i = 0; i < trimmed.size(); i++) {
707
+ if (trimmed[i] == '"') in_str = !in_str;
708
+ if (!in_str && i + 1 < trimmed.size() && trimmed[i] == '/' && trimmed[i+1] == '/') {
709
+ comment_pos = i;
710
+ break;
711
+ }
712
+ }
713
+ if (comment_pos != std::string::npos) {
714
+ trimmed = trimmed.substr(0, comment_pos);
715
+ }
716
+
717
+ // Remove \r characters (Windows line endings)
718
+ trimmed.erase(std::remove(trimmed.begin(), trimmed.end(), '\r'), trimmed.end());
719
+
720
+ // Trim trailing whitespace
721
+ size_t end = trimmed.find_last_not_of(" \t\n");
722
+ if (end != std::string::npos) {
723
+ trimmed = trimmed.substr(0, end + 1);
724
+ }
725
+
726
+ if (trimmed.empty()) return true;
727
+
728
+ // Split opcode and operands
729
+ size_t space = trimmed.find(' ');
730
+ std::string opcode_name = (space != std::string::npos) ? trimmed.substr(0, space) : trimmed;
731
+ std::string operands = (space != std::string::npos) ? trimmed.substr(space + 1) : "";
732
+
733
+ // Trim operands
734
+ start = operands.find_first_not_of(" \t");
735
+ if (start != std::string::npos) {
736
+ operands = operands.substr(start);
737
+ }
738
+
739
+ // Find opcode
740
+ int op = SmaliDisassembler::get_opcode_by_name(opcode_name);
741
+ if (op < 0) {
742
+ error = "Unknown opcode: " + opcode_name;
743
+ return false;
744
+ }
745
+
746
+ const OpcodeInfo& info = SmaliDisassembler::get_opcode_info(static_cast<uint8_t>(op));
747
+ size_t insn_size = info.size * 2;
748
+
749
+ std::vector<uint8_t> insn(insn_size, 0);
750
+ insn[0] = static_cast<uint8_t>(op);
751
+
752
+ // Parse operands based on format
753
+ std::vector<std::string> parts;
754
+ std::string current;
755
+ bool in_brace = false;
756
+ bool in_quote = false;
757
+ for (char c : operands) {
758
+ if (c == '"' && !in_brace) in_quote = !in_quote;
759
+ if (c == '{' && !in_quote) in_brace = true;
760
+ if (c == '}' && !in_quote) in_brace = false;
761
+ if (c == ',' && !in_brace && !in_quote) {
762
+ size_t s = current.find_first_not_of(" \t");
763
+ size_t e = current.find_last_not_of(" \t");
764
+ if (s != std::string::npos && e != std::string::npos) {
765
+ parts.push_back(current.substr(s, e - s + 1));
766
+ }
767
+ current.clear();
768
+ } else {
769
+ current += c;
770
+ }
771
+ }
772
+ if (!current.empty()) {
773
+ size_t s = current.find_first_not_of(" \t");
774
+ size_t e = current.find_last_not_of(" \t");
775
+ if (s != std::string::npos && e != std::string::npos) {
776
+ parts.push_back(current.substr(s, e - s + 1));
777
+ }
778
+ }
779
+
780
+ switch (info.format) {
781
+ case OpcodeFormat::k10x:
782
+ // No operands
783
+ break;
784
+
785
+ case OpcodeFormat::k12x: {
786
+ // k12x format: B|A|op, A is low 4 bits, B is high 4 bits
787
+ if (parts.size() < 2) { error = "Expected 2 registers"; return false; }
788
+ int vA, vB;
789
+ if (!parse_register(parts[0], vA) || !parse_register(parts[1], vB)) {
790
+ error = "Invalid registers"; return false;
791
+ }
792
+ insn[1] = static_cast<uint8_t>((vB << 4) | (vA & 0xF));
793
+ break;
794
+ }
795
+
796
+ case OpcodeFormat::k11n: {
797
+ if (parts.size() < 2) { error = "Expected register and literal"; return false; }
798
+ int vA;
799
+ int64_t lit;
800
+ if (!parse_register(parts[0], vA)) { error = "Invalid register"; return false; }
801
+ std::string lit_str = parts[1];
802
+ if (lit_str.find("#int") != std::string::npos) {
803
+ lit_str = lit_str.substr(lit_str.find("#int") + 5);
804
+ }
805
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
806
+ insn[1] = static_cast<uint8_t>(((lit & 0xF) << 4) | (vA & 0xF));
807
+ break;
808
+ }
809
+
810
+ case OpcodeFormat::k11x: {
811
+ if (parts.size() < 1) { error = "Expected register"; return false; }
812
+ int vAA;
813
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
814
+ insn[1] = static_cast<uint8_t>(vAA);
815
+ break;
816
+ }
817
+
818
+ case OpcodeFormat::k21s: {
819
+ if (parts.size() < 2) { error = "Expected register and literal"; return false; }
820
+ int vAA;
821
+ int64_t lit;
822
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
823
+ std::string lit_str = parts[1];
824
+ if (lit_str.find("#int") != std::string::npos) {
825
+ lit_str = lit_str.substr(lit_str.find("#int") + 5);
826
+ }
827
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
828
+ insn[1] = static_cast<uint8_t>(vAA);
829
+ write_le<int16_t>(&insn[2], static_cast<int16_t>(lit));
830
+ break;
831
+ }
832
+
833
+ case OpcodeFormat::k21c: {
834
+ if (parts.size() < 2) { error = "Expected register and reference"; return false; }
835
+ int vAA;
836
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
837
+ insn[1] = static_cast<uint8_t>(vAA);
838
+
839
+ std::string ref = parts[1];
840
+ int idx = -1;
841
+
842
+ if (ref[0] == '"') {
843
+ // String literal
844
+ std::string str = ref.substr(1, ref.length() - 2);
845
+ idx = find_string(str);
846
+ if (idx < 0) { error = "String not found: " + str; return false; }
847
+ } else if (ref.find("->") != std::string::npos) {
848
+ // Field reference (Lclass;->name:type)
849
+ idx = find_field(ref);
850
+ if (idx < 0) { error = "Field not found: " + ref; return false; }
851
+ } else if (ref.find("field@") == 0) {
852
+ idx = std::stoi(ref.substr(6));
853
+ } else if (ref[0] == 'L' || ref.find("type@") == 0) {
854
+ idx = find_type(ref);
855
+ if (idx < 0) { error = "Type not found: " + ref; return false; }
856
+ } else {
857
+ idx = find_field(ref);
858
+ if (idx < 0) { error = "Reference not found: " + ref; return false; }
859
+ }
860
+ write_le<uint16_t>(&insn[2], static_cast<uint16_t>(idx));
861
+ break;
862
+ }
863
+
864
+ case OpcodeFormat::k22c: {
865
+ // vA, vB, type@CCCC or field@CCCC
866
+ if (parts.size() < 3) { error = "Expected 2 registers and reference"; return false; }
867
+ int vA, vB;
868
+ if (!parse_register(parts[0], vA) || !parse_register(parts[1], vB)) {
869
+ error = "Invalid registers"; return false;
870
+ }
871
+ insn[1] = static_cast<uint8_t>((vB << 4) | (vA & 0xF));
872
+
873
+ std::string ref = parts[2];
874
+ int idx = find_field(ref);
875
+ if (idx < 0) {
876
+ idx = find_type(ref);
877
+ }
878
+ if (idx < 0) { error = "Reference not found: " + ref; return false; }
879
+ write_le<uint16_t>(&insn[2], static_cast<uint16_t>(idx));
880
+ break;
881
+ }
882
+
883
+ case OpcodeFormat::k23x: {
884
+ // vAA, vBB, vCC
885
+ if (parts.size() < 3) { error = "Expected 3 registers"; return false; }
886
+ int vAA, vBB, vCC;
887
+ if (!parse_register(parts[0], vAA) || !parse_register(parts[1], vBB) || !parse_register(parts[2], vCC)) {
888
+ error = "Invalid registers"; return false;
889
+ }
890
+ insn[1] = static_cast<uint8_t>(vAA);
891
+ insn[2] = static_cast<uint8_t>(vBB);
892
+ insn[3] = static_cast<uint8_t>(vCC);
893
+ break;
894
+ }
895
+
896
+ case OpcodeFormat::k10t: {
897
+ // +AA (goto)
898
+ int64_t offset_val;
899
+ std::string offset_str = parts.size() > 0 ? parts[0] : "0";
900
+ if (!parse_int(offset_str, offset_val)) { error = "Invalid offset"; return false; }
901
+ insn[1] = static_cast<uint8_t>(static_cast<int8_t>(offset_val));
902
+ break;
903
+ }
904
+
905
+ case OpcodeFormat::k20t: {
906
+ // +AAAA (goto/16)
907
+ int64_t offset_val;
908
+ std::string offset_str = parts.size() > 0 ? parts[0] : "0";
909
+ if (!parse_int(offset_str, offset_val)) { error = "Invalid offset"; return false; }
910
+ write_le<int16_t>(&insn[2], static_cast<int16_t>(offset_val));
911
+ break;
912
+ }
913
+
914
+ case OpcodeFormat::k21t: {
915
+ // vAA, +BBBB (if-*z)
916
+ if (parts.size() < 2) { error = "Expected register and offset"; return false; }
917
+ int vAA;
918
+ int64_t offset_val;
919
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
920
+ if (!parse_int(parts[1], offset_val)) { error = "Invalid offset"; return false; }
921
+ insn[1] = static_cast<uint8_t>(vAA);
922
+ write_le<int16_t>(&insn[2], static_cast<int16_t>(offset_val));
923
+ break;
924
+ }
925
+
926
+ case OpcodeFormat::k21h: {
927
+ // vAA, #+BBBB0000 (const/high16, const-wide/high16)
928
+ if (parts.size() < 2) { error = "Expected register and literal"; return false; }
929
+ int vAA;
930
+ int64_t lit;
931
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
932
+ std::string lit_str = parts[1];
933
+ if (lit_str.find("#int") != std::string::npos) {
934
+ lit_str = lit_str.substr(lit_str.find("#int") + 5);
935
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
936
+ lit = lit >> 16; // Extract high 16 bits
937
+ } else if (lit_str.find("#long") != std::string::npos) {
938
+ lit_str = lit_str.substr(lit_str.find("#long") + 6);
939
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
940
+ lit = lit >> 48; // Extract high 16 bits
941
+ } else {
942
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
943
+ }
944
+ insn[1] = static_cast<uint8_t>(vAA);
945
+ write_le<int16_t>(&insn[2], static_cast<int16_t>(lit));
946
+ break;
947
+ }
948
+
949
+ case OpcodeFormat::k22b: {
950
+ // vAA, vBB, #+CC
951
+ if (parts.size() < 3) { error = "Expected 2 registers and literal"; return false; }
952
+ int vAA, vBB;
953
+ int64_t lit;
954
+ if (!parse_register(parts[0], vAA) || !parse_register(parts[1], vBB)) {
955
+ error = "Invalid registers"; return false;
956
+ }
957
+ std::string lit_str = parts[2];
958
+ if (lit_str.find("#int") != std::string::npos) {
959
+ lit_str = lit_str.substr(lit_str.find("#int") + 5);
960
+ }
961
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
962
+ insn[1] = static_cast<uint8_t>(vAA);
963
+ insn[2] = static_cast<uint8_t>(vBB);
964
+ insn[3] = static_cast<uint8_t>(static_cast<int8_t>(lit));
965
+ break;
966
+ }
967
+
968
+ case OpcodeFormat::k22t: {
969
+ // vA, vB, +CCCC (if-*)
970
+ if (parts.size() < 3) { error = "Expected 2 registers and offset"; return false; }
971
+ int vA, vB;
972
+ int64_t offset_val;
973
+ if (!parse_register(parts[0], vA) || !parse_register(parts[1], vB)) {
974
+ error = "Invalid registers"; return false;
975
+ }
976
+ if (!parse_int(parts[2], offset_val)) { error = "Invalid offset"; return false; }
977
+ insn[1] = static_cast<uint8_t>((vB << 4) | (vA & 0xF));
978
+ write_le<int16_t>(&insn[2], static_cast<int16_t>(offset_val));
979
+ break;
980
+ }
981
+
982
+ case OpcodeFormat::k22s: {
983
+ // vA, vB, #+CCCC
984
+ if (parts.size() < 3) { error = "Expected 2 registers and literal"; return false; }
985
+ int vA, vB;
986
+ int64_t lit;
987
+ if (!parse_register(parts[0], vA) || !parse_register(parts[1], vB)) {
988
+ error = "Invalid registers"; return false;
989
+ }
990
+ std::string lit_str = parts[2];
991
+ if (lit_str.find("#int") != std::string::npos) {
992
+ lit_str = lit_str.substr(lit_str.find("#int") + 5);
993
+ }
994
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
995
+ insn[1] = static_cast<uint8_t>((vB << 4) | (vA & 0xF));
996
+ write_le<int16_t>(&insn[2], static_cast<int16_t>(lit));
997
+ break;
998
+ }
999
+
1000
+ case OpcodeFormat::k22x: {
1001
+ // vAA, vBBBB
1002
+ if (parts.size() < 2) { error = "Expected 2 registers"; return false; }
1003
+ int vAA, vBBBB;
1004
+ if (!parse_register(parts[0], vAA) || !parse_register(parts[1], vBBBB)) {
1005
+ error = "Invalid registers"; return false;
1006
+ }
1007
+ insn[1] = static_cast<uint8_t>(vAA);
1008
+ write_le<uint16_t>(&insn[2], static_cast<uint16_t>(vBBBB));
1009
+ break;
1010
+ }
1011
+
1012
+ case OpcodeFormat::k32x: {
1013
+ // vAAAA, vBBBB
1014
+ if (parts.size() < 2) { error = "Expected 2 registers"; return false; }
1015
+ int vAAAA, vBBBB;
1016
+ if (!parse_register(parts[0], vAAAA) || !parse_register(parts[1], vBBBB)) {
1017
+ error = "Invalid registers"; return false;
1018
+ }
1019
+ write_le<uint16_t>(&insn[2], static_cast<uint16_t>(vAAAA));
1020
+ write_le<uint16_t>(&insn[4], static_cast<uint16_t>(vBBBB));
1021
+ break;
1022
+ }
1023
+
1024
+ case OpcodeFormat::k30t: {
1025
+ // +AAAAAAAA (goto/32)
1026
+ int64_t offset_val;
1027
+ std::string offset_str = parts.size() > 0 ? parts[0] : "0";
1028
+ if (!parse_int(offset_str, offset_val)) { error = "Invalid offset"; return false; }
1029
+ write_le<int32_t>(&insn[2], static_cast<int32_t>(offset_val));
1030
+ break;
1031
+ }
1032
+
1033
+ case OpcodeFormat::k31t: {
1034
+ // vAA, +BBBBBBBB (fill-array-data, packed-switch, sparse-switch)
1035
+ if (parts.size() < 2) { error = "Expected register and offset"; return false; }
1036
+ int vAA;
1037
+ int64_t offset_val;
1038
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
1039
+ if (!parse_int(parts[1], offset_val)) { error = "Invalid offset"; return false; }
1040
+ insn[1] = static_cast<uint8_t>(vAA);
1041
+ write_le<int32_t>(&insn[2], static_cast<int32_t>(offset_val));
1042
+ break;
1043
+ }
1044
+
1045
+ case OpcodeFormat::k31i: {
1046
+ // vAA, #+BBBBBBBB (const)
1047
+ if (parts.size() < 2) { error = "Expected register and literal"; return false; }
1048
+ int vAA;
1049
+ int64_t lit;
1050
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
1051
+ std::string lit_str = parts[1];
1052
+ if (lit_str.find("#int") != std::string::npos) {
1053
+ lit_str = lit_str.substr(lit_str.find("#int") + 5);
1054
+ }
1055
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
1056
+ insn[1] = static_cast<uint8_t>(vAA);
1057
+ write_le<int32_t>(&insn[2], static_cast<int32_t>(lit));
1058
+ break;
1059
+ }
1060
+
1061
+ case OpcodeFormat::k31c: {
1062
+ // vAA, string@BBBBBBBB (const-string/jumbo)
1063
+ if (parts.size() < 2) { error = "Expected register and string"; return false; }
1064
+ int vAA;
1065
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
1066
+
1067
+ std::string ref = parts[1];
1068
+ int idx = -1;
1069
+ if (ref[0] == '"') {
1070
+ std::string str = ref.substr(1, ref.length() - 2);
1071
+ idx = find_string(str);
1072
+ if (idx < 0) { error = "String not found: " + str; return false; }
1073
+ } else if (ref.find("string@") == 0) {
1074
+ idx = std::stoi(ref.substr(7));
1075
+ } else {
1076
+ idx = find_string(ref);
1077
+ if (idx < 0) { error = "String not found: " + ref; return false; }
1078
+ }
1079
+ insn[1] = static_cast<uint8_t>(vAA);
1080
+ write_le<uint32_t>(&insn[2], static_cast<uint32_t>(idx));
1081
+ break;
1082
+ }
1083
+
1084
+ case OpcodeFormat::k3rc: {
1085
+ // {vCCCC .. vNNNN}, method@BBBB (invoke-*/range)
1086
+ if (parts.size() < 2) { error = "Expected register range and method"; return false; }
1087
+
1088
+ std::string range_str = parts[0];
1089
+ if (range_str[0] == '{') range_str = range_str.substr(1);
1090
+ if (range_str.back() == '}') range_str = range_str.substr(0, range_str.length() - 1);
1091
+
1092
+ // Parse "vCCCC .. vNNNN" or just "vCCCC"
1093
+ int vStart = 0, vEnd = 0;
1094
+ size_t dotdot = range_str.find("..");
1095
+ if (dotdot != std::string::npos) {
1096
+ std::string start_str = range_str.substr(0, dotdot);
1097
+ std::string end_str = range_str.substr(dotdot + 2);
1098
+ size_t s = start_str.find_first_not_of(" \t");
1099
+ size_t e = start_str.find_last_not_of(" \t");
1100
+ if (s != std::string::npos) start_str = start_str.substr(s, e - s + 1);
1101
+ s = end_str.find_first_not_of(" \t");
1102
+ e = end_str.find_last_not_of(" \t");
1103
+ if (s != std::string::npos) end_str = end_str.substr(s, e - s + 1);
1104
+
1105
+ if (!parse_register(start_str, vStart) || !parse_register(end_str, vEnd)) {
1106
+ error = "Invalid register range"; return false;
1107
+ }
1108
+ } else {
1109
+ size_t s = range_str.find_first_not_of(" \t");
1110
+ size_t e = range_str.find_last_not_of(" \t");
1111
+ if (s != std::string::npos) range_str = range_str.substr(s, e - s + 1);
1112
+ if (!parse_register(range_str, vStart)) {
1113
+ error = "Invalid register"; return false;
1114
+ }
1115
+ vEnd = vStart;
1116
+ }
1117
+
1118
+ int count = vEnd - vStart + 1;
1119
+
1120
+ std::string method_ref = parts[1];
1121
+ int method_idx = find_method(method_ref);
1122
+ if (method_idx < 0) { error = "Method not found: " + method_ref; return false; }
1123
+
1124
+ insn[1] = static_cast<uint8_t>(count);
1125
+ write_le<uint16_t>(&insn[2], static_cast<uint16_t>(method_idx));
1126
+ write_le<uint16_t>(&insn[4], static_cast<uint16_t>(vStart));
1127
+ break;
1128
+ }
1129
+
1130
+ case OpcodeFormat::k51l: {
1131
+ // vAA, #+BBBBBBBBBBBBBBBB (const-wide)
1132
+ if (parts.size() < 2) { error = "Expected register and literal"; return false; }
1133
+ int vAA;
1134
+ int64_t lit;
1135
+ if (!parse_register(parts[0], vAA)) { error = "Invalid register"; return false; }
1136
+ std::string lit_str = parts[1];
1137
+ if (lit_str.find("#long") != std::string::npos) {
1138
+ lit_str = lit_str.substr(lit_str.find("#long") + 6);
1139
+ }
1140
+ if (!parse_int(lit_str, lit)) { error = "Invalid literal"; return false; }
1141
+ insn[1] = static_cast<uint8_t>(vAA);
1142
+ write_le<int64_t>(&insn[2], lit);
1143
+ break;
1144
+ }
1145
+
1146
+ case OpcodeFormat::k35c: {
1147
+ // {vC, vD, vE, vF, vG}, method@BBBB or type@BBBB
1148
+ // Format: A|G|op BBBB F|E|D|C
1149
+ if (parts.size() < 2) { error = "Expected registers and method/type"; return false; }
1150
+
1151
+ std::string regs_str = parts[0];
1152
+ if (regs_str[0] == '{') regs_str = regs_str.substr(1);
1153
+ if (regs_str.back() == '}') regs_str = regs_str.substr(0, regs_str.length() - 1);
1154
+
1155
+ std::vector<int> regs;
1156
+ std::stringstream ss(regs_str);
1157
+ std::string reg;
1158
+ while (std::getline(ss, reg, ',')) {
1159
+ size_t s = reg.find_first_not_of(" \t");
1160
+ size_t e = reg.find_last_not_of(" \t");
1161
+ if (s != std::string::npos) {
1162
+ int r;
1163
+ if (parse_register(reg.substr(s, e - s + 1), r)) {
1164
+ regs.push_back(r);
1165
+ }
1166
+ }
1167
+ }
1168
+
1169
+ std::string ref = parts[1];
1170
+ int idx = -1;
1171
+ if (op >= 0x6e && op <= 0x72) { // invoke-*
1172
+ idx = find_method(ref);
1173
+ if (idx < 0) { error = "Method not found: " + ref; return false; }
1174
+ } else { // filled-new-array
1175
+ idx = find_type(ref);
1176
+ if (idx < 0) { error = "Type not found: " + ref; return false; }
1177
+ }
1178
+
1179
+ // Encode: A|G in code[1], where A = count, G = 5th register (if any)
1180
+ uint8_t A = static_cast<uint8_t>(regs.size());
1181
+ uint8_t G = (regs.size() > 4) ? static_cast<uint8_t>(regs[4] & 0xF) : 0;
1182
+ insn[1] = static_cast<uint8_t>((A << 4) | G);
1183
+
1184
+ write_le<uint16_t>(&insn[2], static_cast<uint16_t>(idx));
1185
+
1186
+ // Encode D|C in code[4], F|E in code[5]
1187
+ uint8_t C = (regs.size() > 0) ? static_cast<uint8_t>(regs[0] & 0xF) : 0;
1188
+ uint8_t D = (regs.size() > 1) ? static_cast<uint8_t>(regs[1] & 0xF) : 0;
1189
+ uint8_t E = (regs.size() > 2) ? static_cast<uint8_t>(regs[2] & 0xF) : 0;
1190
+ uint8_t F = (regs.size() > 3) ? static_cast<uint8_t>(regs[3] & 0xF) : 0;
1191
+ insn[4] = static_cast<uint8_t>(C | (D << 4));
1192
+ insn[5] = static_cast<uint8_t>(E | (F << 4));
1193
+ break;
1194
+ }
1195
+
1196
+ default:
1197
+ error = "Unsupported instruction format for assembly: " + opcode_name;
1198
+ return false;
1199
+ }
1200
+
1201
+ bytecode.insert(bytecode.end(), insn.begin(), insn.end());
1202
+ return true;
1203
+ }
1204
+
1205
+ bool SmaliAssembler::assemble(const std::string& smali_code, std::vector<uint8_t>& bytecode, std::string& error) {
1206
+ bytecode.clear();
1207
+
1208
+ std::istringstream iss(smali_code);
1209
+ std::string line;
1210
+ int line_num = 0;
1211
+
1212
+ while (std::getline(iss, line)) {
1213
+ line_num++;
1214
+ if (!assemble_insn(line, bytecode, error)) {
1215
+ error = "Line " + std::to_string(line_num) + ": " + error;
1216
+ return false;
1217
+ }
1218
+ }
1219
+
1220
+ return true;
1221
+ }
1222
+
1223
+ } // namespace dex