• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012, Google LLC
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google LLC nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 package com.android.tools.smali.dexlib2.dexbacked;
32 
33 import com.android.tools.smali.util.ExceptionWithContext;
34 import com.android.tools.smali.util.Utf8Utils;
35 
36 import javax.annotation.Nonnull;
37 
38 public class DexReader<T extends DexBuffer> {
39     @Nonnull public final T dexBuf;
40     private int offset;
41 
DexReader(@onnull T dexBuf, int offset)42     public DexReader(@Nonnull T dexBuf, int offset) {
43         this.dexBuf = dexBuf;
44         this.offset = offset;
45     }
46 
getOffset()47     public int getOffset() { return offset; }
setOffset(int offset)48     public void setOffset(int offset) { this.offset = offset; }
49 
readSleb128()50     public int readSleb128() {
51         int end = dexBuf.baseOffset + offset;
52         int currentByteValue;
53         int result;
54         byte[] buf = dexBuf.buf;
55 
56         result = buf[end++] & 0xff;
57         if (result <= 0x7f) {
58             result = (result << 25) >> 25;
59         } else {
60             currentByteValue = buf[end++] & 0xff;
61             result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
62             if (currentByteValue <= 0x7f) {
63                 result = (result << 18) >> 18;
64             } else {
65                 currentByteValue = buf[end++] & 0xff;
66                 result |= (currentByteValue & 0x7f) << 14;
67                 if (currentByteValue <= 0x7f) {
68                     result = (result << 11) >> 11;
69                 } else {
70                     currentByteValue = buf[end++] & 0xff;
71                     result |= (currentByteValue & 0x7f) << 21;
72                     if (currentByteValue <= 0x7f) {
73                         result = (result << 4) >> 4;
74                     } else {
75                         currentByteValue = buf[end++] & 0xff;
76                         if (currentByteValue > 0x7f) {
77                             throw new ExceptionWithContext(
78                                     "Invalid sleb128 integer encountered at offset 0x%x", offset);
79                         }
80                         result |= currentByteValue << 28;
81                     }
82                 }
83             }
84         }
85 
86         offset = end - dexBuf.baseOffset;
87         return result;
88     }
89 
peekSleb128Size()90     public int peekSleb128Size() {
91         int end = dexBuf.baseOffset + offset;
92         int currentByteValue;
93         int result;
94         byte[] buf = dexBuf.buf;
95 
96         result = buf[end++] & 0xff;
97         if (result > 0x7f) {
98             currentByteValue = buf[end++] & 0xff;
99             if (currentByteValue > 0x7f) {
100                 currentByteValue = buf[end++] & 0xff;
101                 if (currentByteValue > 0x7f) {
102                     currentByteValue = buf[end++] & 0xff;
103                     if (currentByteValue > 0x7f) {
104                         currentByteValue = buf[end++] & 0xff;
105                         if (currentByteValue > 0x7f) {
106                             throw new ExceptionWithContext(
107                                 "Invalid sleb128 integer encountered at offset 0x%x", offset);
108                         }
109                     }
110                 }
111             }
112         }
113 
114         return end - (dexBuf.baseOffset + offset);
115     }
116 
readSmallUleb128()117     public int readSmallUleb128() {
118         return readUleb128(false);
119     }
120 
peekSmallUleb128Size()121     public int peekSmallUleb128Size() {
122         return peekUleb128Size(false);
123     }
124 
readUleb128(boolean allowLarge)125     private int readUleb128(boolean allowLarge) {
126         int end = dexBuf.baseOffset + offset;
127         int currentByteValue;
128         int result;
129         byte[] buf = dexBuf.buf;
130 
131         result = buf[end++] & 0xff;
132         if (result > 0x7f) {
133             currentByteValue = buf[end++] & 0xff;
134             result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
135             if (currentByteValue > 0x7f) {
136                 currentByteValue = buf[end++] & 0xff;
137                 result |= (currentByteValue & 0x7f) << 14;
138                 if (currentByteValue > 0x7f) {
139                     currentByteValue = buf[end++] & 0xff;
140                     result |= (currentByteValue & 0x7f) << 21;
141                     if (currentByteValue > 0x7f) {
142                         currentByteValue = buf[end++];
143 
144                         // MSB shouldn't be set on last byte
145                         if (currentByteValue < 0) {
146                             throw new ExceptionWithContext(
147                                     "Invalid uleb128 integer encountered at offset 0x%x", offset);
148                         } else if ((currentByteValue & 0xf) > 0x07) {
149                             if (!allowLarge) {
150                                 // for non-large uleb128s, we assume most significant bit of the result will not be
151                                 // set, so that it can fit into a signed integer without wrapping
152                                 throw new ExceptionWithContext(
153                                         "Encountered valid uleb128 that is out of range at offset 0x%x", offset);
154                             }
155                         }
156                         result |= currentByteValue << 28;
157                     }
158                 }
159             }
160         }
161 
162         offset = end - dexBuf.baseOffset;
163         return result;
164     }
165 
peekUleb128Size(boolean allowLarge)166     private int peekUleb128Size(boolean allowLarge) {
167         int end = dexBuf.baseOffset + offset;
168         int currentByteValue;
169         int result;
170         byte[] buf = dexBuf.buf;
171 
172         result = buf[end++] & 0xff;
173         if (result > 0x7f) {
174             currentByteValue = buf[end++] & 0xff;
175             if (currentByteValue > 0x7f) {
176                 currentByteValue = buf[end++] & 0xff;
177                 if (currentByteValue > 0x7f) {
178                     currentByteValue = buf[end++] & 0xff;
179                     if (currentByteValue > 0x7f) {
180                         currentByteValue = buf[end++];
181 
182                         // MSB shouldn't be set on last byte
183                         if (currentByteValue < 0) {
184                             throw new ExceptionWithContext(
185                                 "Invalid uleb128 integer encountered at offset 0x%x", offset);
186                         } else if ((currentByteValue & 0xf) > 0x07) {
187                             if (!allowLarge) {
188                                 // for non-large uleb128s, we assume most significant bit of the result will not be
189                                 // set, so that it can fit into a signed integer without wrapping
190                                 throw new ExceptionWithContext(
191                                     "Encountered valid uleb128 that is out of range at offset 0x%x", offset);
192                             }
193                         }
194                     }
195                 }
196             }
197         }
198 
199         return end - (dexBuf.baseOffset + offset);
200     }
201 
202 
203     /**
204      * Reads a "large" uleb128. That is, one that may legitimately be greater than a signed int.
205      *
206      * The value is returned as if it were signed. i.e. a value of 0xFFFFFFFF would be returned as -1. It is up to the
207      * caller to handle the value appropriately.
208      */
readLargeUleb128()209     public int readLargeUleb128() {
210        return readUleb128(true);
211     }
212 
213     /**
214      * Reads a "big" uleb128 that can legitimately be > 2^31. The value is returned as a signed integer, with the
215      * expected semantics of re-interpreting an unsigned value as a signed value.
216      *
217      * @return The unsigned value, reinterpreted as a signed int
218      */
readBigUleb128()219     public int readBigUleb128() {
220         int end = dexBuf.baseOffset + offset;
221         int currentByteValue;
222         int result;
223         byte[] buf = dexBuf.buf;
224 
225         result = buf[end++] & 0xff;
226         if (result > 0x7f) {
227             currentByteValue = buf[end++] & 0xff;
228             result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
229             if (currentByteValue > 0x7f) {
230                 currentByteValue = buf[end++] & 0xff;
231                 result |= (currentByteValue & 0x7f) << 14;
232                 if (currentByteValue > 0x7f) {
233                     currentByteValue = buf[end++] & 0xff;
234                     result |= (currentByteValue & 0x7f) << 21;
235                     if (currentByteValue > 0x7f) {
236                         currentByteValue = buf[end++];
237 
238                         // MSB shouldn't be set on last byte
239                         if (currentByteValue < 0) {
240                             throw new ExceptionWithContext(
241                                     "Invalid uleb128 integer encountered at offset 0x%x", offset);
242                         }
243                         result |= currentByteValue << 28;
244                     }
245                 }
246             }
247         }
248 
249         offset = end - dexBuf.baseOffset;
250         return result;
251     }
252 
peekBigUleb128Size()253     public int peekBigUleb128Size() {
254         int end = dexBuf.baseOffset + offset;
255         int currentByteValue;
256         int result;
257         byte[] buf = dexBuf.buf;
258 
259         result = buf[end++] & 0xff;
260         if (result > 0x7f) {
261             currentByteValue = buf[end++] & 0xff;
262             if (currentByteValue > 0x7f) {
263                 currentByteValue = buf[end++] & 0xff;
264                 if (currentByteValue > 0x7f) {
265                     currentByteValue = buf[end++] & 0xff;
266                     if (currentByteValue > 0x7f) {
267                         currentByteValue = buf[end++];
268 
269                         // MSB shouldn't be set on last byte
270                         if (currentByteValue < 0) {
271                             throw new ExceptionWithContext(
272                                 "Invalid uleb128 integer encountered at offset 0x%x", offset);
273                         }
274                     }
275                 }
276             }
277         }
278 
279         return end - (dexBuf.baseOffset + offset);
280     }
281 
skipUleb128()282     public void skipUleb128() {
283         int end = dexBuf.baseOffset + offset;
284         byte currentByteValue;
285         byte[] buf = dexBuf.buf;
286 
287         currentByteValue = buf[end++];
288         if (currentByteValue < 0) { // if the MSB is set
289             currentByteValue = buf[end++];
290             if (currentByteValue < 0) { // if the MSB is set
291                 currentByteValue = buf[end++];
292                 if (currentByteValue < 0) { // if the MSB is set
293                     currentByteValue = buf[end++];
294                     if (currentByteValue < 0) { // if the MSB is set
295                         currentByteValue = buf[end++];
296                         if (currentByteValue < 0) {
297                             throw new ExceptionWithContext(
298                                     "Invalid uleb128 integer encountered at offset 0x%x", offset);
299                         }
300                     }
301                 }
302             }
303         }
304 
305         offset = end - dexBuf.baseOffset;
306     }
307 
readSmallUint()308     public int readSmallUint() {
309         int o = offset;
310         int result = dexBuf.readSmallUint(o);
311         offset = o + 4;
312         return result;
313     }
314 
readOptionalUint()315     public int readOptionalUint() {
316         int o = offset;
317         int result = dexBuf.readOptionalUint(o);
318         offset = o + 4;
319         return result;
320     }
321 
peekUshort()322     public int peekUshort() {
323         return dexBuf.readUshort(offset);
324     }
325 
readUshort()326     public int readUshort() {
327         int o = offset;
328         int result = dexBuf.readUshort(offset);
329         offset = o + 2;
330         return result;
331     }
332 
peekUbyte()333     public int peekUbyte() {
334         return dexBuf.readUbyte(offset);
335     }
336 
readUbyte()337     public int readUbyte() {
338         int o = offset;
339         int result = dexBuf.readUbyte(offset);
340         offset = o + 1;
341         return result;
342     }
343 
readLong()344     public long readLong() {
345         int o = offset;
346         long result = dexBuf.readLong(offset);
347         offset = o + 8;
348         return result;
349     }
350 
readInt()351     public int readInt() {
352         int o = offset;
353         int result = dexBuf.readInt(offset);
354         offset = o + 4;
355         return result;
356     }
357 
readShort()358     public int readShort() {
359         int o = offset;
360         int result = dexBuf.readShort(offset);
361         offset = o + 2;
362         return result;
363     }
364 
readByte()365     public int readByte() {
366         int o = offset;
367         int result = dexBuf.readByte(offset);
368         offset = o + 1;
369         return result;
370     }
371 
skipByte()372     public void skipByte() { offset++; }
moveRelative(int i)373     public void moveRelative(int i) { offset += i; }
374 
readSmallUint(int offset)375     public int readSmallUint(int offset) { return dexBuf.readSmallUint(offset); }
readUshort(int offset)376     public int readUshort(int offset) { return dexBuf.readUshort(offset); }
readUbyte(int offset)377     public int readUbyte(int offset) { return dexBuf.readUbyte(offset); }
readLong(int offset)378     public long readLong(int offset) { return dexBuf.readLong(offset); }
readInt(int offset)379     public int readInt(int offset) { return dexBuf.readInt(offset); }
readShort(int offset)380     public int readShort(int offset) { return dexBuf.readShort(offset); }
readByte(int offset)381     public int readByte(int offset) { return dexBuf.readByte(offset); }
382 
readSizedInt(int bytes)383     public int readSizedInt(int bytes) {
384         int o = dexBuf.baseOffset + offset;
385         byte[] buf = dexBuf.buf;
386 
387         int result;
388         switch (bytes) {
389             case 4:
390                 result = (buf[o] & 0xff) |
391                         ((buf[o+1] & 0xff) << 8) |
392                         ((buf[o+2] & 0xff) << 16) |
393                         (buf[o+3] << 24);
394                 break;
395             case 3:
396                 result = (buf[o] & 0xff) |
397                         ((buf[o+1] & 0xff) << 8) |
398                         ((buf[o+2]) << 16);
399                 break;
400             case 2:
401                 result = (buf[o] & 0xff) |
402                         ((buf[o+1]) << 8);
403                 break;
404             case 1:
405                 result = buf[o];
406                 break;
407             default:
408                 throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
409         }
410         offset = o + bytes - dexBuf.baseOffset;
411         return result;
412     }
413 
readSizedSmallUint(int bytes)414     public int readSizedSmallUint(int bytes) {
415         int o = dexBuf.baseOffset + offset;
416         byte[] buf = dexBuf.buf;
417 
418         int result = 0;
419         switch (bytes) {
420             case 4:
421                 int b = buf[o+3];
422                 if (b < 0) {
423                     throw new ExceptionWithContext(
424                             "Encountered valid sized uint that is out of range at offset 0x%x", offset);
425                 }
426                 result = b << 24;
427                 // fall-through
428             case 3:
429                 result |= (buf[o+2] & 0xff) << 16;
430                 // fall-through
431             case 2:
432                 result |= (buf[o+1] & 0xff) << 8;
433                 // fall-through
434             case 1:
435                 result |= (buf[o] & 0xff);
436                 break;
437             default:
438                 throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
439         }
440         offset = o + bytes - dexBuf.baseOffset;
441         return result;
442     }
443 
readSizedRightExtendedInt(int bytes)444     public int readSizedRightExtendedInt(int bytes) {
445         int o = dexBuf.baseOffset + offset;
446         byte[] buf = dexBuf.buf;
447 
448         int result;
449         switch (bytes) {
450             case 4:
451                 result = (buf[o] & 0xff) |
452                         ((buf[o+1] & 0xff) << 8) |
453                         ((buf[o+2] & 0xff) << 16) |
454                         (buf[o+3] << 24);
455                 break;
456             case 3:
457                 result = (buf[o] & 0xff) << 8 |
458                         ((buf[o+1] & 0xff) << 16) |
459                         (buf[o+2] << 24);
460                 break;
461             case 2:
462                 result = (buf[o] & 0xff) << 16 |
463                         (buf[o+1] << 24);
464                 break;
465             case 1:
466                 result = buf[o] << 24;
467                 break;
468             default:
469                 throw new ExceptionWithContext(
470                         "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
471         }
472         offset = o + bytes - dexBuf.baseOffset;
473         return result;
474     }
475 
readSizedRightExtendedLong(int bytes)476     public long readSizedRightExtendedLong(int bytes) {
477         int o = dexBuf.baseOffset + offset;
478         byte[] buf = dexBuf.buf;
479 
480         long result;
481         switch (bytes) {
482             case 8:
483                 result = (buf[o] & 0xff) |
484                         ((buf[o+1] & 0xff) << 8) |
485                         ((buf[o+2] & 0xff) << 16) |
486                         ((buf[o+3] & 0xffL) << 24) |
487                         ((buf[o+4] & 0xffL) << 32) |
488                         ((buf[o+5] & 0xffL) << 40) |
489                         ((buf[o+6] & 0xffL) << 48) |
490                         (((long)buf[o+7]) << 56);
491                 break;
492             case 7:
493                 result = ((buf[o] & 0xff)) << 8 |
494                         ((buf[o+1] & 0xff) << 16) |
495                         ((buf[o+2] & 0xffL) << 24) |
496                         ((buf[o+3] & 0xffL) << 32) |
497                         ((buf[o+4] & 0xffL) << 40) |
498                         ((buf[o+5] & 0xffL) << 48) |
499                         (((long)buf[o+6]) << 56);
500                 break;
501             case 6:
502                 result = ((buf[o] & 0xff)) << 16 |
503                         ((buf[o+1] & 0xffL) << 24) |
504                         ((buf[o+2] & 0xffL) << 32) |
505                         ((buf[o+3] & 0xffL) << 40) |
506                         ((buf[o+4] & 0xffL) << 48) |
507                         (((long)buf[o+5]) << 56);
508                 break;
509             case 5:
510                 result = ((buf[o] & 0xffL)) << 24 |
511                         ((buf[o+1] & 0xffL) << 32) |
512                         ((buf[o+2] & 0xffL) << 40) |
513                         ((buf[o+3] & 0xffL) << 48) |
514                         (((long)buf[o+4]) << 56);
515                 break;
516             case 4:
517                 result = ((buf[o] & 0xffL)) << 32 |
518                         ((buf[o+1] & 0xffL) << 40) |
519                         ((buf[o+2] & 0xffL) << 48) |
520                         (((long)buf[o+3]) << 56);
521                 break;
522             case 3:
523                 result = ((buf[o] & 0xffL)) << 40 |
524                         ((buf[o+1] & 0xffL) << 48) |
525                         (((long)buf[o+2]) << 56);
526                 break;
527             case 2:
528                 result = ((buf[o] & 0xffL)) << 48 |
529                         (((long)buf[o+1]) << 56);
530                 break;
531             case 1:
532                 result = ((long)buf[o]) << 56;
533                 break;
534             default:
535                 throw new ExceptionWithContext(
536                         "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
537         }
538         offset = o + bytes - dexBuf.baseOffset;
539         return result;
540     }
541 
readSizedLong(int bytes)542     public long readSizedLong(int bytes) {
543         int o = dexBuf.baseOffset + offset;
544         byte[] buf = dexBuf.buf;
545 
546         long result;
547         switch (bytes) {
548             case 8:
549                 result = (buf[o] & 0xff) |
550                         ((buf[o+1] & 0xff) << 8) |
551                         ((buf[o+2] & 0xff) << 16) |
552                         ((buf[o+3] & 0xffL) << 24) |
553                         ((buf[o+4] & 0xffL) << 32) |
554                         ((buf[o+5] & 0xffL) << 40) |
555                         ((buf[o+6] & 0xffL) << 48) |
556                         (((long)buf[o+7]) << 56);
557                 break;
558             case 7:
559                 result = (buf[o] & 0xff) |
560                         ((buf[o+1] & 0xff) << 8) |
561                         ((buf[o+2] & 0xff) << 16) |
562                         ((buf[o+3] & 0xffL) << 24) |
563                         ((buf[o+4] & 0xffL) << 32) |
564                         ((buf[o+5] & 0xffL) << 40) |
565                         ((long)(buf[o+6]) << 48);
566                 break;
567             case 6:
568                 result = (buf[o] & 0xff) |
569                         ((buf[o+1] & 0xff) << 8) |
570                         ((buf[o+2] & 0xff) << 16) |
571                         ((buf[o+3] & 0xffL) << 24) |
572                         ((buf[o+4] & 0xffL) << 32) |
573                         ((long)(buf[o+5]) << 40);
574                 break;
575             case 5:
576                 result = (buf[o] & 0xff) |
577                         ((buf[o+1] & 0xff) << 8) |
578                         ((buf[o+2] & 0xff) << 16) |
579                         ((buf[o+3] & 0xffL) << 24) |
580                         ((long)(buf[o+4]) << 32);
581                 break;
582             case 4:
583                 result = (buf[o] & 0xff) |
584                         ((buf[o+1] & 0xff) << 8) |
585                         ((buf[o+2] & 0xff) << 16) |
586                         (((long)buf[o+3]) << 24);
587                 break;
588             case 3:
589                 result = (buf[o] & 0xff) |
590                         ((buf[o+1] & 0xff) << 8) |
591                         (buf[o+2] << 16);
592                 break;
593             case 2:
594                 result = (buf[o] & 0xff) |
595                         (buf[o+1] << 8);
596                 break;
597             case 1:
598                 result = buf[o];
599                 break;
600             default:
601                 throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
602         }
603 
604         offset = o + bytes - dexBuf.baseOffset;
605         return result;
606     }
607 
readString(int utf16Length)608     public String readString(int utf16Length) {
609         int[] ret = new int[1];
610         String value = Utf8Utils.utf8BytesWithUtf16LengthToString(
611                 dexBuf.buf, dexBuf.baseOffset + offset, utf16Length, ret);
612         offset += ret[0];
613         return value;
614     }
615 
peekStringLength(int utf16Length)616     public int peekStringLength(int utf16Length) {
617         int[] ret = new int[1];
618         Utf8Utils.utf8BytesWithUtf16LengthToString(
619             dexBuf.buf, dexBuf.baseOffset + offset, utf16Length, ret);
620         return ret[0];
621     }
622 }
623