├── LICENSE
├── common.cc
├── dex_bytecode.cc
├── dex_format.cc
├── dex_helper.cc
├── dex_helper.h
├── dex_ir.cc
├── dex_utf8.cc
├── main.cc
├── reader.cc
├── slicer
├── arrayview.h
├── buffer.h
├── chronometer.h
├── common.h
├── dex_bytecode.h
├── dex_format.h
├── dex_instruction_list.h
├── dex_ir.h
├── dex_leb128.h
├── dex_utf8.h
├── hash_table.h
├── index_map.h
├── memview.h
├── reader.h
├── scopeguard.h
└── writer.h
└── test.cc
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2022 LSPosed
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/common.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include "slicer/common.h"
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | namespace slicer {
26 |
27 | // Helper for the default SLICER_CHECK() policy
28 | void _checkFailed(const char* expr, int line, const char* file) {
29 | printf("\nSLICER_CHECK failed [%s] at %s:%d\n\n", expr, file, line);
30 | abort();
31 | }
32 |
33 | // keep track of the failures we already saw to avoid spamming with duplicates
34 | thread_local std::set> weak_failures;
35 |
36 | // Helper for the default SLICER_WEAK_CHECK() policy
37 | //
38 | // TODO: implement a modal switch (abort/continue)
39 | //
40 | void _weakCheckFailed(const char* expr, int line, const char* file) {
41 | auto failure_id = std::make_pair(line, file);
42 | if (weak_failures.find(failure_id) == weak_failures.end()) {
43 | printf("\nSLICER_WEAK_CHECK failed [%s] at %s:%d\n\n", expr, file, line);
44 | weak_failures.insert(failure_id);
45 | }
46 | }
47 |
48 | // Prints a formatted message and aborts
49 | void _fatal(const char* format, ...) {
50 | va_list args;
51 | va_start(args, format);
52 | vprintf(format, args);
53 | va_end(args);
54 | abort();
55 | }
56 |
57 | } // namespace slicer
58 |
--------------------------------------------------------------------------------
/dex_bytecode.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include "slicer/dex_bytecode.h"
18 | #include "slicer/common.h"
19 |
20 | #include
21 | #include
22 |
23 | namespace dex {
24 |
25 | Opcode OpcodeFromBytecode(u2 bytecode) {
26 | Opcode opcode = Opcode(bytecode & 0xff);
27 | return opcode;
28 | }
29 |
30 | // Table that maps each opcode to the index type implied by that opcode
31 | static constexpr std::array
32 | gInstructionDescriptors = {{
33 | #define INSTRUCTION_DESCR(o, c, p, format, index, flags, e, vflags) \
34 | { \
35 | vflags, \
36 | format, \
37 | index, \
38 | flags, \
39 | },
40 | #include "slicer/dex_instruction_list.h"
41 | DEX_INSTRUCTION_LIST(INSTRUCTION_DESCR)
42 | #undef DEX_INSTRUCTION_LIST
43 | #undef INSTRUCTION_DESCR
44 | }};
45 |
46 | InstructionIndexType GetIndexTypeFromOpcode(Opcode opcode) {
47 | return gInstructionDescriptors[opcode].index_type;
48 | }
49 |
50 | InstructionFormat GetFormatFromOpcode(Opcode opcode) {
51 | return gInstructionDescriptors[opcode].format;
52 | }
53 |
54 | OpcodeFlags GetFlagsFromOpcode(Opcode opcode) {
55 | return gInstructionDescriptors[opcode].flags;
56 | }
57 |
58 | VerifyFlags GetVerifyFlagsFromOpcode(Opcode opcode) {
59 | return gInstructionDescriptors[opcode].verify_flags;
60 | }
61 |
62 | size_t GetWidthFromFormat(InstructionFormat format) {
63 | switch (format) {
64 | case k10x:
65 | case k12x:
66 | case k11n:
67 | case k11x:
68 | case k10t:
69 | return 1;
70 | case k20t:
71 | case k20bc:
72 | case k21c:
73 | case k22x:
74 | case k21s:
75 | case k21t:
76 | case k21h:
77 | case k23x:
78 | case k22b:
79 | case k22s:
80 | case k22t:
81 | case k22c:
82 | case k22cs:
83 | return 2;
84 | case k30t:
85 | case k31t:
86 | case k31c:
87 | case k32x:
88 | case k31i:
89 | case k35c:
90 | case k35ms:
91 | case k35mi:
92 | case k3rc:
93 | case k3rms:
94 | case k3rmi:
95 | return 3;
96 | case k45cc:
97 | case k4rcc:
98 | return 4;
99 | case k51l:
100 | return 5;
101 | }
102 | }
103 |
104 | size_t GetWidthFromBytecode(const u2* bytecode) {
105 | size_t width = 0;
106 | if (*bytecode == kPackedSwitchSignature) {
107 | width = 4 + bytecode[1] * 2;
108 | } else if (*bytecode == kSparseSwitchSignature) {
109 | width = 2 + bytecode[1] * 4;
110 | } else if (*bytecode == kArrayDataSignature) {
111 | u2 elemWidth = bytecode[1];
112 | u4 len = bytecode[2] | (((u4)bytecode[3]) << 16);
113 | // The plus 1 is to round up for odd size and width.
114 | width = 4 + (elemWidth * len + 1) / 2;
115 | } else {
116 | width = GetWidthFromFormat(
117 | GetFormatFromOpcode(OpcodeFromBytecode(bytecode[0])));
118 | }
119 | return width;
120 | }
121 |
122 | // Dalvik opcode names.
123 | static constexpr std::array gOpcodeNames = {
124 | #define INSTRUCTION_NAME(o, c, pname, f, i, a, e, v) pname,
125 | #include "slicer/dex_instruction_list.h"
126 | DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
127 | #undef DEX_INSTRUCTION_LIST
128 | #undef INSTRUCTION_NAME
129 | };
130 |
131 | const char* GetOpcodeName(Opcode opcode) { return gOpcodeNames[opcode]; }
132 |
133 | // Helpers for DecodeInstruction()
134 | static u4 InstA(u2 inst) { return (inst >> 8) & 0x0f; }
135 | static u4 InstB(u2 inst) { return inst >> 12; }
136 | static u4 InstAA(u2 inst) { return inst >> 8; }
137 |
138 | // Helper for DecodeInstruction()
139 | static u4 FetchU4(const u2* ptr) { return ptr[0] | (u4(ptr[1]) << 16); }
140 |
141 | // Helper for DecodeInstruction()
142 | static u8 FetchU8(const u2* ptr) {
143 | return FetchU4(ptr) | (u8(FetchU4(ptr + 2)) << 32);
144 | }
145 |
146 | // Decode a Dalvik bytecode and extract the individual fields
147 | Instruction DecodeInstruction(const u2* bytecode) {
148 | u2 inst = bytecode[0];
149 | Opcode opcode = OpcodeFromBytecode(inst);
150 | InstructionFormat format = GetFormatFromOpcode(opcode);
151 |
152 | Instruction dec = {};
153 | dec.opcode = opcode;
154 |
155 | switch (format) {
156 | case k10x: // op
157 | return dec;
158 | case k12x: // op vA, vB
159 | dec.vA = InstA(inst);
160 | dec.vB = InstB(inst);
161 | return dec;
162 | case k11n: // op vA, #+B
163 | dec.vA = InstA(inst);
164 | dec.vB = s4(InstB(inst) << 28) >> 28; // sign extend 4-bit value
165 | return dec;
166 | case k11x: // op vAA
167 | dec.vA = InstAA(inst);
168 | return dec;
169 | case k10t: // op +AA
170 | dec.vA = s1(InstAA(inst)); // sign-extend 8-bit value
171 | return dec;
172 | case k20t: // op +AAAA
173 | dec.vA = s2(bytecode[1]); // sign-extend 16-bit value
174 | return dec;
175 | case k20bc: // [opt] op AA, thing@BBBB
176 | case k21c: // op vAA, thing@BBBB
177 | case k22x: // op vAA, vBBBB
178 | dec.vA = InstAA(inst);
179 | dec.vB = bytecode[1];
180 | return dec;
181 | case k21s: // op vAA, #+BBBB
182 | case k21t: // op vAA, +BBBB
183 | dec.vA = InstAA(inst);
184 | dec.vB = s2(bytecode[1]); // sign-extend 16-bit value
185 | return dec;
186 | case k21h: // op vAA, #+BBBB0000[00000000]
187 | dec.vA = InstAA(inst);
188 | // The value should be treated as right-zero-extended, but we don't
189 | // actually do that here. Among other things, we don't know if it's
190 | // the top bits of a 32- or 64-bit value.
191 | dec.vB = bytecode[1];
192 | return dec;
193 | case k23x: // op vAA, vBB, vCC
194 | dec.vA = InstAA(inst);
195 | dec.vB = bytecode[1] & 0xff;
196 | dec.vC = bytecode[1] >> 8;
197 | return dec;
198 | case k22b: // op vAA, vBB, #+CC
199 | dec.vA = InstAA(inst);
200 | dec.vB = bytecode[1] & 0xff;
201 | dec.vC = s1(bytecode[1] >> 8); // sign-extend 8-bit value
202 | return dec;
203 | case k22s: // op vA, vB, #+CCCC
204 | case k22t: // op vA, vB, +CCCC
205 | dec.vA = InstA(inst);
206 | dec.vB = InstB(inst);
207 | dec.vC = s2(bytecode[1]); // sign-extend 16-bit value
208 | return dec;
209 | case k22c: // op vA, vB, thing@CCCC
210 | case k22cs: // [opt] op vA, vB, field offset CCCC
211 | dec.vA = InstA(inst);
212 | dec.vB = InstB(inst);
213 | dec.vC = bytecode[1];
214 | return dec;
215 | case k30t: // op +AAAAAAAA
216 | dec.vA = FetchU4(bytecode + 1);
217 | return dec;
218 | case k31t: // op vAA, +BBBBBBBB
219 | case k31c: // op vAA, string@BBBBBBBB
220 | dec.vA = InstAA(inst);
221 | dec.vB = FetchU4(bytecode + 1);
222 | return dec;
223 | case k32x: // op vAAAA, vBBBB
224 | dec.vA = bytecode[1];
225 | dec.vB = bytecode[2];
226 | return dec;
227 | case k31i: // op vAA, #+BBBBBBBB
228 | dec.vA = InstAA(inst);
229 | dec.vB = FetchU4(bytecode + 1);
230 | return dec;
231 | case k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
232 | case k35ms: // [opt] invoke-virtual+super
233 | case k35mi: { // [opt] inline invoke
234 | dec.vA = InstB(inst); // This is labeled A in the spec.
235 | dec.vB = bytecode[1];
236 |
237 | u2 regList = bytecode[2];
238 |
239 | // Copy the argument registers into the arg[] array, and
240 | // also copy the first argument (if any) into vC. (The
241 | // Instruction structure doesn't have separate
242 | // fields for {vD, vE, vF, vG}, so there's no need to make
243 | // copies of those.) Note that cases 5..2 fall through.
244 | switch (dec.vA) {
245 | case 5:
246 | // A fifth arg is verboten for inline invokes
247 | SLICER_CHECK(format != k35mi);
248 |
249 | // Per note at the top of this format decoder, the
250 | // fifth argument comes from the A field in the
251 | // instruction, but it's labeled G in the spec.
252 | dec.arg[4] = InstA(inst);
253 | FALLTHROUGH_INTENDED;
254 | case 4:
255 | dec.arg[3] = (regList >> 12) & 0x0f;
256 | FALLTHROUGH_INTENDED;
257 | case 3:
258 | dec.arg[2] = (regList >> 8) & 0x0f;
259 | FALLTHROUGH_INTENDED;
260 | case 2:
261 | dec.arg[1] = (regList >> 4) & 0x0f;
262 | FALLTHROUGH_INTENDED;
263 | case 1:
264 | dec.vC = dec.arg[0] = regList & 0x0f;
265 | FALLTHROUGH_INTENDED;
266 | case 0:
267 | // Valid, but no need to do anything
268 | return dec;
269 | }
270 | }
271 | SLICER_CHECK(!"Invalid arg count in 35c/35ms/35mi");
272 | case k3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
273 | case k3rms: // [opt] invoke-virtual+super/range
274 | case k3rmi: // [opt] execute-inline/range
275 | dec.vA = InstAA(inst);
276 | dec.vB = bytecode[1];
277 | dec.vC = bytecode[2];
278 | return dec;
279 | case k45cc: {
280 | // AG op BBBB FEDC HHHH
281 | dec.vA = InstB(inst); // This is labelled A in the spec.
282 | dec.vB = bytecode[1]; // vB meth@BBBB
283 |
284 | u2 regList = bytecode[2];
285 | dec.vC = regList & 0xf;
286 | dec.arg[0] = (regList >> 4) & 0xf; // vD
287 | dec.arg[1] = (regList >> 8) & 0xf; // vE
288 | dec.arg[2] = (regList >> 12); // vF
289 | dec.arg[3] = InstA(inst); // vG
290 | dec.arg[4] = bytecode[3]; // vH proto@HHHH
291 | }
292 | return dec;
293 | case k4rcc:
294 | // AA op BBBB CCCC HHHH
295 | dec.vA = InstAA(inst);
296 | dec.vB = bytecode[1];
297 | dec.vC = bytecode[2];
298 | dec.arg[4] = bytecode[3]; // vH proto@HHHH
299 | return dec;
300 | case k51l: // op vAA, #+BBBBBBBBBBBBBBBB
301 | dec.vA = InstAA(inst);
302 | dec.vB_wide = FetchU8(bytecode + 1);
303 | return dec;
304 | }
305 | SLICER_FATAL("Can't decode unexpected format 0x%02x (op=0x%02x)", format,
306 | opcode);
307 | }
308 |
309 | } // namespace dex
310 |
--------------------------------------------------------------------------------
/dex_format.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include "slicer/dex_format.h"
18 | #include "slicer/common.h"
19 |
20 | #include
21 |
22 | namespace dex {
23 |
24 | // Compute the DEX file checksum for a memory-mapped DEX file
25 | u4 ComputeChecksum(const Header* header) {
26 | const u1* start = reinterpret_cast(header);
27 |
28 | uLong adler = adler32(0L, Z_NULL, 0);
29 | const int non_sum = sizeof(header->magic) + sizeof(header->checksum);
30 |
31 | return static_cast(
32 | adler32(adler, start + non_sum, header->file_size - non_sum));
33 | }
34 |
35 | // Returns the human-readable name for a primitive type
36 | static const char* PrimitiveTypeName(char type_char) {
37 | switch (type_char) {
38 | case 'B': return "byte";
39 | case 'C': return "char";
40 | case 'D': return "double";
41 | case 'F': return "float";
42 | case 'I': return "int";
43 | case 'J': return "long";
44 | case 'S': return "short";
45 | case 'V': return "void";
46 | case 'Z': return "boolean";
47 | }
48 | SLICER_CHECK(!"unexpected type");
49 | return nullptr;
50 | }
51 |
52 | // Converts a type descriptor to human-readable "dotted" form. For
53 | // example, "Ljava/lang/String;" becomes "java.lang.String", and
54 | // "[I" becomes "int[]".
55 | std::string DescriptorToDecl(const char* descriptor) {
56 | std::string ss;
57 |
58 | int array_dimensions = 0;
59 | while (*descriptor == '[') {
60 | ++array_dimensions;
61 | ++descriptor;
62 | }
63 |
64 | if (*descriptor == 'L') {
65 | for (++descriptor; *descriptor != ';'; ++descriptor) {
66 | SLICER_CHECK(*descriptor != '\0');
67 | ss += (*descriptor == '/' ? '.' : *descriptor);
68 | }
69 | } else {
70 | ss += PrimitiveTypeName(*descriptor);
71 | }
72 |
73 | SLICER_CHECK(descriptor[1] == '\0');
74 |
75 | // add the array brackets
76 | for (int i = 0; i < array_dimensions; ++i) {
77 | ss += "[]";
78 | }
79 |
80 | return ss;
81 | }
82 |
83 | // Converts a type descriptor to a single "shorty" char
84 | // (ex. "LFoo;" and "[[I" become 'L', "I" stays 'I')
85 | char DescriptorToShorty(const char* descriptor) {
86 | // skip array dimensions
87 | int array_dimensions = 0;
88 | while (*descriptor == '[') {
89 | ++array_dimensions;
90 | ++descriptor;
91 | }
92 |
93 | char short_descriptor = *descriptor;
94 | if (short_descriptor == 'L') {
95 | // skip the full class name
96 | for(; *descriptor && *descriptor != ';'; ++descriptor);
97 | SLICER_CHECK(*descriptor == ';');
98 | }
99 |
100 | SLICER_CHECK(descriptor[1] == '\0');
101 | SLICER_CHECK(short_descriptor == 'L' || PrimitiveTypeName(short_descriptor) != nullptr);
102 |
103 | return array_dimensions > 0 ? 'L' : short_descriptor;
104 | }
105 |
106 | } // namespace dex
107 |
--------------------------------------------------------------------------------
/dex_helper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "slicer/reader.h"
4 | #include
5 | #include
6 | #include
7 |
8 | class DexHelper {
9 | public:
10 | DexHelper(const std::vector> &dexs);
11 | void CreateFullCache() const;
12 | std::vector FindMethodUsingString(
13 | std::string_view str, bool match_prefix, size_t return_type,
14 | short parameter_count, std::string_view parameter_shorty,
15 | size_t declaring_class, const std::vector ¶meter_types,
16 | const std::vector &contains_parameter_types,
17 | const std::vector &dex_priority, bool find_first) const;
18 |
19 | std::vector FindMethodInvoking(
20 | size_t method_idx, size_t return_type, short parameter_count,
21 | std::string_view parameter_shorty, size_t declaring_class,
22 | const std::vector ¶meter_types,
23 | const std::vector &contains_parameter_types,
24 | const std::vector &dex_priority, bool find_first) const;
25 |
26 | std::vector FindMethodInvoked(
27 | size_t method_idx, size_t return_type, short parameter_count,
28 | std::string_view parameter_shorty, size_t declaring_class,
29 | const std::vector ¶meter_types,
30 | const std::vector &contains_parameter_types,
31 | const std::vector &dex_priority, bool find_first) const;
32 |
33 | std::vector FindMethodGettingField(
34 | size_t field_idx, size_t return_type, short parameter_count,
35 | std::string_view parameter_shorty, size_t declaring_class,
36 | const std::vector ¶meter_types,
37 | const std::vector &contains_parameter_types,
38 | const std::vector &dex_priority, bool find_first) const;
39 |
40 | std::vector FindMethodSettingField(
41 | size_t field_idx, size_t return_type, short parameter_count,
42 | std::string_view parameter_shorty, size_t declaring_class,
43 | const std::vector ¶meter_types,
44 | const std::vector &contains_parameter_types,
45 | const std::vector &dex_priority, bool find_first) const;
46 |
47 | std::vector FindField(size_t type,
48 | const std::vector &dex_priority,
49 | bool find_first) const;
50 |
51 | struct Class {
52 | const std::string_view name;
53 | };
54 | struct Field {
55 | const Class declaring_class;
56 | const Class type;
57 | const std::string_view name;
58 | };
59 | struct Method {
60 | const Class declaring_class;
61 | const std::string_view name;
62 | const std::vector parameters;
63 | const Class return_type;
64 | };
65 |
66 | size_t CreateClassIndex(std::string_view class_name,
67 | size_t on_dex = -1) const;
68 | size_t CreateMethodIndex(std::string_view class_name,
69 | std::string_view method_name,
70 | const std::vector ¶ms_name,
71 | size_t on_dex = -1) const;
72 | size_t CreateFieldIndex(std::string_view class_name,
73 | std::string_view field_name,
74 | size_t on_dex = -1) const;
75 |
76 | Class DecodeClass(size_t class_idx) const;
77 | Field DecodeField(size_t field_idx) const;
78 | Method DecodeMethod(size_t method_idx) const;
79 |
80 | private:
81 | std::tuple>,
82 | std::vector>>
83 | ConvertParameters(const std::vector ¶meter_types,
84 | const std::vector &contains_parameter_types) const;
85 |
86 | std::vector GetPriority(const std::vector &priority) const;
87 |
88 | bool ScanMethod(size_t dex_idx, uint32_t method_id,
89 | size_t str_lower = size_t(-1),
90 | size_t str_upper = size_t(-1)) const;
91 |
92 | std::tuple
93 | FindPrefixStringId(size_t dex_idx, std::string_view to_find) const;
94 |
95 | uint32_t FindPrefixStringIdExact(size_t dex_idx,
96 | std::string_view to_find) const;
97 |
98 | bool
99 | IsMethodMatch(size_t dex_id, uint32_t method_id, uint32_t return_type,
100 | short parameter_count, std::string_view parameter_shorty,
101 | uint32_t declaring_class,
102 | const std::vector ¶meter_types,
103 | const std::vector &contains_parameter_types) const;
104 |
105 | size_t CreateMethodIndex(size_t dex_idx, uint32_t method_id) const;
106 | size_t CreateClassIndex(size_t dex_idx, uint32_t class_id) const;
107 | size_t CreateFieldIndex(size_t dex_idx, uint32_t field_id) const;
108 |
109 | std::vector readers_;
110 |
111 | // for interface
112 | // indices[method_index][dex] -> id
113 | mutable std::vector> method_indices_;
114 | mutable std::vector> class_indices_;
115 | mutable std::vector> field_indices_;
116 | // rev[dex][method_id] -> method_index
117 | mutable std::vector> rev_method_indices_; // for each dex
118 | mutable std::vector> rev_class_indices_;
119 | mutable std::vector> rev_field_indices_;
120 |
121 | // for preprocess
122 | // strings[dex][str_id] -> str
123 | std::vector> strings_;
124 | // method_codes[dex][method_id] -> code
125 | std::vector> method_codes_;
126 | std::vector> method_params_;
127 |
128 | // for cache
129 | // type_cache[dex][str_id] -> type_id
130 | std::vector> type_cache_;
131 | // field_cache[dex][type_id][str_id] -> method_ids
132 | std::vector>>>
133 | method_cache_;
134 | // field_cache[dex][type_id][str_id] -> field_id
135 | std::vector>> field_cache_;
136 | // class_cache[dex][type_id] -> class_id
137 | std::vector> class_cache_;
138 |
139 | // search result cache
140 | // string_cache[dex][str_id] -> method_ids
141 | mutable std::vector>> string_cache_;
142 | // invoking_cache[dex][method_id] -> method_ids
143 | mutable std::vector>> invoking_cache_;
144 | // invoked_cache[dex][method_id] -> method_ids
145 | mutable std::vector>> invoked_cache_;
146 | // getting/setting_cache[dex][field_id] -> method_ids
147 | mutable std::vector>> getting_cache_;
148 | mutable std::vector>> setting_cache_;
149 | mutable std::vector>> declaring_cache_;
150 | // for method search
151 | mutable std::vector> searched_methods_;
152 |
153 | constexpr static uint8_t opcode_len[] = {
154 | 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3,
155 | 5, 2, 2, 3, 2, 1, 1, 2, 2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2,
156 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
157 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
158 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3,
159 | 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
160 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
161 | 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
162 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
163 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
164 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 3, 3, 2, 2};
165 | static_assert(sizeof(opcode_len) == 256);
166 | };
167 |
--------------------------------------------------------------------------------
/dex_ir.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #include "slicer/dex_ir.h"
18 | #include "slicer/chronometer.h"
19 | #include "slicer/dex_utf8.h"
20 | #include "slicer/dex_format.h"
21 |
22 | #include
23 | #include
24 | #include