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,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
|