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